Whamcloud - gitweb
LU-14953 e2fsck: pfsck progress report
[tools/e2fsprogs.git] / debugfs / ls.c
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 #include "ext2fs/lfsck.h"
28
29 /*
30  * list directory
31  */
32
33 #define LONG_OPT        0x0001
34 #define PARSE_OPT       0x0002
35 #define RAW_OPT         0x0004
36 #define DIRDATA_OPT     0x0008
37 #define ENCRYPT_OPT     0x8000
38
39 struct list_dir_struct {
40         FILE    *f;
41         int     col;
42         int     options;
43         int     state;
44 };
45
46 static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
47                                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
48
49 static void list_dirdata(struct list_dir_struct *ls,
50                          struct ext2_dir_entry *dirent)
51 {
52         unsigned char   *data;
53         int             dlen;
54         __u8            dirdata_mask;
55         __u8            file_type = dirent->name_len >> 8;
56
57         data = (unsigned char *)dirent->name +
58                 (dirent->name_len & EXT2_NAME_LEN) + 1;
59
60         for (dirdata_mask = EXT2_FT_MASK + 1;
61              dirdata_mask != 0; dirdata_mask <<= 1) {
62                 if ((dirdata_mask & file_type) == 0)
63                         continue;
64
65                 dlen = data[0];
66
67                 if (dirdata_mask == EXT2_DIRENT_LUFID) {
68                         struct lu_fid *fid = (struct lu_fid *)(data + 1);
69
70                         fid_be_to_cpu(fid, fid);
71                         fprintf(ls->f, "fid:"DFID, PFID(fid));
72                 } else {
73                         int i;
74
75                         for (i = 1; i < dlen; i++)
76                                 fprintf(ls->f, "%02x", data[i]);
77                 }
78
79                 fprintf(ls->f, " ");
80                 data += dlen;
81         }
82 }
83
84 static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options)
85 {
86         unsigned char   ch;
87         const char *cp = dirent->name;
88         int len = ext2fs_dirent_name_len(dirent);
89         int retlen = 0;
90
91         if ((options & ENCRYPT_OPT) && !(options & RAW_OPT)) {
92                 if (f)
93                         return fprintf(f, "<encrypted (%d)>", len);
94                 else
95                         return snprintf(NULL, 0, "<encrypted (%d)>", len);
96         }
97         while (len--) {
98                 ch = *cp++;
99                 if (ch < 32 || ch >= 127 || ch == '\\') {
100                         if (f)
101                                 fprintf(f, "\\x%02x", ch);
102                         retlen += 4;
103                 } else {
104                         if (f)
105                                 fputc(ch, f);
106                         retlen++;
107                 }
108         }
109         return retlen;
110 }
111
112 static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
113                          int    entry,
114                          struct ext2_dir_entry *dirent,
115                          int    offset EXT2FS_ATTR((unused)),
116                          int    blocksize EXT2FS_ATTR((unused)),
117                          char   *buf EXT2FS_ATTR((unused)),
118                          void   *private)
119 {
120         struct ext2_inode       inode;
121         ext2_ino_t              ino;
122         struct tm               *tm_p;
123         time_t                  modtime;
124         char                    tmp[EXT2_NAME_LEN + 16];
125         char                    datestr[80];
126         char                    lbr, rbr;
127         int                     thislen;
128         int                     options;
129         struct list_dir_struct *ls = (struct list_dir_struct *) private;
130         struct ext2_dir_entry_tail *t = (struct ext2_dir_entry_tail *) dirent;
131
132         thislen = ext2fs_dirent_name_len(dirent);
133         ino = dirent->inode;
134         options = ls->options;
135         if (ls->state < 2) {
136                 ls->state++;
137                 options |= RAW_OPT;
138         }
139
140         if (entry == DIRENT_DELETED_FILE) {
141                 lbr = '<';
142                 rbr = '>';
143                 ino = 0;
144         } else {
145                 lbr = rbr = ' ';
146         }
147         if (options & PARSE_OPT) {
148                 if (ino) {
149                         if (debugfs_read_inode(ino, &inode, "ls"))
150                                 return 0;
151                 } else
152                         memset(&inode, 0, sizeof(struct ext2_inode));
153                 fprintf(ls->f,"/%u/%06o/%d/%d/%.*s/", ino, inode.i_mode,
154                         inode_uid(inode), inode_gid(inode), thislen, dirent->name);
155                 if (LINUX_S_ISDIR(inode.i_mode))
156                         fprintf(ls->f, "/");
157                 else
158                         fprintf(ls->f, "%llu/",
159                                 (unsigned long long) EXT2_I_SIZE(&inode));
160                 fprintf(ls->f, "\n");
161         } else if (options & LONG_OPT) {
162                 if (ino) {
163                         if (debugfs_read_inode(ino, &inode, "ls"))
164                                 return 0;
165                         modtime = inode.i_mtime;
166                         tm_p = localtime(&modtime);
167                         sprintf(datestr, "%2d-%s-%4d %02d:%02d",
168                                 tm_p->tm_mday, monstr[tm_p->tm_mon],
169                                 1900 + tm_p->tm_year, tm_p->tm_hour,
170                                 tm_p->tm_min);
171                 } else {
172                         strcpy(datestr, "                 ");
173                         memset(&inode, 0, sizeof(struct ext2_inode));
174                 }
175                 fprintf(ls->f, "%c%6u%c %6o ", lbr, ino, rbr, inode.i_mode);
176                 if (entry == DIRENT_CHECKSUM) {
177                         fprintf(ls->f, "(dirblock checksum: 0x%08x)\n",
178                                 t->det_checksum);
179                         return 0;
180                 }
181                 fprintf(ls->f, "(%d)  %5d  %5d   ",
182                         ext2fs_dirent_file_type(dirent),
183                         inode_uid(inode), inode_gid(inode));
184                         fprintf(ls->f, "%5llu",
185                                 (unsigned long long) EXT2_I_SIZE(&inode));
186                 fprintf(ls->f, " %s ", datestr);
187                 if ((ls->options & DIRDATA_OPT) != 0)
188                         list_dirdata(ls, dirent);
189                 print_filename(ls->f, dirent, options);
190                 fputc('\n', ls->f);
191         } else {
192                 if (entry == DIRENT_CHECKSUM) {
193                         sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x)   ",
194                                 lbr, dirent->inode, rbr, t->det_checksum);
195                         thislen = strlen(tmp);
196                         if (ls->col + thislen > 80) {
197                                 fputc('\n', ls->f);
198                                 ls->col = 0;
199                         }
200                         fprintf(ls->f, "%s", tmp);
201                         ls->col += thislen;
202                         return 0;
203                 }
204                 sprintf(tmp, "%c%u%c (%d) ", lbr, dirent->inode, rbr,
205                         dirent->rec_len);
206                 thislen = strlen(tmp) + 3;
207                 thislen += print_filename(NULL, dirent, options);
208
209                 if (ls->col + thislen > 80) {
210                         fputc('\n', ls->f);
211                         ls->col = 0;
212                 }
213                 fprintf(ls->f, "%s", tmp);
214                 print_filename(ls->f, dirent, options);
215                 fputs("   ", ls->f);
216                 ls->col += thislen;
217         }
218         return 0;
219 }
220
221 void do_list_dir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
222                  void *infop EXT2FS_ATTR((unused)))
223 {
224         struct ext2_inode inode;
225         ext2_ino_t      ino;
226         int             retval;
227         int             c;
228         int             flags = DIRENT_FLAG_INCLUDE_EMPTY;
229         struct list_dir_struct ls;
230
231         ls.options = 0;
232         ls.state = 0;
233         if (check_fs_open(argv[0]))
234                 return;
235
236         reset_getopt();
237         while ((c = getopt(argc, argv, "cdDlpr")) != EOF) {
238                 switch (c) {
239                 case 'c':
240                         flags |= DIRENT_FLAG_INCLUDE_CSUM;
241                         break;
242                 case 'l':
243                         ls.options |= LONG_OPT;
244                         break;
245                 case 'D':
246                         ls.options |= DIRDATA_OPT;
247                         break;
248                 case 'd':
249                         flags |= DIRENT_FLAG_INCLUDE_REMOVED;
250                         break;
251                 case 'p':
252                         ls.options |= PARSE_OPT;
253                         break;
254                 case 'r':
255                         ls.options |= RAW_OPT;
256                         break;
257                 default:
258                         goto print_usage;
259                 }
260         }
261
262         if (argc > optind+1) {
263         print_usage:
264                 com_err(0, 0, "Usage: ls [-c] [-d] [-l] [-p] [-r] [-D] file");
265                 return;
266         }
267
268         if (argc == optind)
269                 ino = cwd;
270         else
271                 ino = string_to_inode(argv[optind]);
272         if (!ino)
273                 return;
274
275         ls.f = open_pager();
276         ls.col = 0;
277
278         if (debugfs_read_inode(ino, &inode, argv[0]))
279                 return;
280
281         if (inode.i_flags & EXT4_ENCRYPT_FL)
282                 ls.options |= ENCRYPT_OPT;
283
284         retval = ext2fs_dir_iterate2(current_fs, ino, flags,
285                                     0, list_dir_proc, &ls);
286         fprintf(ls.f, "\n");
287         close_pager(ls.f);
288         if (retval)
289                 com_err(argv[1], retval, 0);
290
291         return;
292 }
293
294