ls.c revision fa7c30276c2b3ff06ddfa6ac0067a753bfbe0d21
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 <stdio.h>
9#include <unistd.h>
10#include <stdlib.h>
11#include <ctype.h>
12#include <string.h>
13#include <time.h>
14#ifdef HAVE_ERRNO_H
15#include <errno.h>
16#endif
17#include <sys/types.h>
18#ifdef HAVE_GETOPT_H
19#include <getopt.h>
20#else
21extern int optind;
22extern char *optarg;
23#endif
24#ifdef HAVE_OPTRESET
25extern int optreset;		/* defined by BSD, but not others */
26#endif
27
28#include "debugfs.h"
29
30/*
31 * list directory
32 */
33
34#define LONG_OPT	0x0001
35#define DELETED_OPT	0x0002
36
37struct list_dir_struct {
38	FILE	*f;
39	int	col;
40	int	options;
41};
42
43static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
44				"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
45
46static int list_dir_proc(ext2_ino_t dir,
47			 int	entry,
48			 struct ext2_dir_entry *dirent,
49			 int	offset,
50			 int	blocksize,
51			 char	*buf,
52			 void	*private)
53{
54	struct ext2_dir_entry_2	*d2;
55	struct ext2_inode	inode;
56	ext2_ino_t		ino;
57	struct tm		*tm_p;
58	time_t			modtime;
59	char			name[EXT2_NAME_LEN];
60	char			tmp[EXT2_NAME_LEN + 16];
61	char			datestr[80];
62	char			lbr, rbr;
63	int			thislen;
64	struct list_dir_struct *ls = (struct list_dir_struct *) private;
65
66	thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN) ?
67		(dirent->name_len & 0xFF) : EXT2_NAME_LEN;
68	strncpy(name, dirent->name, thislen);
69	name[thislen] = '\0';
70	ino = dirent->inode;
71
72	if (entry == DIRENT_DELETED_FILE) {
73		lbr = '<';
74		rbr = '>';
75		ino = 0;
76	} else {
77		lbr = rbr = ' ';
78	}
79	if (ls->options & LONG_OPT) {
80		if (ino) {
81			if (debugfs_read_inode(ino, &inode, name))
82				return 0;
83			modtime = inode.i_mtime;
84			tm_p = localtime(&modtime);
85			sprintf(datestr, "%2d-%s-%4d %02d:%02d",
86				tm_p->tm_mday, monstr[tm_p->tm_mon],
87				1900 + tm_p->tm_year, tm_p->tm_hour,
88				tm_p->tm_min);
89		} else {
90			strcpy(datestr, "                 ");
91			memset(&inode, 0, sizeof(struct ext2_inode));
92		}
93		d2 = (struct dir_entry_2 *) dirent;
94		fprintf(ls->f, "%c%6u%c %6o (%d)  %5d  %5d   ", lbr, ino, rbr,
95			inode.i_mode, d2->file_type, inode.i_uid, inode.i_gid);
96		if (LINUX_S_ISDIR(inode.i_mode))
97			fprintf(ls->f, "%5d", inode.i_size);
98		else
99			fprintf(ls->f, "%5lld", inode.i_size |
100				((__u64)inode.i_size_high << 32));
101		fprintf (ls->f, " %s %s\n", datestr, name);
102	} else {
103		sprintf(tmp, "%c%u%c (%d) %s   ", lbr, dirent->inode, rbr,
104			dirent->rec_len, name);
105		thislen = strlen(tmp);
106
107		if (ls->col + thislen > 80) {
108			fprintf(ls->f, "\n");
109			ls->col = 0;
110		}
111		fprintf(ls->f, "%s", tmp);
112		ls->col += thislen;
113	}
114	return 0;
115}
116
117void do_list_dir(int argc, char *argv[])
118{
119	ext2_ino_t	inode;
120	int		retval;
121	int		c;
122	int		flags;
123	struct list_dir_struct ls;
124
125	ls.options = 0;
126	if (check_fs_open(argv[0]))
127		return;
128
129	optind = 0;
130#ifdef HAVE_OPTRESET
131	optreset = 1;		/* Makes BSD getopt happy */
132#endif
133	while ((c = getopt (argc, argv, "dl")) != EOF) {
134		switch (c) {
135		case 'l':
136			ls.options |= LONG_OPT;
137			break;
138		case 'd':
139			ls.options |= DELETED_OPT;
140			break;
141		}
142	}
143
144	if (argc > optind+1) {
145		com_err(0, 0, "Usage: ls [-l] [-d] file");
146		return;
147	}
148
149	if (argc == optind)
150		inode = cwd;
151	else
152		inode = string_to_inode(argv[optind]);
153	if (!inode)
154		return;
155
156	ls.f = open_pager();
157	ls.col = 0;
158	flags = DIRENT_FLAG_INCLUDE_EMPTY;
159	if (ls.options & DELETED_OPT)
160		flags |= DIRENT_FLAG_INCLUDE_REMOVED;
161
162	retval = ext2fs_dir_iterate2(current_fs, inode, flags,
163				    0, list_dir_proc, &ls);
164	fprintf(ls.f, "\n");
165	close_pager(ls.f);
166	if (retval)
167		com_err(argv[1], retval, "");
168
169	return;
170}
171
172
173