1 #include "fsmap.h"
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include "support/nls-enable.h"
7
8 struct walk_ext_priv_data {
9 char *path;
10 ext2_filsys fs;
11 struct fsmap_format *format;
12 };
13
walk_block(ext2_filsys fs EXT2FS_ATTR ((unused)),blk64_t * blocknr,e2_blkcnt_t blockcnt,blk64_t ref64_blk EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv)14 static int walk_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t *blocknr,
15 e2_blkcnt_t blockcnt,
16 blk64_t ref64_blk EXT2FS_ATTR((unused)),
17 int ref_offset EXT2FS_ATTR((unused)),
18 void *priv)
19 {
20 struct walk_ext_priv_data *pdata = priv;
21 struct fsmap_format *format = pdata->format;
22
23 return format->add_block(fs, *blocknr, blockcnt < 0, format->private);
24 }
25
ino_iter_extents(ext2_filsys fs,ext2_ino_t ino,ext2_extent_handle_t extents,struct walk_ext_priv_data * pdata)26 static errcode_t ino_iter_extents(ext2_filsys fs, ext2_ino_t ino,
27 ext2_extent_handle_t extents,
28 struct walk_ext_priv_data *pdata)
29 {
30 blk64_t block;
31 errcode_t retval;
32 blk64_t next_lblk = 0;
33 int op = EXT2_EXTENT_ROOT;
34 struct ext2fs_extent extent;
35 struct fsmap_format *format = pdata->format;
36
37 for (;;) {
38 retval = ext2fs_extent_get(extents, op, &extent);
39 if (retval)
40 break;
41
42 op = EXT2_EXTENT_NEXT;
43
44 if ((extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) ||
45 !(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF))
46 continue;
47
48 for (; next_lblk < extent.e_lblk; next_lblk++)
49 format->add_block(fs, 0, 0, format->private);
50
51 block = extent.e_pblk;
52 for (; next_lblk < extent.e_lblk + extent.e_len; next_lblk++)
53 format->add_block(fs, block++, 0, format->private);
54 }
55
56 if (retval == EXT2_ET_EXTENT_NO_NEXT)
57 retval = 0;
58 if (retval) {
59 com_err(__func__, retval, ("getting extents of ino \"%u\""),
60 ino);
61 }
62 return retval;
63 }
64
ino_iter_blocks(ext2_filsys fs,ext2_ino_t ino,struct walk_ext_priv_data * pdata)65 static errcode_t ino_iter_blocks(ext2_filsys fs, ext2_ino_t ino,
66 struct walk_ext_priv_data *pdata)
67 {
68 errcode_t retval;
69 struct ext2_inode inode;
70 ext2_extent_handle_t extents;
71 struct fsmap_format *format = pdata->format;
72
73 retval = ext2fs_read_inode(fs, ino, &inode);
74 if (retval)
75 return retval;
76
77 if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
78 return format->inline_data(&(inode.i_block[0]),
79 format->private);
80
81 retval = ext2fs_extent_open(fs, ino, &extents);
82 if (retval == EXT2_ET_INODE_NOT_EXTENT) {
83 retval = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
84 NULL, walk_block, pdata);
85 if (retval) {
86 com_err(__func__, retval, _("listing blocks of ino \"%u\""),
87 ino);
88 }
89 return retval;
90 }
91
92 retval = ino_iter_extents(fs, ino, extents, pdata);
93
94 ext2fs_extent_free(extents);
95 return retval;
96 }
97
is_dir(ext2_filsys fs,ext2_ino_t ino)98 static int is_dir(ext2_filsys fs, ext2_ino_t ino)
99 {
100 struct ext2_inode inode;
101
102 if (ext2fs_read_inode(fs, ino, &inode))
103 return 0;
104 return S_ISDIR(inode.i_mode);
105 }
106
walk_ext_dir(ext2_ino_t dir EXT2FS_ATTR ((unused)),int flags EXT2FS_ATTR ((unused)),struct ext2_dir_entry * de,int offset EXT2FS_ATTR ((unused)),int blocksize EXT2FS_ATTR ((unused)),char * buf EXT2FS_ATTR ((unused)),void * priv_data)107 static int walk_ext_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
108 int flags EXT2FS_ATTR((unused)),
109 struct ext2_dir_entry *de,
110 int offset EXT2FS_ATTR((unused)),
111 int blocksize EXT2FS_ATTR((unused)),
112 char *buf EXT2FS_ATTR((unused)), void *priv_data)
113 {
114 errcode_t retval;
115 struct ext2_inode inode;
116 char *filename, *cur_path, *name = de->name;
117 int name_len = de->name_len & 0xff;
118 struct walk_ext_priv_data *pdata = priv_data;
119 struct fsmap_format *format = pdata->format;
120
121 if (!strncmp(name, ".", name_len)
122 || !strncmp(name, "..", name_len)
123 || !strncmp(name, "lost+found", 10))
124 return 0;
125
126 if (asprintf(&filename, "%s/%.*s", pdata->path, name_len, name) < 0)
127 return -ENOMEM;
128
129 retval = ext2fs_read_inode(pdata->fs, de->inode, &inode);
130 if (retval) {
131 com_err(__func__, retval, _("reading ino \"%u\""), de->inode);
132 goto end;
133 }
134 format->start_new_file(filename, de->inode, &inode, format->private);
135 retval = ino_iter_blocks(pdata->fs, de->inode, pdata);
136 if (retval)
137 return retval;
138 format->end_new_file(format->private);
139
140 retval = 0;
141 if (is_dir(pdata->fs, de->inode)) {
142 cur_path = pdata->path;
143 pdata->path = filename;
144 retval = ext2fs_dir_iterate2(pdata->fs, de->inode, 0, NULL,
145 walk_ext_dir, pdata);
146 pdata->path = cur_path;
147 }
148
149 end:
150 free(filename);
151 return retval;
152 }
153
fsmap_iter_filsys(ext2_filsys fs,struct fsmap_format * format,const char * file,const char * mountpoint)154 errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format,
155 const char *file, const char *mountpoint)
156 {
157 struct walk_ext_priv_data pdata;
158 errcode_t retval;
159
160 format->private = format->init(file, mountpoint);
161 pdata.fs = fs;
162 pdata.path = "";
163 pdata.format = format;
164
165 retval = ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_ext_dir, &pdata);
166
167 format->cleanup(format->private);
168 return retval;
169 }
170