Whamcloud - gitweb
LU-8465 e2fsck: do not change global variables
[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.i_uid, inode.i_gid, thislen, dirent->name);
155                 if (LINUX_S_ISDIR(inode.i_mode))
156                         fprintf(ls->f, "/");
157                 else
158                         fprintf(ls->f, "%lld/", EXT2_I_SIZE(&inode));
159                 fprintf(ls->f, "\n");
160         } else if (options & LONG_OPT) {
161                 if (ino) {
162                         if (debugfs_read_inode(ino, &inode, "ls"))
163                                 return 0;
164                         modtime = inode.i_mtime;
165                         tm_p = localtime(&modtime);
166                         sprintf(datestr, "%2d-%s-%4d %02d:%02d",
167                                 tm_p->tm_mday, monstr[tm_p->tm_mon],
168                                 1900 + tm_p->tm_year, tm_p->tm_hour,
169                                 tm_p->tm_min);
170                 } else {
171                         strcpy(datestr, "                 ");
172                         memset(&inode, 0, sizeof(struct ext2_inode));
173                 }
174                 fprintf(ls->f, "%c%6u%c %6o ", lbr, ino, rbr, inode.i_mode);
175                 if (entry == DIRENT_CHECKSUM) {
176                         fprintf(ls->f, "(dirblock checksum: 0x%08x)\n",
177                                 t->det_checksum);
178                         return 0;
179                 }
180                 fprintf(ls->f, "(%d)  %5d  %5d   ",
181                         ext2fs_dirent_file_type(dirent),
182                         inode_uid(inode), inode_gid(inode));
183                         fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode));
184                 fprintf(ls->f, " %s ", datestr);
185                 if ((ls->options & DIRDATA_OPT) != 0)
186                         list_dirdata(ls, dirent);
187                 print_filename(ls->f, dirent, options);
188                 fputc('\n', ls->f);
189         } else {
190                 if (entry == DIRENT_CHECKSUM) {
191                         sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x)   ",
192                                 lbr, dirent->inode, rbr, t->det_checksum);
193                         thislen = strlen(tmp);
194                         if (ls->col + thislen > 80) {
195                                 fputc('\n', ls->f);
196                                 ls->col = 0;
197                         }
198                         fprintf(ls->f, "%s", tmp);
199                         ls->col += thislen;
200                         return 0;
201                 }
202                 sprintf(tmp, "%c%u%c (%d) ", lbr, dirent->inode, rbr,
203                         dirent->rec_len);
204                 thislen = strlen(tmp) + 3;
205                 thislen += print_filename(NULL, dirent, options);
206
207                 if (ls->col + thislen > 80) {
208                         fputc('\n', ls->f);
209                         ls->col = 0;
210                 }
211                 fprintf(ls->f, "%s", tmp);
212                 print_filename(ls->f, dirent, options);
213                 fputs("   ", ls->f);
214                 ls->col += thislen;
215         }
216         return 0;
217 }
218
219 void do_list_dir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
220                  void *infop EXT2FS_ATTR((unused)))
221 {
222         struct ext2_inode inode;
223         ext2_ino_t      ino;
224         int             retval;
225         int             c;
226         int             flags = DIRENT_FLAG_INCLUDE_EMPTY;
227         struct list_dir_struct ls;
228
229         ls.options = 0;
230         ls.state = 0;
231         if (check_fs_open(argv[0]))
232                 return;
233
234         reset_getopt();
235         while ((c = getopt(argc, argv, "cdDlpr")) != EOF) {
236                 switch (c) {
237                 case 'c':
238                         flags |= DIRENT_FLAG_INCLUDE_CSUM;
239                         break;
240                 case 'l':
241                         ls.options |= LONG_OPT;
242                         break;
243                 case 'D':
244                         ls.options |= DIRDATA_OPT;
245                         break;
246                 case 'd':
247                         flags |= DIRENT_FLAG_INCLUDE_REMOVED;
248                         break;
249                 case 'p':
250                         ls.options |= PARSE_OPT;
251                         break;
252                 case 'r':
253                         ls.options |= RAW_OPT;
254                         break;
255                 default:
256                         goto print_usage;
257                 }
258         }
259
260         if (argc > optind+1) {
261         print_usage:
262                 com_err(0, 0, "Usage: ls [-c] [-d] [-l] [-p] [-r] [-D] file");
263                 return;
264         }
265
266         if (argc == optind)
267                 ino = cwd;
268         else
269                 ino = string_to_inode(argv[optind]);
270         if (!ino)
271                 return;
272
273         ls.f = open_pager();
274         ls.col = 0;
275
276         if (debugfs_read_inode(ino, &inode, argv[0]))
277                 return;
278
279         if (inode.i_flags & EXT4_ENCRYPT_FL)
280                 ls.options |= ENCRYPT_OPT;
281
282         retval = ext2fs_dir_iterate2(current_fs, ino, flags,
283                                     0, list_dir_proc, &ls);
284         fprintf(ls.f, "\n");
285         close_pager(ls.f);
286         if (retval)
287                 com_err(argv[1], retval, 0);
288
289         return;
290 }
291
292