Whamcloud - gitweb
1b549b4b7c1d9edbceb5861c145aa2c23d3ec681
[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                         char tmp[1];
96                         return snprintf(tmp, sizeof(tmp),
97                                         "<encrypted (%d)>", len);
98                 }
99         }
100         while (len--) {
101                 ch = *cp++;
102                 if (ch > 128) {
103                         if (f)
104                                 fputs("M-", f);
105                         ch -= 128;
106                         retlen += 2;
107                 }
108                 if ((ch < 32) || (ch == 0x7f)) {
109                         if (f)
110                                 fputc('^', f);
111                         ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
112                         retlen++;
113                 }
114                 if (f)
115                         fputc(ch, f);
116                 retlen++;
117         }
118         return retlen;
119 }
120
121 static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
122                          int    entry,
123                          struct ext2_dir_entry *dirent,
124                          int    offset EXT2FS_ATTR((unused)),
125                          int    blocksize EXT2FS_ATTR((unused)),
126                          char   *buf EXT2FS_ATTR((unused)),
127                          void   *private)
128 {
129         struct ext2_inode       inode;
130         ext2_ino_t              ino;
131         struct tm               *tm_p;
132         time_t                  modtime;
133         char                    tmp[EXT2_NAME_LEN + 16];
134         char                    datestr[80];
135         char                    lbr, rbr;
136         int                     thislen;
137         int                     options;
138         struct list_dir_struct *ls = (struct list_dir_struct *) private;
139         struct ext2_dir_entry_tail *t = (struct ext2_dir_entry_tail *) dirent;
140
141         thislen = ext2fs_dirent_name_len(dirent);
142         ino = dirent->inode;
143         options = ls->options;
144         if (ls->state < 2) {
145                 ls->state++;
146                 options |= RAW_OPT;
147         }
148
149         if (entry == DIRENT_DELETED_FILE) {
150                 lbr = '<';
151                 rbr = '>';
152                 ino = 0;
153         } else {
154                 lbr = rbr = ' ';
155         }
156         if (options & PARSE_OPT) {
157                 if (ino) {
158                         if (debugfs_read_inode(ino, &inode, "ls"))
159                                 return 0;
160                 } else
161                         memset(&inode, 0, sizeof(struct ext2_inode));
162                 fprintf(ls->f,"/%u/%06o/%d/%d/%.*s/", ino, inode.i_mode,
163                         inode.i_uid, inode.i_gid, thislen, dirent->name);
164                 if (LINUX_S_ISDIR(inode.i_mode))
165                         fprintf(ls->f, "/");
166                 else
167                         fprintf(ls->f, "%lld/", EXT2_I_SIZE(&inode));
168                 fprintf(ls->f, "\n");
169         } else if (options & LONG_OPT) {
170                 if (ino) {
171                         if (debugfs_read_inode(ino, &inode, "ls"))
172                                 return 0;
173                         modtime = inode.i_mtime;
174                         tm_p = localtime(&modtime);
175                         sprintf(datestr, "%2d-%s-%4d %02d:%02d",
176                                 tm_p->tm_mday, monstr[tm_p->tm_mon],
177                                 1900 + tm_p->tm_year, tm_p->tm_hour,
178                                 tm_p->tm_min);
179                 } else {
180                         strcpy(datestr, "                 ");
181                         memset(&inode, 0, sizeof(struct ext2_inode));
182                 }
183                 fprintf(ls->f, "%c%6u%c %6o ", lbr, ino, rbr, inode.i_mode);
184                 if (entry == DIRENT_CHECKSUM) {
185                         fprintf(ls->f, "(dirblock checksum: 0x%08x)\n",
186                                 t->det_checksum);
187                         return 0;
188                 }
189                 fprintf(ls->f, "(%d)  %5d  %5d   ",
190                         ext2fs_dirent_file_type(dirent),
191                         inode_uid(inode), inode_gid(inode));
192                 if (LINUX_S_ISDIR(inode.i_mode))
193                         fprintf(ls->f, "%5d", inode.i_size);
194                 else
195                         fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode));
196                 fprintf(ls->f, " %s ", datestr);
197                 if ((ls->options & DIRDATA_OPT) != 0)
198                         list_dirdata(ls, dirent);
199                 print_filename(ls->f, dirent, options);
200                 fputc('\n', ls->f);
201         } else {
202                 if (entry == DIRENT_CHECKSUM) {
203                         sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x)   ",
204                                 lbr, dirent->inode, rbr, t->det_checksum);
205                         thislen = strlen(tmp);
206                         if (ls->col + thislen > 80) {
207                                 fputc('\n', ls->f);
208                                 ls->col = 0;
209                         }
210                         fprintf(ls->f, "%s", tmp);
211                         ls->col += thislen;
212                         return 0;
213                 }
214                 sprintf(tmp, "%c%u%c (%d) ", lbr, dirent->inode, rbr,
215                         dirent->rec_len);
216                 thislen = strlen(tmp) + 3;
217                 thislen += print_filename(NULL, dirent, options);
218
219                 if (ls->col + thislen > 80) {
220                         fputc('\n', ls->f);
221                         ls->col = 0;
222                 }
223                 fprintf(ls->f, "%s", tmp);
224                 print_filename(ls->f, dirent, options);
225                 fputs("   ", ls->f);
226                 ls->col += thislen;
227         }
228         return 0;
229 }
230
231 void do_list_dir(int argc, char *argv[])
232 {
233         struct ext2_inode inode;
234         ext2_ino_t      ino;
235         int             retval;
236         int             c;
237         int             flags = DIRENT_FLAG_INCLUDE_EMPTY;
238         struct list_dir_struct ls;
239
240         ls.options = 0;
241         ls.state = 0;
242         if (check_fs_open(argv[0]))
243                 return;
244
245         reset_getopt();
246         while ((c = getopt(argc, argv, "cdDlpr")) != EOF) {
247                 switch (c) {
248                 case 'c':
249                         flags |= DIRENT_FLAG_INCLUDE_CSUM;
250                         break;
251                 case 'l':
252                         ls.options |= LONG_OPT;
253                         break;
254                 case 'D':
255                         ls.options |= DIRDATA_OPT;
256                         break;
257                 case 'd':
258                         flags |= DIRENT_FLAG_INCLUDE_REMOVED;
259                         break;
260                 case 'p':
261                         ls.options |= PARSE_OPT;
262                         break;
263                 case 'r':
264                         ls.options |= RAW_OPT;
265                         break;
266                 default:
267                         goto print_usage;
268                 }
269         }
270
271         if (argc > optind+1) {
272         print_usage:
273                 com_err(0, 0, "Usage: ls [-c] [-d] [-l] [-p] [-r] file");
274                 return;
275         }
276
277         if (argc == optind)
278                 ino = cwd;
279         else
280                 ino = string_to_inode(argv[optind]);
281         if (!ino)
282                 return;
283
284         ls.f = open_pager();
285         ls.col = 0;
286
287         if (debugfs_read_inode(ino, &inode, argv[0]))
288                 return;
289
290         if (inode.i_flags & EXT4_ENCRYPT_FL)
291                 ls.options |= ENCRYPT_OPT;
292
293         retval = ext2fs_dir_iterate2(current_fs, ino, flags,
294                                     0, list_dir_proc, &ls);
295         fprintf(ls.f, "\n");
296         close_pager(ls.f);
297         if (retval)
298                 com_err(argv[1], retval, 0);
299
300         return;
301 }
302
303