26
26
#include <stdio.h>
27
27
#include <string.h>
28
28
29
+ #ifdef HAVE_FTS_OPEN
30
+ #include <fts.h>
31
+ #endif
32
+
29
33
#include "c.h"
30
34
#include "cctype.h"
31
35
#include "nls.h"
@@ -125,12 +129,13 @@ struct fincore_control {
125
129
unsigned int bytes : 1 ,
126
130
noheadings : 1 ,
127
131
raw : 1 ,
128
- json : 1 ;
132
+ json : 1 ,
133
+ recursive : 1 ;
129
134
130
135
};
131
136
132
137
struct fincore_state {
133
- const char * const name ;
138
+ const char * name ;
134
139
long long unsigned int file_size ;
135
140
136
141
struct cachestat cstat ;
@@ -356,40 +361,50 @@ static int fincore_fd (struct fincore_control *ctl,
356
361
/*
357
362
* Returns: <0 on error, 0 success, 1 ignore.
358
363
*/
359
- static int fincore_name (struct fincore_control * ctl , const char * name )
364
+ static int fincore_name (struct fincore_control * ctl ,
365
+ const char * filename ,
366
+ const char * showname ,
367
+ struct stat * statp )
360
368
{
361
369
int fd ;
362
370
int rc = 0 ;
363
- struct stat sb ;
364
- struct fincore_state _st = { .name = name }, * st = & _st ;
371
+ struct stat sb , * stp = statp ?: & sb ;
372
+ struct fincore_state st = { .name = filename } ;
365
373
366
- if ((fd = open ( st -> name , O_RDONLY )) < 0 ) {
367
- warn (_ ("failed to open: %s" ), st -> name );
374
+ if ((fd = open ( filename , O_RDONLY )) < 0 ) {
375
+ warn (_ ("failed to open: %s" ), showname );
368
376
return - errno ;
369
377
}
370
378
371
- if (fstat (fd , & sb ) < 0 ) {
372
- warn (_ ("failed to do fstat: %s" ), st -> name );
373
- close (fd );
374
- return - errno ;
379
+ if (!statp ) {
380
+ if (fstat (fd , & sb ) < 0 ) {
381
+ warn (_ ("failed to do fstat: %s" ), showname );
382
+ close (fd );
383
+ return - errno ;
384
+ }
375
385
}
376
- st -> file_size = sb .st_size ;
377
386
378
- if (S_ISBLK (sb . st_mode )) {
379
- rc = blkdev_get_size (fd , & st -> file_size );
387
+ if (S_ISBLK (stp -> st_mode )) {
388
+ rc = blkdev_get_size (fd , & st . file_size );
380
389
if (rc )
381
- warn (_ ("failed ioctl to get size: %s" ), st -> name );
382
- } else if (S_ISREG (sb .st_mode )) {
383
- st -> file_size = sb .st_size ;
390
+ warn (_ ("failed ioctl to get size: %s" ), showname );
391
+ } else if (S_ISREG (stp -> st_mode )) {
392
+ st .file_size = stp -> st_size ;
393
+ } else {
394
+ rc = 1 ; /* ignore things like symlinks
395
+ * and directories*/
384
396
}
385
397
386
- if (!rc )
387
- rc = fincore_fd (ctl , fd , st );
398
+ if (!rc ) {
399
+ rc = fincore_fd (ctl , fd , & st );
400
+ }
388
401
389
402
close (fd );
390
403
391
- if (!rc )
392
- rc = add_output_data (ctl , st );
404
+ if (!rc ) {
405
+ st .name = showname ;
406
+ rc = add_output_data (ctl , & st );
407
+ }
393
408
394
409
return rc ;
395
410
}
@@ -409,6 +424,7 @@ static void __attribute__((__noreturn__)) usage(void)
409
424
fputs (_ (" -o, --output <list> output columns\n" ), out );
410
425
fputs (_ (" --output-all output all columns\n" ), out );
411
426
fputs (_ (" -r, --raw use raw output format\n" ), out );
427
+ fputs (_ (" -R, --recursive recursively check all files in directories\n" ), out );
412
428
413
429
fputs (USAGE_SEPARATOR , out );
414
430
fprintf (out , USAGE_HELP_OPTIONS (23 ));
@@ -446,6 +462,7 @@ int main(int argc, char ** argv)
446
462
{ "help" , no_argument , NULL , 'h' },
447
463
{ "json" , no_argument , NULL , 'J' },
448
464
{ "raw" , no_argument , NULL , 'r' },
465
+ { "recursive" , no_argument , NULL , 'R' },
449
466
{ NULL , 0 , NULL , 0 },
450
467
};
451
468
@@ -454,7 +471,7 @@ int main(int argc, char ** argv)
454
471
textdomain (PACKAGE );
455
472
close_stdout_atexit ();
456
473
457
- while ((c = getopt_long (argc , argv , "bno:JrVh " , longopts , NULL )) != -1 ) {
474
+ while ((c = getopt_long (argc , argv , "bno:JrRVh " , longopts , NULL )) != -1 ) {
458
475
switch (c ) {
459
476
case 'b' :
460
477
ctl .bytes = 1 ;
@@ -475,6 +492,12 @@ int main(int argc, char ** argv)
475
492
case 'r' :
476
493
ctl .raw = 1 ;
477
494
break ;
495
+ case 'R' :
496
+ #ifndef HAVE_FTS_OPEN
497
+ errx (0 , _ ("recursive option is not supported" ));
498
+ #endif
499
+ ctl .recursive = 1 ;
500
+ break ;
478
501
case 'V' :
479
502
print_version (EXIT_SUCCESS );
480
503
case 'h' :
@@ -538,10 +561,33 @@ int main(int argc, char ** argv)
538
561
}
539
562
}
540
563
541
- for (; optind < argc ; optind ++ ) {
542
- rc = fincore_name (& ctl , argv [optind ]);
543
- if (rc )
544
- break ;
564
+ if (ctl .recursive ) {
565
+ #ifdef HAVE_FTS_OPEN
566
+ FTS * fts = fts_open (argv + optind , FTS_PHYSICAL , NULL );
567
+ FTSENT * ent ;
568
+
569
+ if (!fts ) {
570
+ warn (_ ("failed to iterate tree" ));
571
+ rc = EXIT_FAILURE ;
572
+ } else {
573
+ while ((ent = fts_read (fts )) != NULL ) {
574
+ if (ent -> fts_info == FTS_F || ent -> fts_info == FTS_DEFAULT ) {
575
+ /* fts changes directory when iterating,
576
+ * so we need to use .fts_accpath to access
577
+ * the file named .fts_path */
578
+ rc = fincore_name (& ctl , ent -> fts_accpath , ent -> fts_path , ent -> fts_statp );
579
+ if (rc )
580
+ break ;
581
+ }
582
+ }
583
+ }
584
+ #endif
585
+ } else {
586
+ for (; optind < argc ; optind ++ ) {
587
+ rc = fincore_name (& ctl , argv [optind ], argv [optind ], NULL );
588
+ if (rc )
589
+ break ;
590
+ }
545
591
}
546
592
547
593
if (rc == 0 )
0 commit comments