/crypto/heimdal/appl/ftp/ftpd/ls.c
https://bitbucket.org/freebsd/freebsd-head/ · C · 891 lines · 785 code · 59 blank · 47 comment · 252 complexity · 53212496a7068b000d731cbc3fd6fc0e MD5 · raw file
- /*
- * Copyright (c) 1999 - 2002 Kungliga Tekniska Hรถgskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of KTH nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
- #ifndef TEST
- #include "ftpd_locl.h"
- RCSID("$Id$");
- #else
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <time.h>
- #include <dirent.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <pwd.h>
- #include <grp.h>
- #include <errno.h>
- #define sec_fprintf2 fprintf
- #define sec_fflush fflush
- static void list_files(FILE *out, const char **files, int n_files, int flags);
- static int parse_flags(const char *options);
- int
- main(int argc, char **argv)
- {
- int i = 1;
- int flags;
- if(argc > 1 && argv[1][0] == '-') {
- flags = parse_flags(argv[1]);
- i = 2;
- } else
- flags = parse_flags(NULL);
- list_files(stdout, (const char **)argv + i, argc - i, flags);
- return 0;
- }
- #endif
- struct fileinfo {
- struct stat st;
- int inode;
- int bsize;
- char mode[11];
- int n_link;
- char *user;
- char *group;
- char *size;
- char *major;
- char *minor;
- char *date;
- char *filename;
- char *link;
- };
- static void
- free_fileinfo(struct fileinfo *f)
- {
- free(f->user);
- free(f->group);
- free(f->size);
- free(f->major);
- free(f->minor);
- free(f->date);
- free(f->filename);
- free(f->link);
- }
- #define LS_DIRS (1 << 0)
- #define LS_IGNORE_DOT (1 << 1)
- #define LS_SORT_MODE (3 << 2)
- #define SORT_MODE(f) ((f) & LS_SORT_MODE)
- #define LS_SORT_NAME (1 << 2)
- #define LS_SORT_MTIME (2 << 2)
- #define LS_SORT_SIZE (3 << 2)
- #define LS_SORT_REVERSE (1 << 4)
- #define LS_SIZE (1 << 5)
- #define LS_INODE (1 << 6)
- #define LS_TYPE (1 << 7)
- #define LS_DISP_MODE (3 << 8)
- #define DISP_MODE(f) ((f) & LS_DISP_MODE)
- #define LS_DISP_LONG (1 << 8)
- #define LS_DISP_COLUMN (2 << 8)
- #define LS_DISP_CROSS (3 << 8)
- #define LS_SHOW_ALL (1 << 10)
- #define LS_RECURSIVE (1 << 11)
- #define LS_EXTRA_BLANK (1 << 12)
- #define LS_SHOW_DIRNAME (1 << 13)
- #define LS_DIR_FLAG (1 << 14) /* these files come via list_dir */
- #ifndef S_ISTXT
- #define S_ISTXT S_ISVTX
- #endif
- #if !defined(_S_IFMT) && defined(S_IFMT)
- #define _S_IFMT S_IFMT
- #endif
- #ifndef S_ISSOCK
- #define S_ISSOCK(mode) (((mode) & _S_IFMT) == S_IFSOCK)
- #endif
- #ifndef S_ISLNK
- #define S_ISLNK(mode) (((mode) & _S_IFMT) == S_IFLNK)
- #endif
- static size_t
- block_convert(size_t blocks)
- {
- #ifdef S_BLKSIZE
- return blocks * S_BLKSIZE / 1024;
- #else
- return blocks * 512 / 1024;
- #endif
- }
- static int
- make_fileinfo(FILE *out, const char *filename, struct fileinfo *file, int flags)
- {
- char buf[128];
- int file_type = 0;
- struct stat *st = &file->st;
- file->inode = st->st_ino;
- file->bsize = block_convert(st->st_blocks);
- if(S_ISDIR(st->st_mode)) {
- file->mode[0] = 'd';
- file_type = '/';
- }
- else if(S_ISCHR(st->st_mode))
- file->mode[0] = 'c';
- else if(S_ISBLK(st->st_mode))
- file->mode[0] = 'b';
- else if(S_ISREG(st->st_mode)) {
- file->mode[0] = '-';
- if(st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
- file_type = '*';
- }
- else if(S_ISFIFO(st->st_mode)) {
- file->mode[0] = 'p';
- file_type = '|';
- }
- else if(S_ISLNK(st->st_mode)) {
- file->mode[0] = 'l';
- file_type = '@';
- }
- else if(S_ISSOCK(st->st_mode)) {
- file->mode[0] = 's';
- file_type = '=';
- }
- #ifdef S_ISWHT
- else if(S_ISWHT(st->st_mode)) {
- file->mode[0] = 'w';
- file_type = '%';
- }
- #endif
- else
- file->mode[0] = '?';
- {
- char *x[] = { "---", "--x", "-w-", "-wx",
- "r--", "r-x", "rw-", "rwx" };
- strcpy(file->mode + 1, x[(st->st_mode & S_IRWXU) >> 6]);
- strcpy(file->mode + 4, x[(st->st_mode & S_IRWXG) >> 3]);
- strcpy(file->mode + 7, x[(st->st_mode & S_IRWXO) >> 0]);
- if((st->st_mode & S_ISUID)) {
- if((st->st_mode & S_IXUSR))
- file->mode[3] = 's';
- else
- file->mode[3] = 'S';
- }
- if((st->st_mode & S_ISGID)) {
- if((st->st_mode & S_IXGRP))
- file->mode[6] = 's';
- else
- file->mode[6] = 'S';
- }
- if((st->st_mode & S_ISTXT)) {
- if((st->st_mode & S_IXOTH))
- file->mode[9] = 't';
- else
- file->mode[9] = 'T';
- }
- }
- file->n_link = st->st_nlink;
- {
- struct passwd *pwd;
- pwd = getpwuid(st->st_uid);
- if(pwd == NULL) {
- if (asprintf(&file->user, "%u", (unsigned)st->st_uid) == -1)
- file->user = NULL;
- } else
- file->user = strdup(pwd->pw_name);
- if (file->user == NULL) {
- syslog(LOG_ERR, "out of memory");
- return -1;
- }
- }
- {
- struct group *grp;
- grp = getgrgid(st->st_gid);
- if(grp == NULL) {
- if (asprintf(&file->group, "%u", (unsigned)st->st_gid) == -1)
- file->group = NULL;
- } else
- file->group = strdup(grp->gr_name);
- if (file->group == NULL) {
- syslog(LOG_ERR, "out of memory");
- return -1;
- }
- }
- if(S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
- #if defined(major) && defined(minor)
- if (asprintf(&file->major, "%u", (unsigned)major(st->st_rdev)) == -1)
- file->major = NULL;
- if (asprintf(&file->minor, "%u", (unsigned)minor(st->st_rdev)) == -1)
- file->minor = NULL;
- #else
- /* Don't want to use the DDI/DKI crap. */
- if (asprintf(&file->major, "%u", (unsigned)st->st_rdev) == -1)
- file->major = NULL;
- if (asprintf(&file->minor, "%u", 0) == -1)
- file->minor = NULL;
- #endif
- if (file->major == NULL || file->minor == NULL) {
- syslog(LOG_ERR, "out of memory");
- return -1;
- }
- } else {
- if (asprintf(&file->size, "%lu", (unsigned long)st->st_size) == -1)
- file->size = NULL;
- }
- {
- time_t t = time(NULL);
- time_t mtime = st->st_mtime;
- struct tm *tm = localtime(&mtime);
- if((t - mtime > 6*30*24*60*60) ||
- (mtime - t > 6*30*24*60*60))
- strftime(buf, sizeof(buf), "%b %e %Y", tm);
- else
- strftime(buf, sizeof(buf), "%b %e %H:%M", tm);
- file->date = strdup(buf);
- if (file->date == NULL) {
- syslog(LOG_ERR, "out of memory");
- return -1;
- }
- }
- {
- const char *p = strrchr(filename, '/');
- if(p)
- p++;
- else
- p = filename;
- if((flags & LS_TYPE) && file_type != 0) {
- if (asprintf(&file->filename, "%s%c", p, file_type) == -1)
- file->filename = NULL;
- } else
- file->filename = strdup(p);
- if (file->filename == NULL) {
- syslog(LOG_ERR, "out of memory");
- return -1;
- }
- }
- if(S_ISLNK(st->st_mode)) {
- int n;
- n = readlink((char *)filename, buf, sizeof(buf) - 1);
- if(n >= 0) {
- buf[n] = '\0';
- file->link = strdup(buf);
- if (file->link == NULL) {
- syslog(LOG_ERR, "out of memory");
- return -1;
- }
- } else
- sec_fprintf2(out, "readlink(%s): %s", filename, strerror(errno));
- }
- return 0;
- }
- static void
- print_file(FILE *out,
- int flags,
- struct fileinfo *f,
- int max_inode,
- int max_bsize,
- int max_n_link,
- int max_user,
- int max_group,
- int max_size,
- int max_major,
- int max_minor,
- int max_date)
- {
- if(f->filename == NULL)
- return;
- if(flags & LS_INODE) {
- sec_fprintf2(out, "%*d", max_inode, f->inode);
- sec_fprintf2(out, " ");
- }
- if(flags & LS_SIZE) {
- sec_fprintf2(out, "%*d", max_bsize, f->bsize);
- sec_fprintf2(out, " ");
- }
- sec_fprintf2(out, "%s", f->mode);
- sec_fprintf2(out, " ");
- sec_fprintf2(out, "%*d", max_n_link, f->n_link);
- sec_fprintf2(out, " ");
- sec_fprintf2(out, "%-*s", max_user, f->user);
- sec_fprintf2(out, " ");
- sec_fprintf2(out, "%-*s", max_group, f->group);
- sec_fprintf2(out, " ");
- if(f->major != NULL && f->minor != NULL)
- sec_fprintf2(out, "%*s, %*s", max_major, f->major, max_minor, f->minor);
- else
- sec_fprintf2(out, "%*s", max_size, f->size);
- sec_fprintf2(out, " ");
- sec_fprintf2(out, "%*s", max_date, f->date);
- sec_fprintf2(out, " ");
- sec_fprintf2(out, "%s", f->filename);
- if(f->link)
- sec_fprintf2(out, " -> %s", f->link);
- sec_fprintf2(out, "\r\n");
- }
- static int
- compare_filename(struct fileinfo *a, struct fileinfo *b)
- {
- if(a->filename == NULL)
- return 1;
- if(b->filename == NULL)
- return -1;
- return strcmp(a->filename, b->filename);
- }
- static int
- compare_mtime(struct fileinfo *a, struct fileinfo *b)
- {
- if(a->filename == NULL)
- return 1;
- if(b->filename == NULL)
- return -1;
- return b->st.st_mtime - a->st.st_mtime;
- }
- static int
- compare_size(struct fileinfo *a, struct fileinfo *b)
- {
- if(a->filename == NULL)
- return 1;
- if(b->filename == NULL)
- return -1;
- return b->st.st_size - a->st.st_size;
- }
- static int list_dir(FILE*, const char*, int);
- static int
- find_log10(int num)
- {
- int i = 1;
- while(num > 10) {
- i++;
- num /= 10;
- }
- return i;
- }
- /*
- * Operate as lstat but fake up entries for AFS mount points so we don't
- * have to fetch them.
- */
- #ifdef KRB5
- static int do_the_afs_dance = 1;
- #endif
- static int
- lstat_file (const char *file, struct stat *sb)
- {
- #ifdef KRB5
- if (do_the_afs_dance &&
- k_hasafs()
- && strcmp(file, ".")
- && strcmp(file, "..")
- && strcmp(file, "/"))
- {
- struct ViceIoctl a_params;
- char *dir, *last;
- char *path_bkp;
- static ino_t ino_counter = 0, ino_last = 0;
- int ret;
- const int maxsize = 2048;
- path_bkp = strdup (file);
- if (path_bkp == NULL)
- return -1;
- a_params.out = malloc (maxsize);
- if (a_params.out == NULL) {
- free (path_bkp);
- return -1;
- }
- /* If path contains more than the filename alone - split it */
- last = strrchr (path_bkp, '/');
- if (last != NULL) {
- if(last[1] == '\0')
- /* if path ended in /, replace with `.' */
- a_params.in = ".";
- else
- a_params.in = last + 1;
- while(last > path_bkp && *--last == '/');
- if(*last != '/' || last != path_bkp) {
- *++last = '\0';
- dir = path_bkp;
- } else
- /* we got to the start, so this must be the root dir */
- dir = "/";
- } else {
- /* file is relative to cdir */
- dir = ".";
- a_params.in = path_bkp;
- }
- a_params.in_size = strlen (a_params.in) + 1;
- a_params.out_size = maxsize;
- ret = k_pioctl (dir, VIOC_AFS_STAT_MT_PT, &a_params, 0);
- free (a_params.out);
- if (ret < 0) {
- free (path_bkp);
- if (errno != EINVAL)
- return ret;
- else
- /* if we get EINVAL this is probably not a mountpoint */
- return lstat (file, sb);
- }
- /*
- * wow this was a mountpoint, lets cook the struct stat
- * use . as a prototype
- */
- ret = lstat (dir, sb);
- free (path_bkp);
- if (ret < 0)
- return ret;
- if (ino_last == sb->st_ino)
- ino_counter++;
- else {
- ino_last = sb->st_ino;
- ino_counter = 0;
- }
- sb->st_ino += ino_counter;
- sb->st_nlink = 3;
- return 0;
- }
- #endif /* KRB5 */
- return lstat (file, sb);
- }
- #define IS_DOT_DOTDOT(X) ((X)[0] == '.' && ((X)[1] == '\0' || \
- ((X)[1] == '.' && (X)[2] == '\0')))
- static int
- list_files(FILE *out, const char **files, int n_files, int flags)
- {
- struct fileinfo *fi;
- int i;
- int *dirs = NULL;
- size_t total_blocks = 0;
- int n_print = 0;
- int ret = 0;
- if(n_files == 0)
- return 0;
- if(n_files > 1)
- flags |= LS_SHOW_DIRNAME;
- fi = calloc(n_files, sizeof(*fi));
- if (fi == NULL) {
- syslog(LOG_ERR, "out of memory");
- return -1;
- }
- for(i = 0; i < n_files; i++) {
- if(lstat_file(files[i], &fi[i].st) < 0) {
- sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno));
- fi[i].filename = NULL;
- } else {
- int include_in_list = 1;
- total_blocks += block_convert(fi[i].st.st_blocks);
- if(S_ISDIR(fi[i].st.st_mode)) {
- if(dirs == NULL)
- dirs = calloc(n_files, sizeof(*dirs));
- if(dirs == NULL) {
- syslog(LOG_ERR, "%s: %m", files[i]);
- ret = -1;
- goto out;
- }
- dirs[i] = 1;
- if((flags & LS_DIRS) == 0)
- include_in_list = 0;
- }
- if(include_in_list) {
- ret = make_fileinfo(out, files[i], &fi[i], flags);
- if (ret)
- goto out;
- n_print++;
- }
- }
- }
- switch(SORT_MODE(flags)) {
- case LS_SORT_NAME:
- qsort(fi, n_files, sizeof(*fi),
- (int (*)(const void*, const void*))compare_filename);
- break;
- case LS_SORT_MTIME:
- qsort(fi, n_files, sizeof(*fi),
- (int (*)(const void*, const void*))compare_mtime);
- break;
- case LS_SORT_SIZE:
- qsort(fi, n_files, sizeof(*fi),
- (int (*)(const void*, const void*))compare_size);
- break;
- }
- if(DISP_MODE(flags) == LS_DISP_LONG) {
- int max_inode = 0;
- int max_bsize = 0;
- int max_n_link = 0;
- int max_user = 0;
- int max_group = 0;
- int max_size = 0;
- int max_major = 0;
- int max_minor = 0;
- int max_date = 0;
- for(i = 0; i < n_files; i++) {
- if(fi[i].filename == NULL)
- continue;
- if(fi[i].inode > max_inode)
- max_inode = fi[i].inode;
- if(fi[i].bsize > max_bsize)
- max_bsize = fi[i].bsize;
- if(fi[i].n_link > max_n_link)
- max_n_link = fi[i].n_link;
- if(strlen(fi[i].user) > max_user)
- max_user = strlen(fi[i].user);
- if(strlen(fi[i].group) > max_group)
- max_group = strlen(fi[i].group);
- if(fi[i].major != NULL && strlen(fi[i].major) > max_major)
- max_major = strlen(fi[i].major);
- if(fi[i].minor != NULL && strlen(fi[i].minor) > max_minor)
- max_minor = strlen(fi[i].minor);
- if(fi[i].size != NULL && strlen(fi[i].size) > max_size)
- max_size = strlen(fi[i].size);
- if(strlen(fi[i].date) > max_date)
- max_date = strlen(fi[i].date);
- }
- if(max_size < max_major + max_minor + 2)
- max_size = max_major + max_minor + 2;
- else if(max_size - max_minor - 2 > max_major)
- max_major = max_size - max_minor - 2;
- max_inode = find_log10(max_inode);
- max_bsize = find_log10(max_bsize);
- max_n_link = find_log10(max_n_link);
- if(n_print > 0)
- sec_fprintf2(out, "total %lu\r\n", (unsigned long)total_blocks);
- if(flags & LS_SORT_REVERSE)
- for(i = n_files - 1; i >= 0; i--)
- print_file(out,
- flags,
- &fi[i],
- max_inode,
- max_bsize,
- max_n_link,
- max_user,
- max_group,
- max_size,
- max_major,
- max_minor,
- max_date);
- else
- for(i = 0; i < n_files; i++)
- print_file(out,
- flags,
- &fi[i],
- max_inode,
- max_bsize,
- max_n_link,
- max_user,
- max_group,
- max_size,
- max_major,
- max_minor,
- max_date);
- } else if(DISP_MODE(flags) == LS_DISP_COLUMN ||
- DISP_MODE(flags) == LS_DISP_CROSS) {
- int max_len = 0;
- int size_len = 0;
- int num_files = n_files;
- int columns;
- int j;
- for(i = 0; i < n_files; i++) {
- if(fi[i].filename == NULL) {
- num_files--;
- continue;
- }
- if(strlen(fi[i].filename) > max_len)
- max_len = strlen(fi[i].filename);
- if(find_log10(fi[i].bsize) > size_len)
- size_len = find_log10(fi[i].bsize);
- }
- if(num_files == 0)
- goto next;
- if(flags & LS_SIZE) {
- columns = 80 / (size_len + 1 + max_len + 1);
- max_len = 80 / columns - size_len - 1;
- } else {
- columns = 80 / (max_len + 1); /* get space between columns */
- max_len = 80 / columns;
- }
- if(flags & LS_SIZE)
- sec_fprintf2(out, "total %lu\r\n",
- (unsigned long)total_blocks);
- if(DISP_MODE(flags) == LS_DISP_CROSS) {
- for(i = 0, j = 0; i < n_files; i++) {
- if(fi[i].filename == NULL)
- continue;
- if(flags & LS_SIZE)
- sec_fprintf2(out, "%*u %-*s", size_len, fi[i].bsize,
- max_len, fi[i].filename);
- else
- sec_fprintf2(out, "%-*s", max_len, fi[i].filename);
- j++;
- if(j == columns) {
- sec_fprintf2(out, "\r\n");
- j = 0;
- }
- }
- if(j > 0)
- sec_fprintf2(out, "\r\n");
- } else {
- int skip = (num_files + columns - 1) / columns;
- for(i = 0; i < skip; i++) {
- for(j = i; j < n_files;) {
- while(j < n_files && fi[j].filename == NULL)
- j++;
- if(flags & LS_SIZE)
- sec_fprintf2(out, "%*u %-*s", size_len, fi[j].bsize,
- max_len, fi[j].filename);
- else
- sec_fprintf2(out, "%-*s", max_len, fi[j].filename);
- j += skip;
- }
- sec_fprintf2(out, "\r\n");
- }
- }
- } else {
- for(i = 0; i < n_files; i++) {
- if(fi[i].filename == NULL)
- continue;
- sec_fprintf2(out, "%s\r\n", fi[i].filename);
- }
- }
- next:
- if(((flags & LS_DIRS) == 0 || (flags & LS_RECURSIVE)) && dirs != NULL) {
- for(i = 0; i < n_files; i++) {
- if(dirs[i]) {
- const char *p = strrchr(files[i], '/');
- if(p == NULL)
- p = files[i];
- else
- p++;
- if(!(flags & LS_DIR_FLAG) || !IS_DOT_DOTDOT(p)) {
- if((flags & LS_SHOW_DIRNAME)) {
- if ((flags & LS_EXTRA_BLANK))
- sec_fprintf2(out, "\r\n");
- sec_fprintf2(out, "%s:\r\n", files[i]);
- }
- list_dir(out, files[i], flags | LS_DIRS | LS_EXTRA_BLANK);
- }
- }
- }
- }
- out:
- for(i = 0; i < n_files; i++)
- free_fileinfo(&fi[i]);
- free(fi);
- if(dirs != NULL)
- free(dirs);
- return ret;
- }
- static void
- free_files (char **files, int n)
- {
- int i;
- for (i = 0; i < n; ++i)
- free (files[i]);
- free (files);
- }
- static int
- hide_file(const char *filename, int flags)
- {
- if(filename[0] != '.')
- return 0;
- if((flags & LS_IGNORE_DOT))
- return 1;
- if(filename[1] == '\0' || (filename[1] == '.' && filename[2] == '\0')) {
- if((flags & LS_SHOW_ALL))
- return 0;
- else
- return 1;
- }
- return 0;
- }
- static int
- list_dir(FILE *out, const char *directory, int flags)
- {
- DIR *d = opendir(directory);
- struct dirent *ent;
- char **files = NULL;
- int n_files = 0;
- int ret;
- if(d == NULL) {
- syslog(LOG_ERR, "%s: %m", directory);
- return -1;
- }
- while((ent = readdir(d)) != NULL) {
- void *tmp;
- if(hide_file(ent->d_name, flags))
- continue;
- tmp = realloc(files, (n_files + 1) * sizeof(*files));
- if (tmp == NULL) {
- syslog(LOG_ERR, "%s: out of memory", directory);
- free_files (files, n_files);
- closedir (d);
- return -1;
- }
- files = tmp;
- ret = asprintf(&files[n_files], "%s/%s", directory, ent->d_name);
- if (ret == -1) {
- syslog(LOG_ERR, "%s: out of memory", directory);
- free_files (files, n_files);
- closedir (d);
- return -1;
- }
- ++n_files;
- }
- closedir(d);
- return list_files(out, (const char**)files, n_files, flags | LS_DIR_FLAG);
- }
- static int
- parse_flags(const char *options)
- {
- #ifdef TEST
- int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_COLUMN;
- #else
- int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_LONG;
- #endif
- const char *p;
- if(options == NULL || *options != '-')
- return flags;
- for(p = options + 1; *p; p++) {
- switch(*p) {
- case '1':
- flags = (flags & ~LS_DISP_MODE);
- break;
- case 'a':
- flags |= LS_SHOW_ALL;
- /*FALLTHROUGH*/
- case 'A':
- flags &= ~LS_IGNORE_DOT;
- break;
- case 'C':
- flags = (flags & ~LS_DISP_MODE) | LS_DISP_COLUMN;
- break;
- case 'd':
- flags |= LS_DIRS;
- break;
- case 'f':
- flags = (flags & ~LS_SORT_MODE);
- break;
- case 'F':
- flags |= LS_TYPE;
- break;
- case 'i':
- flags |= LS_INODE;
- break;
- case 'l':
- flags = (flags & ~LS_DISP_MODE) | LS_DISP_LONG;
- break;
- case 'r':
- flags |= LS_SORT_REVERSE;
- break;
- case 'R':
- flags |= LS_RECURSIVE;
- break;
- case 's':
- flags |= LS_SIZE;
- break;
- case 'S':
- flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE;
- break;
- case 't':
- flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME;
- break;
- case 'x':
- flags = (flags & ~LS_DISP_MODE) | LS_DISP_CROSS;
- break;
- /* these are a bunch of unimplemented flags from BSD ls */
- case 'k': /* display sizes in kB */
- case 'c': /* last change time */
- case 'L': /* list symlink target */
- case 'm': /* stream output */
- case 'o': /* BSD file flags */
- case 'p': /* display / after directories */
- case 'q': /* print non-graphic characters */
- case 'u': /* use last access time */
- case 'T': /* display complete time */
- case 'W': /* include whiteouts */
- break;
- }
- }
- return flags;
- }
- int
- builtin_ls(FILE *out, const char *file)
- {
- int flags;
- int ret;
- if(*file == '-') {
- flags = parse_flags(file);
- file = ".";
- } else
- flags = parse_flags("");
- ret = list_files(out, &file, 1, flags);
- sec_fflush(out);
- return ret;
- }