diff options
Diffstat (limited to '')
-rw-r--r-- | debugfs/ls.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/debugfs/ls.c b/debugfs/ls.c new file mode 100644 index 0000000..525f084 --- /dev/null +++ b/debugfs/ls.c @@ -0,0 +1,252 @@ +/* + * ls.c --- list directories + * + * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed + * under the terms of the GNU Public License. + */ + +#include "config.h" +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <time.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <sys/types.h> +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#else +extern int optind; +extern char *optarg; +#endif + +#include "debugfs.h" + +/* + * list directory + */ + +#define LONG_OPT 0x0001 +#define PARSE_OPT 0x0002 +#define RAW_OPT 0x0004 +#define ENCRYPT_OPT 0x8000 + +struct list_dir_struct { + FILE *f; + int col; + int options; + int state; +}; + +static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options) +{ + unsigned char ch; + const char *cp = dirent->name; + int len = ext2fs_dirent_name_len(dirent); + int retlen = 0; + + if ((options & ENCRYPT_OPT) && !(options & RAW_OPT)) { + if (f) + return fprintf(f, "<encrypted (%d)>", len); + else + return snprintf(NULL, 0, "<encrypted (%d)>", len); + } + while (len--) { + ch = *cp++; + if (ch < 32 || ch >= 127 || ch == '\\') { + if (f) + fprintf(f, "\\x%02x", ch); + retlen += 4; + } else { + if (f) + fputc(ch, f); + retlen++; + } + } + return retlen; +} + +static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), + int entry, + struct ext2_dir_entry *dirent, + int offset EXT2FS_ATTR((unused)), + int blocksize EXT2FS_ATTR((unused)), + char *buf EXT2FS_ATTR((unused)), + void *private) +{ + struct ext2_inode inode; + ext2_ino_t ino; + struct tm *tm_p; + time_t modtime; + char tmp[EXT2_NAME_LEN + 16]; + char datestr[80]; + char lbr, rbr; + int thislen; + int options; + struct list_dir_struct *ls = (struct list_dir_struct *) private; + struct ext2_dir_entry_tail *t = (struct ext2_dir_entry_tail *) dirent; + + thislen = ext2fs_dirent_name_len(dirent); + ino = dirent->inode; + options = ls->options; + if (ls->state < 2) { + ls->state++; + options |= RAW_OPT; + } + + if (entry == DIRENT_DELETED_FILE) { + lbr = '<'; + rbr = '>'; + ino = 0; + } else { + lbr = rbr = ' '; + } + if (options & PARSE_OPT) { + if (ino) { + if (debugfs_read_inode(ino, &inode, "ls")) + return 0; + } else + memset(&inode, 0, sizeof(struct ext2_inode)); + fprintf(ls->f,"/%u/%06o/%d/%d/%.*s/", ino, inode.i_mode, + inode_uid(inode), inode_gid(inode), thislen, dirent->name); + if (LINUX_S_ISDIR(inode.i_mode)) + fprintf(ls->f, "/"); + else + fprintf(ls->f, "%llu/", + (unsigned long long) EXT2_I_SIZE(&inode)); + fprintf(ls->f, "\n"); + } else if (options & LONG_OPT) { + if (ino) { + if (debugfs_read_inode(ino, &inode, "ls")) + return 0; + modtime = inode.i_mtime; + tm_p = localtime(&modtime); + sprintf(datestr, "%2d-%s-%4d %02d:%02d", + tm_p->tm_mday, monstr[tm_p->tm_mon], + 1900 + tm_p->tm_year, tm_p->tm_hour, + tm_p->tm_min); + } else { + strcpy(datestr, " "); + memset(&inode, 0, sizeof(struct ext2_inode)); + } + fprintf(ls->f, "%c%6u%c %6o ", lbr, ino, rbr, inode.i_mode); + if (entry == DIRENT_CHECKSUM) { + fprintf(ls->f, "(dirblock checksum: 0x%08x)\n", + t->det_checksum); + return 0; + } + fprintf(ls->f, "(%d) %5d %5d ", + ext2fs_dirent_file_type(dirent), + inode_uid(inode), inode_gid(inode)); + fprintf(ls->f, "%5llu", + (unsigned long long) EXT2_I_SIZE(&inode)); + fprintf(ls->f, " %s ", datestr); + print_filename(ls->f, dirent, options); + fputc('\n', ls->f); + } else { + if (entry == DIRENT_CHECKSUM) { + sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x) ", + lbr, dirent->inode, rbr, t->det_checksum); + thislen = strlen(tmp); + if (ls->col + thislen > 80) { + fputc('\n', ls->f); + ls->col = 0; + } + fprintf(ls->f, "%s", tmp); + ls->col += thislen; + return 0; + } + sprintf(tmp, "%c%u%c (%d) ", lbr, dirent->inode, rbr, + dirent->rec_len); + thislen = strlen(tmp) + 3; + thislen += print_filename(NULL, dirent, options); + + if (ls->col + thislen > 80) { + fputc('\n', ls->f); + ls->col = 0; + } + fprintf(ls->f, "%s", tmp); + print_filename(ls->f, dirent, options); + fputs(" ", ls->f); + ls->col += thislen; + } + return 0; +} + +void do_list_dir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), + void *infop EXT2FS_ATTR((unused))) +{ + struct ext2_inode inode; + ext2_ino_t ino; + int retval; + int c; + int flags = DIRENT_FLAG_INCLUDE_EMPTY; + struct list_dir_struct ls; + + ls.options = 0; + ls.state = 0; + if (check_fs_open(argv[0])) + return; + + reset_getopt(); + while ((c = getopt (argc, argv, "cdlpr")) != EOF) { + switch (c) { + case 'c': + flags |= DIRENT_FLAG_INCLUDE_CSUM; + break; + case 'l': + ls.options |= LONG_OPT; + break; + case 'd': + flags |= DIRENT_FLAG_INCLUDE_REMOVED; + break; + case 'p': + ls.options |= PARSE_OPT; + break; + case 'r': + ls.options |= RAW_OPT; + break; + default: + goto print_usage; + } + } + + if (argc > optind+1) { + print_usage: + com_err(0, 0, "Usage: ls [-c] [-d] [-l] [-p] [-r] file"); + return; + } + + if (argc == optind) + ino = cwd; + else + ino = string_to_inode(argv[optind]); + if (!ino) + return; + + ls.f = open_pager(); + ls.col = 0; + + if (debugfs_read_inode(ino, &inode, argv[0])) + return; + + if (inode.i_flags & EXT4_ENCRYPT_FL) + ls.options |= ENCRYPT_OPT; + + retval = ext2fs_dir_iterate2(current_fs, ino, flags, + 0, list_dir_proc, &ls); + fprintf(ls.f, "\n"); + close_pager(ls.f); + if (retval) + com_err(argv[1], retval, 0); + + return; +} + + |