Home | History | Annotate | Download | only in debugfs
      1 /*
      2  * ls.c --- list directories
      3  *
      4  * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
      5  * under the terms of the GNU Public License.
      6  */
      7 
      8 #include "config.h"
      9 #include <stdio.h>
     10 #include <unistd.h>
     11 #include <stdlib.h>
     12 #include <ctype.h>
     13 #include <string.h>
     14 #include <time.h>
     15 #ifdef HAVE_ERRNO_H
     16 #include <errno.h>
     17 #endif
     18 #include <sys/types.h>
     19 #ifdef HAVE_GETOPT_H
     20 #include <getopt.h>
     21 #else
     22 extern int optind;
     23 extern char *optarg;
     24 #endif
     25 
     26 #include "debugfs.h"
     27 
     28 /*
     29  * list directory
     30  */
     31 
     32 #define LONG_OPT	0x0001
     33 #define PARSE_OPT	0x0002
     34 #define RAW_OPT		0x0004
     35 #define ENCRYPT_OPT	0x8000
     36 
     37 struct list_dir_struct {
     38 	FILE	*f;
     39 	int	col;
     40 	int	options;
     41 	int	state;
     42 };
     43 
     44 static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     45 				"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
     46 
     47 static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options)
     48 {
     49 	unsigned char	ch;
     50 	const char *cp = dirent->name;
     51 	int len = ext2fs_dirent_name_len(dirent);
     52 	int retlen = 0;
     53 
     54 	if ((options & ENCRYPT_OPT) && !(options & RAW_OPT)) {
     55 		if (f)
     56 			return fprintf(f, "<encrypted (%d)>", len);
     57 		else {
     58 			char tmp[1];
     59 			return snprintf(tmp, sizeof(tmp),
     60 					"<encrypted (%d)>", len);
     61 		}
     62 	}
     63 	while (len--) {
     64 		ch = *cp++;
     65 		if (ch > 128) {
     66 			if (f)
     67 				fputs("M-", f);
     68 			ch -= 128;
     69 			retlen += 2;
     70 		}
     71 		if ((ch < 32) || (ch == 0x7f)) {
     72 			if (f)
     73 				fputc('^', f);
     74 			ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
     75 			retlen++;
     76 		}
     77 		if (f)
     78 			fputc(ch, f);
     79 		retlen++;
     80 	}
     81 	return retlen;
     82 }
     83 
     84 static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
     85 			 int	entry,
     86 			 struct ext2_dir_entry *dirent,
     87 			 int	offset EXT2FS_ATTR((unused)),
     88 			 int	blocksize EXT2FS_ATTR((unused)),
     89 			 char	*buf EXT2FS_ATTR((unused)),
     90 			 void	*private)
     91 {
     92 	struct ext2_inode	inode;
     93 	ext2_ino_t		ino;
     94 	struct tm		*tm_p;
     95 	time_t			modtime;
     96 	char			tmp[EXT2_NAME_LEN + 16];
     97 	char			datestr[80];
     98 	char			lbr, rbr;
     99 	int			thislen;
    100 	int			options;
    101 	struct list_dir_struct *ls = (struct list_dir_struct *) private;
    102 	struct ext2_dir_entry_tail *t = (struct ext2_dir_entry_tail *) dirent;
    103 
    104 	thislen = ext2fs_dirent_name_len(dirent);
    105 	ino = dirent->inode;
    106 	options = ls->options;
    107 	if (ls->state < 2) {
    108 		ls->state++;
    109 		options |= RAW_OPT;
    110 	}
    111 
    112 	if (entry == DIRENT_DELETED_FILE) {
    113 		lbr = '<';
    114 		rbr = '>';
    115 		ino = 0;
    116 	} else {
    117 		lbr = rbr = ' ';
    118 	}
    119 	if (options & PARSE_OPT) {
    120 		if (ino) {
    121 			if (debugfs_read_inode(ino, &inode, "ls"))
    122 				return 0;
    123 		} else
    124 			memset(&inode, 0, sizeof(struct ext2_inode));
    125 		fprintf(ls->f,"/%u/%06o/%d/%d/%*s/", ino, inode.i_mode,
    126 			inode.i_uid, inode.i_gid, thislen, dirent->name);
    127 		if (LINUX_S_ISDIR(inode.i_mode))
    128 			fprintf(ls->f, "/");
    129 		else
    130 			fprintf(ls->f, "%lld/", EXT2_I_SIZE(&inode));
    131 		fprintf(ls->f, "\n");
    132 	} else if (options & LONG_OPT) {
    133 		if (ino) {
    134 			if (debugfs_read_inode(ino, &inode, "ls"))
    135 				return 0;
    136 			modtime = inode.i_mtime;
    137 			tm_p = localtime(&modtime);
    138 			sprintf(datestr, "%2d-%s-%4d %02d:%02d",
    139 				tm_p->tm_mday, monstr[tm_p->tm_mon],
    140 				1900 + tm_p->tm_year, tm_p->tm_hour,
    141 				tm_p->tm_min);
    142 		} else {
    143 			strcpy(datestr, "                 ");
    144 			memset(&inode, 0, sizeof(struct ext2_inode));
    145 		}
    146 		fprintf(ls->f, "%c%6u%c %6o ", lbr, ino, rbr, inode.i_mode);
    147 		if (entry == DIRENT_CHECKSUM) {
    148 			fprintf(ls->f, "(dirblock checksum: 0x%08x)\n",
    149 				t->det_checksum);
    150 			return 0;
    151 		}
    152 		fprintf(ls->f, "(%d)  %5d  %5d   ",
    153 			ext2fs_dirent_file_type(dirent),
    154 			inode_uid(inode), inode_gid(inode));
    155 		if (LINUX_S_ISDIR(inode.i_mode))
    156 			fprintf(ls->f, "%5d", inode.i_size);
    157 		else
    158 			fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode));
    159 		fputs(datestr, ls->f);
    160 		fputc(' ', ls->f);
    161 		print_filename(ls->f, dirent, options);
    162 		fputc('\n', ls->f);
    163 	} else {
    164 		if (entry == DIRENT_CHECKSUM) {
    165 			sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x)   ",
    166 				lbr, dirent->inode, rbr, t->det_checksum);
    167 			thislen = strlen(tmp);
    168 			if (ls->col + thislen > 80) {
    169 				fputc('\n', ls->f);
    170 				ls->col = 0;
    171 			}
    172 			fprintf(ls->f, "%s", tmp);
    173 			ls->col += thislen;
    174 			return 0;
    175 		}
    176 		sprintf(tmp, "%c%u%c (%d) ", lbr, dirent->inode, rbr,
    177 			dirent->rec_len);
    178 		thislen = strlen(tmp) + 3;
    179 		thislen += print_filename(NULL, dirent, options);
    180 
    181 		if (ls->col + thislen > 80) {
    182 			fputc('\n', ls->f);
    183 			ls->col = 0;
    184 		}
    185 		fprintf(ls->f, "%s", tmp);
    186 		print_filename(ls->f, dirent, options);
    187 		fputs("   ", ls->f);
    188 		ls->col += thislen;
    189 	}
    190 	return 0;
    191 }
    192 
    193 void do_list_dir(int argc, char *argv[])
    194 {
    195 	struct ext2_inode inode;
    196 	ext2_ino_t	ino;
    197 	int		retval;
    198 	int		c;
    199 	int		flags = DIRENT_FLAG_INCLUDE_EMPTY;
    200 	struct list_dir_struct ls;
    201 
    202 	ls.options = 0;
    203 	ls.state = 0;
    204 	if (check_fs_open(argv[0]))
    205 		return;
    206 
    207 	reset_getopt();
    208 	while ((c = getopt (argc, argv, "cdlpr")) != EOF) {
    209 		switch (c) {
    210 		case 'c':
    211 			flags |= DIRENT_FLAG_INCLUDE_CSUM;
    212 			break;
    213 		case 'l':
    214 			ls.options |= LONG_OPT;
    215 			break;
    216 		case 'd':
    217 			flags |= DIRENT_FLAG_INCLUDE_REMOVED;
    218 			break;
    219 		case 'p':
    220 			ls.options |= PARSE_OPT;
    221 			break;
    222 		case 'r':
    223 			ls.options |= RAW_OPT;
    224 			break;
    225 		default:
    226 			goto print_usage;
    227 		}
    228 	}
    229 
    230 	if (argc > optind+1) {
    231 	print_usage:
    232 		com_err(0, 0, "Usage: ls [-l] [-d] [-p] file");
    233 		return;
    234 	}
    235 
    236 	if (argc == optind)
    237 		ino = cwd;
    238 	else
    239 		ino = string_to_inode(argv[optind]);
    240 	if (!ino)
    241 		return;
    242 
    243 	ls.f = open_pager();
    244 	ls.col = 0;
    245 
    246 	if (debugfs_read_inode(ino, &inode, argv[0]))
    247 		return;
    248 
    249 	if (inode.i_flags & EXT4_ENCRYPT_FL)
    250 		ls.options |= ENCRYPT_OPT;
    251 
    252 	retval = ext2fs_dir_iterate2(current_fs, ino, flags,
    253 				    0, list_dir_proc, &ls);
    254 	fprintf(ls.f, "\n");
    255 	close_pager(ls.f);
    256 	if (retval)
    257 		com_err(argv[1], retval, 0);
    258 
    259 	return;
    260 }
    261 
    262 
    263