1e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/*
2e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * filefrag.c --- display the fragmentation information for a file
3e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
4e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Copyright (C) 2011 Theodore Ts'o.  This file may be redistributed
5e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * under the terms of the GNU Public License.
6e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall */
7e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
8e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <stdio.h>
9e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <unistd.h>
10e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <stdlib.h>
11e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <ctype.h>
12e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <string.h>
13e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <time.h>
14e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifdef HAVE_ERRNO_H
15e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <errno.h>
16e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
17e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <sys/types.h>
18e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <sys/stat.h>
19e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <fcntl.h>
20e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <utime.h>
21e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifdef HAVE_GETOPT_H
22e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <getopt.h>
23e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#else
24e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallextern int optind;
25e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallextern char *optarg;
26e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
27e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
28e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "debugfs.h"
29e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
30e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define VERBOSE_OPT	0x0001
31e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define DIR_OPT		0x0002
32e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define RECURSIVE_OPT	0x0004
33e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
34e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstruct dir_list {
35e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	char		*name;
36e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2_ino_t	ino;
37e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct dir_list	*next;
38e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall};
39e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
40e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstruct filefrag_struct {
41e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	FILE		*f;
42e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	const char	*name;
43e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	const char	*dir_name;
44e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		options;
45e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		logical_width;
46e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		physical_width;
47e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		ext;
48e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		cont_ext;
49e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	e2_blkcnt_t	num;
50e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	e2_blkcnt_t	logical_start;
51e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t		physical_start;
52e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t		expected;
53e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct dir_list *dir_list, *dir_last;
54e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall};
55e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
56e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int int_log10(unsigned long long arg)
57e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
58e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int     l = 0;
59e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
60e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	arg = arg / 10;
61e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	while (arg) {
62e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		l++;
63e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		arg = arg / 10;
64e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
65e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return l;
66e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
67e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
68e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void print_header(struct filefrag_struct *fs)
69e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
70e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs->options & VERBOSE_OPT) {
71e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fprintf(fs->f, "%4s %*s %*s %*s %*s\n", "ext",
72e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->logical_width, "logical", fs->physical_width,
73e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			"physical", fs->physical_width, "expected",
74e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->logical_width, "length");
75e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
76e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
77e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
78e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void report_filefrag(struct filefrag_struct *fs)
79e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
80e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs->num == 0)
81e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return;
82e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs->options & VERBOSE_OPT) {
83e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (fs->expected)
84e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fprintf(fs->f, "%4d %*lu %*llu %*llu %*lu\n", fs->ext,
85e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->logical_width,
86e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				(unsigned long) fs->logical_start,
87e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->physical_width, fs->physical_start,
88e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->physical_width, fs->expected,
89e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->logical_width, (unsigned long) fs->num);
90e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		else
91e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fprintf(fs->f, "%4d %*lu %*llu %*s %*lu\n", fs->ext,
92e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->logical_width,
93e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				(unsigned long) fs->logical_start,
94e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->physical_width, fs->physical_start,
95e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->physical_width, "",
96e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->logical_width, (unsigned long) fs->num);
97e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
98e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->ext++;
99e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
100e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
101e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int filefrag_blocks_proc(ext2_filsys ext4_fs EXT2FS_ATTR((unused)),
102e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				blk64_t *blocknr, e2_blkcnt_t blockcnt,
103e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				blk64_t ref_block EXT2FS_ATTR((unused)),
104e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				int ref_offset EXT2FS_ATTR((unused)),
105e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				void *private)
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
107e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct filefrag_struct *fs = private;
108e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
109e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (blockcnt < 0 || *blocknr == 0)
110e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
111e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
112e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((fs->num == 0) || (blockcnt != fs->logical_start + fs->num) ||
113e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    (*blocknr != fs->physical_start + fs->num)) {
114e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		report_filefrag(fs);
115e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (blockcnt == fs->logical_start + fs->num)
116e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->expected = fs->physical_start + fs->num;
117e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		else
118e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->expected = 0;
119e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->logical_start = blockcnt;
120e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->physical_start = *blocknr;
121e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->num = 1;
122e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->cont_ext++;
123e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	} else
124e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->num++;
125e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
126e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
127e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
128e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void filefrag(ext2_ino_t ino, struct ext2_inode *inode,
129e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		     struct filefrag_struct *fs)
130e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
131e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t	retval;
132e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		blocksize = current_fs->blocksize;
133e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
134e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->logical_width = int_log10((EXT2_I_SIZE(inode) + blocksize - 1) /
135e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				      blocksize) + 1;
136e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs->logical_width < 7)
137e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->logical_width = 7;
138e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->ext = 0;
139e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->cont_ext = 0;
140e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->logical_start = 0;
141e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->physical_start = 0;
142e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->num = 0;
143e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
144e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs->options & VERBOSE_OPT) {
145e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		blk64_t num_blocks = ext2fs_inode_i_blocks(current_fs, inode);
146e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
147e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (!(current_fs->super->s_feature_ro_compat &
148e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		     EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
149e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		    !(inode->i_flags & EXT4_HUGE_FILE_FL))
150e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			num_blocks /= current_fs->blocksize / 512;
151e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
152e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fprintf(fs->f, "\n%s has %llu block(s), i_size is %llu\n",
153e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->name, num_blocks, EXT2_I_SIZE(inode));
154e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
155e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	print_header(fs);
156e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_block_iterate3(current_fs, ino,
157e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				       BLOCK_FLAG_READ_ONLY, NULL,
158e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				       filefrag_blocks_proc, fs);
159e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval)
160e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err("ext2fs_block_iterate3", retval, 0);
161e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
162e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	report_filefrag(fs);
163e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fprintf(fs->f, "%s: %d contiguous extents%s\n", fs->name, fs->ext,
164e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		LINUX_S_ISDIR(inode->i_mode) ? " (dir)" : "");
165e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
166e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
167e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int filefrag_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
168e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     int	entry,
169e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     struct ext2_dir_entry *dirent,
170e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     int	offset EXT2FS_ATTR((unused)),
171e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     int	blocksize EXT2FS_ATTR((unused)),
172e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     char	*buf EXT2FS_ATTR((unused)),
173e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     void	*private)
174e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
175e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct filefrag_struct *fs = private;
176e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct ext2_inode	inode;
177e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2_ino_t		ino;
178e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	char			name[EXT2_NAME_LEN + 1];
179e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	char			*cp;
180e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int			thislen;
181e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
182e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (entry == DIRENT_DELETED_FILE)
183e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
184e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
185e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	thislen = dirent->name_len & 0xFF;
186e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	strncpy(name, dirent->name, thislen);
187e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	name[thislen] = '\0';
188e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ino = dirent->inode;
189e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
190e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!strcmp(name, ".") || !strcmp(name, ".."))
191e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
192e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
193e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	cp = malloc(strlen(fs->dir_name) + strlen(name) + 2);
194e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!cp) {
195e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fprintf(stderr, "Couldn't allocate memory for %s/%s\n",
196e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->dir_name, name);
197e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
198e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
199e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
200e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	sprintf(cp, "%s/%s", fs->dir_name, name);
201e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->name = cp;
202e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
203e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (debugfs_read_inode(ino, &inode, fs->name))
204e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto errout;
205e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
206e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	filefrag(ino, &inode, fs);
207e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
208e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((fs->options & RECURSIVE_OPT) && LINUX_S_ISDIR(inode.i_mode)) {
209e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		struct dir_list *p;
210e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
211e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		p = malloc(sizeof(struct dir_list));
212e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (!p) {
213e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fprintf(stderr, "Couldn't allocate dir_list for %s\n",
214e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->name);
215e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto errout;
216e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
217e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		memset(p, 0, sizeof(struct dir_list));
218e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		p->name = cp;
219e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		p->ino = ino;
220e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (fs->dir_last)
221e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->dir_last->next = p;
222e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		else
223e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->dir_list = p;
224e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->dir_last = p;
225e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
226e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
227e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallerrout:
228e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	free(cp);
229e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->name = 0;
230e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
231e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
232e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
233e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
234e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void dir_iterate(ext2_ino_t ino, struct filefrag_struct *fs)
235e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
236e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t	retval;
237e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct dir_list	*p = NULL;
238e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
239e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs->dir_name = fs->name;
240e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
241e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	while (1) {
242e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_dir_iterate2(current_fs, ino, 0,
243e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall					     0, filefrag_dir_proc, fs);
244e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
245e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			com_err("ext2fs_dir_iterate2", retval, 0);
246e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (p) {
247e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			free(p->name);
248e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs->dir_list = p->next;
249e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (!fs->dir_list)
250e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				fs->dir_last = 0;
251e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			free(p);
252e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
253e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		p = fs->dir_list;
254e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (!p)
255e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
256e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ino = p->ino;
257e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs->dir_name = p->name;
258e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
259e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
260e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
261e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallvoid do_filefrag(int argc, char *argv[])
262e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
263e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct filefrag_struct fs;
264e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct ext2_inode inode;
265e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2_ino_t	ino;
266e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		c;
267e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
268e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	memset(&fs, 0, sizeof(fs));
269e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (check_fs_open(argv[0]))
270e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return;
271e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
272e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	reset_getopt();
273e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	while ((c = getopt(argc, argv, "dvr")) != EOF) {
274e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		switch (c) {
275e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		case 'd':
276e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs.options |= DIR_OPT;
277e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
278e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		case 'v':
279e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs.options |= VERBOSE_OPT;
280e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
281e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		case 'r':
282e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			fs.options |= RECURSIVE_OPT;
283e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
284e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		default:
285e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto print_usage;
286e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
287e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
288e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
289e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (argc > optind+1) {
290e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	print_usage:
291e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		com_err(0, 0, "Usage: filefrag [-dvr] file");
292e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return;
293e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
294e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
295e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (argc == optind) {
296e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ino = cwd;
297e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs.name = ".";
298e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	} else {
299e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ino = string_to_inode(argv[optind]);
300e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs.name = argv[optind];
301e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
302e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!ino)
303e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return;
304e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
305e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (debugfs_read_inode(ino, &inode, argv[0]))
306e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return;
307e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
308e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs.f = open_pager();
309e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs.physical_width = int_log10(ext2fs_blocks_count(current_fs->super));
310e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fs.physical_width++;
311e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (fs.physical_width < 8)
312e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		fs.physical_width = 8;
313e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
314e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!LINUX_S_ISDIR(inode.i_mode) || (fs.options & DIR_OPT))
315e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		filefrag(ino, &inode, &fs);
316e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	else
317e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		dir_iterate(ino, &fs);
318e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
319e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fprintf(fs.f, "\n");
320e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	close_pager(fs.f);
321e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
322e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return;
323e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
324