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