Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/appl/ftp/ftpd/ls.c
34907 views
1
/*
2
* Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* 3. Neither the name of KTH nor the names of its contributors may be
18
* used to endorse or promote products derived from this software without
19
* specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32
33
#ifndef TEST
34
#include "ftpd_locl.h"
35
36
RCSID("$Id$");
37
38
#else
39
#include <stdio.h>
40
#include <string.h>
41
#include <stdlib.h>
42
#include <time.h>
43
#include <dirent.h>
44
#include <sys/stat.h>
45
#include <unistd.h>
46
#include <pwd.h>
47
#include <grp.h>
48
#include <errno.h>
49
50
#define sec_fprintf2 fprintf
51
#define sec_fflush fflush
52
static void list_files(FILE *out, const char **files, int n_files, int flags);
53
static int parse_flags(const char *options);
54
55
int
56
main(int argc, char **argv)
57
{
58
int i = 1;
59
int flags;
60
if(argc > 1 && argv[1][0] == '-') {
61
flags = parse_flags(argv[1]);
62
i = 2;
63
} else
64
flags = parse_flags(NULL);
65
66
list_files(stdout, (const char **)argv + i, argc - i, flags);
67
return 0;
68
}
69
#endif
70
71
struct fileinfo {
72
struct stat st;
73
int inode;
74
int bsize;
75
char mode[11];
76
int n_link;
77
char *user;
78
char *group;
79
char *size;
80
char *major;
81
char *minor;
82
char *date;
83
char *filename;
84
char *link;
85
};
86
87
static void
88
free_fileinfo(struct fileinfo *f)
89
{
90
free(f->user);
91
free(f->group);
92
free(f->size);
93
free(f->major);
94
free(f->minor);
95
free(f->date);
96
free(f->filename);
97
free(f->link);
98
}
99
100
#define LS_DIRS (1 << 0)
101
#define LS_IGNORE_DOT (1 << 1)
102
#define LS_SORT_MODE (3 << 2)
103
#define SORT_MODE(f) ((f) & LS_SORT_MODE)
104
#define LS_SORT_NAME (1 << 2)
105
#define LS_SORT_MTIME (2 << 2)
106
#define LS_SORT_SIZE (3 << 2)
107
#define LS_SORT_REVERSE (1 << 4)
108
109
#define LS_SIZE (1 << 5)
110
#define LS_INODE (1 << 6)
111
#define LS_TYPE (1 << 7)
112
#define LS_DISP_MODE (3 << 8)
113
#define DISP_MODE(f) ((f) & LS_DISP_MODE)
114
#define LS_DISP_LONG (1 << 8)
115
#define LS_DISP_COLUMN (2 << 8)
116
#define LS_DISP_CROSS (3 << 8)
117
#define LS_SHOW_ALL (1 << 10)
118
#define LS_RECURSIVE (1 << 11)
119
#define LS_EXTRA_BLANK (1 << 12)
120
#define LS_SHOW_DIRNAME (1 << 13)
121
#define LS_DIR_FLAG (1 << 14) /* these files come via list_dir */
122
123
#ifndef S_ISTXT
124
#define S_ISTXT S_ISVTX
125
#endif
126
127
#if !defined(_S_IFMT) && defined(S_IFMT)
128
#define _S_IFMT S_IFMT
129
#endif
130
131
#ifndef S_ISSOCK
132
#define S_ISSOCK(mode) (((mode) & _S_IFMT) == S_IFSOCK)
133
#endif
134
135
#ifndef S_ISLNK
136
#define S_ISLNK(mode) (((mode) & _S_IFMT) == S_IFLNK)
137
#endif
138
139
static size_t
140
block_convert(size_t blocks)
141
{
142
#ifdef S_BLKSIZE
143
return blocks * S_BLKSIZE / 1024;
144
#else
145
return blocks * 512 / 1024;
146
#endif
147
}
148
149
static int
150
make_fileinfo(FILE *out, const char *filename, struct fileinfo *file, int flags)
151
{
152
char buf[128];
153
int file_type = 0;
154
struct stat *st = &file->st;
155
156
file->inode = st->st_ino;
157
file->bsize = block_convert(st->st_blocks);
158
159
if(S_ISDIR(st->st_mode)) {
160
file->mode[0] = 'd';
161
file_type = '/';
162
}
163
else if(S_ISCHR(st->st_mode))
164
file->mode[0] = 'c';
165
else if(S_ISBLK(st->st_mode))
166
file->mode[0] = 'b';
167
else if(S_ISREG(st->st_mode)) {
168
file->mode[0] = '-';
169
if(st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
170
file_type = '*';
171
}
172
else if(S_ISFIFO(st->st_mode)) {
173
file->mode[0] = 'p';
174
file_type = '|';
175
}
176
else if(S_ISLNK(st->st_mode)) {
177
file->mode[0] = 'l';
178
file_type = '@';
179
}
180
else if(S_ISSOCK(st->st_mode)) {
181
file->mode[0] = 's';
182
file_type = '=';
183
}
184
#ifdef S_ISWHT
185
else if(S_ISWHT(st->st_mode)) {
186
file->mode[0] = 'w';
187
file_type = '%';
188
}
189
#endif
190
else
191
file->mode[0] = '?';
192
{
193
char *x[] = { "---", "--x", "-w-", "-wx",
194
"r--", "r-x", "rw-", "rwx" };
195
strcpy(file->mode + 1, x[(st->st_mode & S_IRWXU) >> 6]);
196
strcpy(file->mode + 4, x[(st->st_mode & S_IRWXG) >> 3]);
197
strcpy(file->mode + 7, x[(st->st_mode & S_IRWXO) >> 0]);
198
if((st->st_mode & S_ISUID)) {
199
if((st->st_mode & S_IXUSR))
200
file->mode[3] = 's';
201
else
202
file->mode[3] = 'S';
203
}
204
if((st->st_mode & S_ISGID)) {
205
if((st->st_mode & S_IXGRP))
206
file->mode[6] = 's';
207
else
208
file->mode[6] = 'S';
209
}
210
if((st->st_mode & S_ISTXT)) {
211
if((st->st_mode & S_IXOTH))
212
file->mode[9] = 't';
213
else
214
file->mode[9] = 'T';
215
}
216
}
217
file->n_link = st->st_nlink;
218
{
219
struct passwd *pwd;
220
pwd = getpwuid(st->st_uid);
221
if(pwd == NULL) {
222
if (asprintf(&file->user, "%u", (unsigned)st->st_uid) == -1)
223
file->user = NULL;
224
} else
225
file->user = strdup(pwd->pw_name);
226
if (file->user == NULL) {
227
syslog(LOG_ERR, "out of memory");
228
return -1;
229
}
230
}
231
{
232
struct group *grp;
233
grp = getgrgid(st->st_gid);
234
if(grp == NULL) {
235
if (asprintf(&file->group, "%u", (unsigned)st->st_gid) == -1)
236
file->group = NULL;
237
} else
238
file->group = strdup(grp->gr_name);
239
if (file->group == NULL) {
240
syslog(LOG_ERR, "out of memory");
241
return -1;
242
}
243
}
244
245
if(S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
246
#if defined(major) && defined(minor)
247
if (asprintf(&file->major, "%u", (unsigned)major(st->st_rdev)) == -1)
248
file->major = NULL;
249
if (asprintf(&file->minor, "%u", (unsigned)minor(st->st_rdev)) == -1)
250
file->minor = NULL;
251
#else
252
/* Don't want to use the DDI/DKI crap. */
253
if (asprintf(&file->major, "%u", (unsigned)st->st_rdev) == -1)
254
file->major = NULL;
255
if (asprintf(&file->minor, "%u", 0) == -1)
256
file->minor = NULL;
257
#endif
258
if (file->major == NULL || file->minor == NULL) {
259
syslog(LOG_ERR, "out of memory");
260
return -1;
261
}
262
} else {
263
if (asprintf(&file->size, "%lu", (unsigned long)st->st_size) == -1)
264
file->size = NULL;
265
}
266
267
{
268
time_t t = time(NULL);
269
time_t mtime = st->st_mtime;
270
struct tm *tm = localtime(&mtime);
271
if((t - mtime > 6*30*24*60*60) ||
272
(mtime - t > 6*30*24*60*60))
273
strftime(buf, sizeof(buf), "%b %e %Y", tm);
274
else
275
strftime(buf, sizeof(buf), "%b %e %H:%M", tm);
276
file->date = strdup(buf);
277
if (file->date == NULL) {
278
syslog(LOG_ERR, "out of memory");
279
return -1;
280
}
281
}
282
{
283
const char *p = strrchr(filename, '/');
284
if(p)
285
p++;
286
else
287
p = filename;
288
if((flags & LS_TYPE) && file_type != 0) {
289
if (asprintf(&file->filename, "%s%c", p, file_type) == -1)
290
file->filename = NULL;
291
} else
292
file->filename = strdup(p);
293
if (file->filename == NULL) {
294
syslog(LOG_ERR, "out of memory");
295
return -1;
296
}
297
}
298
if(S_ISLNK(st->st_mode)) {
299
int n;
300
n = readlink((char *)filename, buf, sizeof(buf) - 1);
301
if(n >= 0) {
302
buf[n] = '\0';
303
file->link = strdup(buf);
304
if (file->link == NULL) {
305
syslog(LOG_ERR, "out of memory");
306
return -1;
307
}
308
} else
309
sec_fprintf2(out, "readlink(%s): %s", filename, strerror(errno));
310
}
311
return 0;
312
}
313
314
static void
315
print_file(FILE *out,
316
int flags,
317
struct fileinfo *f,
318
int max_inode,
319
int max_bsize,
320
int max_n_link,
321
int max_user,
322
int max_group,
323
int max_size,
324
int max_major,
325
int max_minor,
326
int max_date)
327
{
328
if(f->filename == NULL)
329
return;
330
331
if(flags & LS_INODE) {
332
sec_fprintf2(out, "%*d", max_inode, f->inode);
333
sec_fprintf2(out, " ");
334
}
335
if(flags & LS_SIZE) {
336
sec_fprintf2(out, "%*d", max_bsize, f->bsize);
337
sec_fprintf2(out, " ");
338
}
339
sec_fprintf2(out, "%s", f->mode);
340
sec_fprintf2(out, " ");
341
sec_fprintf2(out, "%*d", max_n_link, f->n_link);
342
sec_fprintf2(out, " ");
343
sec_fprintf2(out, "%-*s", max_user, f->user);
344
sec_fprintf2(out, " ");
345
sec_fprintf2(out, "%-*s", max_group, f->group);
346
sec_fprintf2(out, " ");
347
if(f->major != NULL && f->minor != NULL)
348
sec_fprintf2(out, "%*s, %*s", max_major, f->major, max_minor, f->minor);
349
else
350
sec_fprintf2(out, "%*s", max_size, f->size);
351
sec_fprintf2(out, " ");
352
sec_fprintf2(out, "%*s", max_date, f->date);
353
sec_fprintf2(out, " ");
354
sec_fprintf2(out, "%s", f->filename);
355
if(f->link)
356
sec_fprintf2(out, " -> %s", f->link);
357
sec_fprintf2(out, "\r\n");
358
}
359
360
static int
361
compare_filename(struct fileinfo *a, struct fileinfo *b)
362
{
363
if(a->filename == NULL)
364
return 1;
365
if(b->filename == NULL)
366
return -1;
367
return strcmp(a->filename, b->filename);
368
}
369
370
static int
371
compare_mtime(struct fileinfo *a, struct fileinfo *b)
372
{
373
if(a->filename == NULL)
374
return 1;
375
if(b->filename == NULL)
376
return -1;
377
return b->st.st_mtime - a->st.st_mtime;
378
}
379
380
static int
381
compare_size(struct fileinfo *a, struct fileinfo *b)
382
{
383
if(a->filename == NULL)
384
return 1;
385
if(b->filename == NULL)
386
return -1;
387
return b->st.st_size - a->st.st_size;
388
}
389
390
static int list_dir(FILE*, const char*, int);
391
392
static int
393
find_log10(int num)
394
{
395
int i = 1;
396
while(num > 10) {
397
i++;
398
num /= 10;
399
}
400
return i;
401
}
402
403
/*
404
* Operate as lstat but fake up entries for AFS mount points so we don't
405
* have to fetch them.
406
*/
407
408
#ifdef KRB5
409
static int do_the_afs_dance = 1;
410
#endif
411
412
static int
413
lstat_file (const char *file, struct stat *sb)
414
{
415
#ifdef KRB5
416
if (do_the_afs_dance &&
417
k_hasafs()
418
&& strcmp(file, ".")
419
&& strcmp(file, "..")
420
&& strcmp(file, "/"))
421
{
422
struct ViceIoctl a_params;
423
char *dir, *last;
424
char *path_bkp;
425
static ino_t ino_counter = 0, ino_last = 0;
426
int ret;
427
const int maxsize = 2048;
428
429
path_bkp = strdup (file);
430
if (path_bkp == NULL)
431
return -1;
432
433
a_params.out = malloc (maxsize);
434
if (a_params.out == NULL) {
435
free (path_bkp);
436
return -1;
437
}
438
439
/* If path contains more than the filename alone - split it */
440
441
last = strrchr (path_bkp, '/');
442
if (last != NULL) {
443
if(last[1] == '\0')
444
/* if path ended in /, replace with `.' */
445
a_params.in = ".";
446
else
447
a_params.in = last + 1;
448
while(last > path_bkp && *--last == '/');
449
if(*last != '/' || last != path_bkp) {
450
*++last = '\0';
451
dir = path_bkp;
452
} else
453
/* we got to the start, so this must be the root dir */
454
dir = "/";
455
} else {
456
/* file is relative to cdir */
457
dir = ".";
458
a_params.in = path_bkp;
459
}
460
461
a_params.in_size = strlen (a_params.in) + 1;
462
a_params.out_size = maxsize;
463
464
ret = k_pioctl (dir, VIOC_AFS_STAT_MT_PT, &a_params, 0);
465
free (a_params.out);
466
if (ret < 0) {
467
free (path_bkp);
468
469
if (errno != EINVAL)
470
return ret;
471
else
472
/* if we get EINVAL this is probably not a mountpoint */
473
return lstat (file, sb);
474
}
475
476
/*
477
* wow this was a mountpoint, lets cook the struct stat
478
* use . as a prototype
479
*/
480
481
ret = lstat (dir, sb);
482
free (path_bkp);
483
if (ret < 0)
484
return ret;
485
486
if (ino_last == sb->st_ino)
487
ino_counter++;
488
else {
489
ino_last = sb->st_ino;
490
ino_counter = 0;
491
}
492
sb->st_ino += ino_counter;
493
sb->st_nlink = 3;
494
495
return 0;
496
}
497
#endif /* KRB5 */
498
return lstat (file, sb);
499
}
500
501
#define IS_DOT_DOTDOT(X) ((X)[0] == '.' && ((X)[1] == '\0' || \
502
((X)[1] == '.' && (X)[2] == '\0')))
503
504
static int
505
list_files(FILE *out, const char **files, int n_files, int flags)
506
{
507
struct fileinfo *fi;
508
int i;
509
int *dirs = NULL;
510
size_t total_blocks = 0;
511
int n_print = 0;
512
int ret = 0;
513
514
if(n_files == 0)
515
return 0;
516
517
if(n_files > 1)
518
flags |= LS_SHOW_DIRNAME;
519
520
fi = calloc(n_files, sizeof(*fi));
521
if (fi == NULL) {
522
syslog(LOG_ERR, "out of memory");
523
return -1;
524
}
525
for(i = 0; i < n_files; i++) {
526
if(lstat_file(files[i], &fi[i].st) < 0) {
527
sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno));
528
fi[i].filename = NULL;
529
} else {
530
int include_in_list = 1;
531
total_blocks += block_convert(fi[i].st.st_blocks);
532
if(S_ISDIR(fi[i].st.st_mode)) {
533
if(dirs == NULL)
534
dirs = calloc(n_files, sizeof(*dirs));
535
if(dirs == NULL) {
536
syslog(LOG_ERR, "%s: %m", files[i]);
537
ret = -1;
538
goto out;
539
}
540
dirs[i] = 1;
541
if((flags & LS_DIRS) == 0)
542
include_in_list = 0;
543
}
544
if(include_in_list) {
545
ret = make_fileinfo(out, files[i], &fi[i], flags);
546
if (ret)
547
goto out;
548
n_print++;
549
}
550
}
551
}
552
switch(SORT_MODE(flags)) {
553
case LS_SORT_NAME:
554
qsort(fi, n_files, sizeof(*fi),
555
(int (*)(const void*, const void*))compare_filename);
556
break;
557
case LS_SORT_MTIME:
558
qsort(fi, n_files, sizeof(*fi),
559
(int (*)(const void*, const void*))compare_mtime);
560
break;
561
case LS_SORT_SIZE:
562
qsort(fi, n_files, sizeof(*fi),
563
(int (*)(const void*, const void*))compare_size);
564
break;
565
}
566
if(DISP_MODE(flags) == LS_DISP_LONG) {
567
int max_inode = 0;
568
int max_bsize = 0;
569
int max_n_link = 0;
570
int max_user = 0;
571
int max_group = 0;
572
int max_size = 0;
573
int max_major = 0;
574
int max_minor = 0;
575
int max_date = 0;
576
for(i = 0; i < n_files; i++) {
577
if(fi[i].filename == NULL)
578
continue;
579
if(fi[i].inode > max_inode)
580
max_inode = fi[i].inode;
581
if(fi[i].bsize > max_bsize)
582
max_bsize = fi[i].bsize;
583
if(fi[i].n_link > max_n_link)
584
max_n_link = fi[i].n_link;
585
if(strlen(fi[i].user) > max_user)
586
max_user = strlen(fi[i].user);
587
if(strlen(fi[i].group) > max_group)
588
max_group = strlen(fi[i].group);
589
if(fi[i].major != NULL && strlen(fi[i].major) > max_major)
590
max_major = strlen(fi[i].major);
591
if(fi[i].minor != NULL && strlen(fi[i].minor) > max_minor)
592
max_minor = strlen(fi[i].minor);
593
if(fi[i].size != NULL && strlen(fi[i].size) > max_size)
594
max_size = strlen(fi[i].size);
595
if(strlen(fi[i].date) > max_date)
596
max_date = strlen(fi[i].date);
597
}
598
if(max_size < max_major + max_minor + 2)
599
max_size = max_major + max_minor + 2;
600
else if(max_size - max_minor - 2 > max_major)
601
max_major = max_size - max_minor - 2;
602
max_inode = find_log10(max_inode);
603
max_bsize = find_log10(max_bsize);
604
max_n_link = find_log10(max_n_link);
605
606
if(n_print > 0)
607
sec_fprintf2(out, "total %lu\r\n", (unsigned long)total_blocks);
608
if(flags & LS_SORT_REVERSE)
609
for(i = n_files - 1; i >= 0; i--)
610
print_file(out,
611
flags,
612
&fi[i],
613
max_inode,
614
max_bsize,
615
max_n_link,
616
max_user,
617
max_group,
618
max_size,
619
max_major,
620
max_minor,
621
max_date);
622
else
623
for(i = 0; i < n_files; i++)
624
print_file(out,
625
flags,
626
&fi[i],
627
max_inode,
628
max_bsize,
629
max_n_link,
630
max_user,
631
max_group,
632
max_size,
633
max_major,
634
max_minor,
635
max_date);
636
} else if(DISP_MODE(flags) == LS_DISP_COLUMN ||
637
DISP_MODE(flags) == LS_DISP_CROSS) {
638
int max_len = 0;
639
int size_len = 0;
640
int num_files = n_files;
641
int columns;
642
int j;
643
for(i = 0; i < n_files; i++) {
644
if(fi[i].filename == NULL) {
645
num_files--;
646
continue;
647
}
648
if(strlen(fi[i].filename) > max_len)
649
max_len = strlen(fi[i].filename);
650
if(find_log10(fi[i].bsize) > size_len)
651
size_len = find_log10(fi[i].bsize);
652
}
653
if(num_files == 0)
654
goto next;
655
if(flags & LS_SIZE) {
656
columns = 80 / (size_len + 1 + max_len + 1);
657
max_len = 80 / columns - size_len - 1;
658
} else {
659
columns = 80 / (max_len + 1); /* get space between columns */
660
max_len = 80 / columns;
661
}
662
if(flags & LS_SIZE)
663
sec_fprintf2(out, "total %lu\r\n",
664
(unsigned long)total_blocks);
665
if(DISP_MODE(flags) == LS_DISP_CROSS) {
666
for(i = 0, j = 0; i < n_files; i++) {
667
if(fi[i].filename == NULL)
668
continue;
669
if(flags & LS_SIZE)
670
sec_fprintf2(out, "%*u %-*s", size_len, fi[i].bsize,
671
max_len, fi[i].filename);
672
else
673
sec_fprintf2(out, "%-*s", max_len, fi[i].filename);
674
j++;
675
if(j == columns) {
676
sec_fprintf2(out, "\r\n");
677
j = 0;
678
}
679
}
680
if(j > 0)
681
sec_fprintf2(out, "\r\n");
682
} else {
683
int skip = (num_files + columns - 1) / columns;
684
685
for(i = 0; i < skip; i++) {
686
for(j = i; j < n_files;) {
687
while(j < n_files && fi[j].filename == NULL)
688
j++;
689
if(flags & LS_SIZE)
690
sec_fprintf2(out, "%*u %-*s", size_len, fi[j].bsize,
691
max_len, fi[j].filename);
692
else
693
sec_fprintf2(out, "%-*s", max_len, fi[j].filename);
694
j += skip;
695
}
696
sec_fprintf2(out, "\r\n");
697
}
698
}
699
} else {
700
for(i = 0; i < n_files; i++) {
701
if(fi[i].filename == NULL)
702
continue;
703
sec_fprintf2(out, "%s\r\n", fi[i].filename);
704
}
705
}
706
next:
707
if(((flags & LS_DIRS) == 0 || (flags & LS_RECURSIVE)) && dirs != NULL) {
708
for(i = 0; i < n_files; i++) {
709
if(dirs[i]) {
710
const char *p = strrchr(files[i], '/');
711
if(p == NULL)
712
p = files[i];
713
else
714
p++;
715
if(!(flags & LS_DIR_FLAG) || !IS_DOT_DOTDOT(p)) {
716
if((flags & LS_SHOW_DIRNAME)) {
717
if ((flags & LS_EXTRA_BLANK))
718
sec_fprintf2(out, "\r\n");
719
sec_fprintf2(out, "%s:\r\n", files[i]);
720
}
721
list_dir(out, files[i], flags | LS_DIRS | LS_EXTRA_BLANK);
722
}
723
}
724
}
725
}
726
out:
727
for(i = 0; i < n_files; i++)
728
free_fileinfo(&fi[i]);
729
free(fi);
730
if(dirs != NULL)
731
free(dirs);
732
return ret;
733
}
734
735
static void
736
free_files (char **files, int n)
737
{
738
int i;
739
740
for (i = 0; i < n; ++i)
741
free (files[i]);
742
free (files);
743
}
744
745
static int
746
hide_file(const char *filename, int flags)
747
{
748
if(filename[0] != '.')
749
return 0;
750
if((flags & LS_IGNORE_DOT))
751
return 1;
752
if(filename[1] == '\0' || (filename[1] == '.' && filename[2] == '\0')) {
753
if((flags & LS_SHOW_ALL))
754
return 0;
755
else
756
return 1;
757
}
758
return 0;
759
}
760
761
static int
762
list_dir(FILE *out, const char *directory, int flags)
763
{
764
DIR *d = opendir(directory);
765
struct dirent *ent;
766
char **files = NULL;
767
int n_files = 0;
768
int ret;
769
770
if(d == NULL) {
771
syslog(LOG_ERR, "%s: %m", directory);
772
return -1;
773
}
774
while((ent = readdir(d)) != NULL) {
775
void *tmp;
776
777
if(hide_file(ent->d_name, flags))
778
continue;
779
tmp = realloc(files, (n_files + 1) * sizeof(*files));
780
if (tmp == NULL) {
781
syslog(LOG_ERR, "%s: out of memory", directory);
782
free_files (files, n_files);
783
closedir (d);
784
return -1;
785
}
786
files = tmp;
787
ret = asprintf(&files[n_files], "%s/%s", directory, ent->d_name);
788
if (ret == -1) {
789
syslog(LOG_ERR, "%s: out of memory", directory);
790
free_files (files, n_files);
791
closedir (d);
792
return -1;
793
}
794
++n_files;
795
}
796
closedir(d);
797
return list_files(out, (const char**)files, n_files, flags | LS_DIR_FLAG);
798
}
799
800
static int
801
parse_flags(const char *options)
802
{
803
#ifdef TEST
804
int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_COLUMN;
805
#else
806
int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_LONG;
807
#endif
808
809
const char *p;
810
if(options == NULL || *options != '-')
811
return flags;
812
for(p = options + 1; *p; p++) {
813
switch(*p) {
814
case '1':
815
flags = (flags & ~LS_DISP_MODE);
816
break;
817
case 'a':
818
flags |= LS_SHOW_ALL;
819
/*FALLTHROUGH*/
820
case 'A':
821
flags &= ~LS_IGNORE_DOT;
822
break;
823
case 'C':
824
flags = (flags & ~LS_DISP_MODE) | LS_DISP_COLUMN;
825
break;
826
case 'd':
827
flags |= LS_DIRS;
828
break;
829
case 'f':
830
flags = (flags & ~LS_SORT_MODE);
831
break;
832
case 'F':
833
flags |= LS_TYPE;
834
break;
835
case 'i':
836
flags |= LS_INODE;
837
break;
838
case 'l':
839
flags = (flags & ~LS_DISP_MODE) | LS_DISP_LONG;
840
break;
841
case 'r':
842
flags |= LS_SORT_REVERSE;
843
break;
844
case 'R':
845
flags |= LS_RECURSIVE;
846
break;
847
case 's':
848
flags |= LS_SIZE;
849
break;
850
case 'S':
851
flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE;
852
break;
853
case 't':
854
flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME;
855
break;
856
case 'x':
857
flags = (flags & ~LS_DISP_MODE) | LS_DISP_CROSS;
858
break;
859
/* these are a bunch of unimplemented flags from BSD ls */
860
case 'k': /* display sizes in kB */
861
case 'c': /* last change time */
862
case 'L': /* list symlink target */
863
case 'm': /* stream output */
864
case 'o': /* BSD file flags */
865
case 'p': /* display / after directories */
866
case 'q': /* print non-graphic characters */
867
case 'u': /* use last access time */
868
case 'T': /* display complete time */
869
case 'W': /* include whiteouts */
870
break;
871
}
872
}
873
return flags;
874
}
875
876
int
877
builtin_ls(FILE *out, const char *file)
878
{
879
int flags;
880
int ret;
881
882
if(*file == '-') {
883
flags = parse_flags(file);
884
file = ".";
885
} else
886
flags = parse_flags("");
887
888
ret = list_files(out, &file, 1, flags);
889
sec_fflush(out);
890
return ret;
891
}
892
893