simple ls
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@7086 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
		
							
								
								
									
										437
									
								
								appl/ftp/ftpd/ls.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								appl/ftp/ftpd/ls.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,437 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 1999 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. */ | ||||||
|  |  | ||||||
|  | #include "ftpd_locl.h" | ||||||
|  |  | ||||||
|  | RCSID("$Id$"); | ||||||
|  |  | ||||||
|  | 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; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #define LS_DIRS		 1 | ||||||
|  | #define LS_IGNORE_DOT	 2 | ||||||
|  | #define LS_SORT_MODE	 12 | ||||||
|  | #define SORT_MODE(f) ((f) & LS_SORT_MODE) | ||||||
|  | #define LS_SORT_NAME	 4 | ||||||
|  | #define LS_SORT_MTIME	 8 | ||||||
|  | #define LS_SORT_SIZE	12 | ||||||
|  | #define LS_SORT_REVERSE	16 | ||||||
|  |  | ||||||
|  | #define LS_SIZE		32 | ||||||
|  | #define LS_INODE	64 | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | make_fileinfo(const char *filename, struct fileinfo *file, int flags) | ||||||
|  | { | ||||||
|  |     char buf[128]; | ||||||
|  |     struct stat *st = &file->st; | ||||||
|  |  | ||||||
|  |     file->inode = st->st_ino; | ||||||
|  | #ifdef S_BLKSIZE | ||||||
|  |     file->bsize = st->st_blocks * S_BLKSIZE / 1024; | ||||||
|  | #else | ||||||
|  |     file->bsize = st->st_blocks * 512 / 1024; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     if(S_ISDIR(st->st_mode)) | ||||||
|  | 	file->mode[0] = 'd'; | ||||||
|  |     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] = '-'; | ||||||
|  |     else if(S_ISFIFO(st->st_mode)) | ||||||
|  | 	file->mode[0] = 'p'; | ||||||
|  |     else if(S_ISLNK(st->st_mode)) | ||||||
|  | 	file->mode[0] = 'l'; | ||||||
|  |     else if(S_ISSOCK(st->st_mode)) | ||||||
|  | 	file->mode[0] = 's'; | ||||||
|  |     else if(S_ISWHT(st->st_mode)) | ||||||
|  | 	file->mode[0] = 'w'; | ||||||
|  |     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) | ||||||
|  | 	    asprintf(&file->user, "%d", st->st_uid); | ||||||
|  | 	else | ||||||
|  | 	    file->user = strdup(pwd->pw_name); | ||||||
|  |     } | ||||||
|  |     { | ||||||
|  | 	struct group *grp; | ||||||
|  | 	grp = getgrgid(st->st_gid); | ||||||
|  | 	if(grp == NULL) | ||||||
|  | 	    asprintf(&file->group, "%d", st->st_gid); | ||||||
|  | 	else | ||||||
|  | 	    file->group = strdup(grp->gr_name); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if(S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { | ||||||
|  | 	asprintf(&file->major, "%u", major(st->st_rdev)); | ||||||
|  | 	asprintf(&file->minor, "%u", minor(st->st_rdev)); | ||||||
|  |     } else | ||||||
|  | 	asprintf(&file->size, "%lu", (unsigned long)st->st_size); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  | 	time_t t = time(NULL); | ||||||
|  | 	struct tm *tm = localtime(&st->st_mtime); | ||||||
|  | 	if((t - st->st_mtime > 6*30*24*60*60) || | ||||||
|  | 	   (st->st_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); | ||||||
|  |     } | ||||||
|  |     { | ||||||
|  | 	const char *p = strrchr(filename, '/'); | ||||||
|  | 	if(p) | ||||||
|  | 	    p++; | ||||||
|  | 	else | ||||||
|  | 	    p = filename; | ||||||
|  | 	file->filename = strdup(p); | ||||||
|  |     } | ||||||
|  |     if(S_ISLNK(st->st_mode)) { | ||||||
|  | 	int n; | ||||||
|  | 	n = readlink(filename, buf, sizeof(buf)); | ||||||
|  | 	if(n >= 0) { | ||||||
|  | 	    buf[n] = '\0'; | ||||||
|  | 	    file->link = strdup(buf); | ||||||
|  | 	} else | ||||||
|  | 	    warn("%s: readlink", filename); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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 a->st.st_mtime - b->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 a->st.st_size - b->st.st_size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | list_dir(FILE *out, const char *directory, int flags); | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | log10(int num) | ||||||
|  | { | ||||||
|  |     int i = 1; | ||||||
|  |     while(num > 10) { | ||||||
|  | 	i++; | ||||||
|  | 	num /= 10; | ||||||
|  |     } | ||||||
|  |     return i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | list_files(FILE *out, char **files, int n_files, int flags) | ||||||
|  | { | ||||||
|  |     struct fileinfo *fi; | ||||||
|  |     int i; | ||||||
|  |     fi = calloc(n_files, sizeof(*fi)); | ||||||
|  |     for(i = 0; i < n_files; i++) { | ||||||
|  | 	if(lstat(files[i], &fi[i].st) < 0) { | ||||||
|  | 	    sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno)); | ||||||
|  | 	    fi[i].filename = NULL; | ||||||
|  | 	} else { | ||||||
|  | 	    if((flags & LS_DIRS) == 0 && S_ISDIR(fi[i].st.st_mode)) { | ||||||
|  | 		if(n_files > 1) | ||||||
|  | 		    sec_fprintf2(out, "%s:\r\n", files[i]); | ||||||
|  | 		list_dir(out, files[i], flags); | ||||||
|  | 	    } else { | ||||||
|  | 		make_fileinfo(files[i], &fi[i], flags); | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  |     { | ||||||
|  | 	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 = log10(max_inode); | ||||||
|  | 	max_bsize = log10(max_bsize); | ||||||
|  | 	max_n_link = log10(max_n_link); | ||||||
|  |  | ||||||
|  | 	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); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | list_dir(FILE *out, const char *directory, int flags) | ||||||
|  | { | ||||||
|  |     DIR *d = opendir(directory); | ||||||
|  |     struct dirent *ent; | ||||||
|  |     char **files = NULL; | ||||||
|  |     int n_files = 0; | ||||||
|  |     if(d == NULL) { | ||||||
|  | 	warn("%s", directory); | ||||||
|  | 	return; | ||||||
|  |     } | ||||||
|  |     while((ent = readdir(d)) != NULL) { | ||||||
|  | 	if(ent->d_name[0] == '.') { | ||||||
|  | 	    if((ent->d_namlen == 1) || | ||||||
|  | 	       (ent->d_namlen == 2 && ent->d_name[1] == '.') || | ||||||
|  | 	       (flags & LS_IGNORE_DOT)) | ||||||
|  | 		continue; | ||||||
|  | 	} | ||||||
|  | 	files = realloc(files, (n_files + 1) * sizeof(*files)); | ||||||
|  | 	asprintf(&files[n_files++], "%s/%s", directory, ent->d_name); | ||||||
|  |     } | ||||||
|  |     closedir(d); | ||||||
|  |     list_files(out, files, n_files, flags | LS_DIRS); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | builtin_ls(FILE *out, const char *file) | ||||||
|  | { | ||||||
|  |     int c; | ||||||
|  |     int flags = LS_SORT_NAME; | ||||||
|  |     if(*file == '-') { | ||||||
|  | 	const char *p; | ||||||
|  | 	for(p = file + 1; *p; p++) { | ||||||
|  | 	    switch(*p) { | ||||||
|  | 	    case 'a': | ||||||
|  | 	    case 'A': | ||||||
|  | 		flags &= ~LS_IGNORE_DOT; | ||||||
|  | 		break; | ||||||
|  | 	    case 'C': | ||||||
|  | 		break; | ||||||
|  | 	    case 'd': | ||||||
|  | 	    flags |= LS_DIRS; | ||||||
|  | 	    case 'f': | ||||||
|  | 		flags = (flags & ~LS_SORT_MODE); | ||||||
|  | 		break; | ||||||
|  | 	    case 'i': | ||||||
|  | 		flags |= flags | LS_INODE; | ||||||
|  | 		break; | ||||||
|  | 	    case 'l': | ||||||
|  | 		break; | ||||||
|  | 	    case 't': | ||||||
|  | 		flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME; | ||||||
|  | 		break; | ||||||
|  | 	    case 's': | ||||||
|  | 		flags |= LS_SIZE; | ||||||
|  | 		break; | ||||||
|  | 	    case 'S': | ||||||
|  | 		flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE; | ||||||
|  | 		break; | ||||||
|  | 	    case 'r': | ||||||
|  | 		flags |= LS_SORT_REVERSE; | ||||||
|  | 		break; | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  | 	file = "."; | ||||||
|  |     } | ||||||
|  |     list_files(out, &file, 1, flags); | ||||||
|  |     sec_fflush(out); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Johan Danielsson
					Johan Danielsson