1 /*
2 * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write the Free Software Foundation,
15 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #include <cache.h>
19 #include <core.h>
20 #include <fs.h>
21
22 #include "xfs_types.h"
23 #include "xfs_sb.h"
24 #include "xfs_ag.h"
25 #include "misc.h"
26 #include "xfs.h"
27 #include "xfs_dinode.h"
28 #include "xfs_dir2.h"
29
30 #include "xfs_readdir.h"
31
fill_dirent(struct fs_info * fs,struct dirent * dirent,uint32_t offset,xfs_ino_t ino,char * name,size_t namelen)32 static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
33 uint32_t offset, xfs_ino_t ino, char *name,
34 size_t namelen)
35 {
36 xfs_dinode_t *core;
37
38 xfs_debug("fs %p, dirent %p offset %lu ino %llu name %s namelen %llu", fs,
39 dirent, offset, ino, name, namelen);
40
41 dirent->d_ino = ino;
42 dirent->d_off = offset;
43 dirent->d_reclen = offsetof(struct dirent, d_name) + namelen + 1;
44
45 core = xfs_dinode_get_core(fs, ino);
46 if (!core) {
47 xfs_error("Failed to get dinode from disk (ino 0x%llx)", ino);
48 return -1;
49 }
50
51 if (be16_to_cpu(core->di_mode) & S_IFDIR)
52 dirent->d_type = DT_DIR;
53 else if (be16_to_cpu(core->di_mode) & S_IFREG)
54 dirent->d_type = DT_REG;
55 else if (be16_to_cpu(core->di_mode) & S_IFLNK)
56 dirent->d_type = DT_LNK;
57
58 memcpy(dirent->d_name, name, namelen);
59 dirent->d_name[namelen] = '\0';
60
61 return 0;
62 }
63
xfs_readdir_dir2_local(struct file * file,struct dirent * dirent,xfs_dinode_t * core)64 int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
65 xfs_dinode_t *core)
66 {
67 xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
68 xfs_dir2_sf_entry_t *sf_entry;
69 uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
70 uint32_t offset = file->offset;
71 uint8_t *start_name;
72 uint8_t *end_name;
73 xfs_ino_t ino;
74 struct fs_info *fs = file->fs;
75 int retval = 0;
76
77 xfs_debug("file %p dirent %p core %p", file, dirent, core);
78 xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
79
80 if (file->offset + 1 > count)
81 goto out;
82
83 file->offset++;
84
85 sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
86 (!sf->hdr.i8count ? 4 : 0));
87
88 if (file->offset - 1) {
89 offset = file->offset;
90 while (--offset) {
91 sf_entry = (xfs_dir2_sf_entry_t *)(
92 (uint8_t *)sf_entry +
93 offsetof(struct xfs_dir2_sf_entry,
94 name[0]) +
95 sf_entry->namelen +
96 (sf->hdr.i8count ? 8 : 4));
97 }
98 }
99
100 start_name = &sf_entry->name[0];
101 end_name = start_name + sf_entry->namelen;
102
103 ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
104 (uint8_t *)sf_entry +
105 offsetof(struct xfs_dir2_sf_entry,
106 name[0]) +
107 sf_entry->namelen));
108
109 retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
110 end_name - start_name);
111 if (retval)
112 xfs_error("Failed to fill in dirent structure");
113
114 return retval;
115
116 out:
117 xfs_dir2_dirblks_flush_cache();
118
119 return -1;
120 }
121
xfs_readdir_dir2_block(struct file * file,struct dirent * dirent,xfs_dinode_t * core)122 int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
123 xfs_dinode_t *core)
124 {
125 xfs_bmbt_irec_t r;
126 block_t dir_blk;
127 struct fs_info *fs = file->fs;
128 const uint8_t *dirblk_buf;
129 uint8_t *p;
130 uint32_t offset;
131 xfs_dir2_data_hdr_t *hdr;
132 xfs_dir2_block_tail_t *btp;
133 xfs_dir2_data_unused_t *dup;
134 xfs_dir2_data_entry_t *dep;
135 uint8_t *start_name;
136 uint8_t *end_name;
137 xfs_ino_t ino;
138 int retval = 0;
139
140 xfs_debug("file %p dirent %p core %p", file, dirent, core);
141
142 bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
143 dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
144
145 dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount);
146 hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
147 if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
148 xfs_error("Block directory header's magic number does not match!");
149 xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
150 goto out;
151 }
152
153 btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
154
155 if (file->offset + 1 > be32_to_cpu(btp->count))
156 goto out;
157
158 file->offset++;
159
160 p = (uint8_t *)(hdr + 1);
161
162 if (file->offset - 1) {
163 offset = file->offset;
164 while (--offset) {
165 dep = (xfs_dir2_data_entry_t *)p;
166
167 dup = (xfs_dir2_data_unused_t *)p;
168 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
169 p += be16_to_cpu(dup->length);
170 continue;
171 }
172
173 p += xfs_dir2_data_entsize(dep->namelen);
174 }
175 }
176
177 dep = (xfs_dir2_data_entry_t *)p;
178
179 start_name = &dep->name[0];
180 end_name = start_name + dep->namelen;
181
182 ino = be64_to_cpu(dep->inumber);
183
184 retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
185 end_name - start_name);
186 if (retval)
187 xfs_error("Failed to fill in dirent structure");
188
189 return retval;
190
191 out:
192 xfs_dir2_dirblks_flush_cache();
193
194 return -1;
195 }
196
xfs_readdir_dir2_leaf(struct file * file,struct dirent * dirent,xfs_dinode_t * core)197 int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
198 xfs_dinode_t *core)
199 {
200 xfs_bmbt_irec_t irec;
201 struct fs_info *fs = file->fs;
202 xfs_dir2_leaf_t *leaf;
203 block_t leaf_blk, dir_blk;
204 xfs_dir2_leaf_entry_t *lep;
205 uint32_t db;
206 unsigned int offset;
207 xfs_dir2_data_entry_t *dep;
208 xfs_dir2_data_hdr_t *data_hdr;
209 uint8_t *start_name;
210 uint8_t *end_name;
211 xfs_intino_t ino;
212 const uint8_t *buf = NULL;
213 int retval = 0;
214
215 xfs_debug("file %p dirent %p core %p", file, dirent, core);
216
217 bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
218 be32_to_cpu(core->di_nextents) - 1);
219 leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
220 BLOCK_SHIFT(file->fs);
221
222 leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(fs, leaf_blk,
223 irec.br_blockcount);
224 if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
225 xfs_error("Single leaf block header's magic number does not match!");
226 goto out;
227 }
228
229 if (!leaf->hdr.count)
230 goto out;
231
232 if (file->offset + 1 > be16_to_cpu(leaf->hdr.count))
233 goto out;
234
235 lep = &leaf->ents[file->offset++];
236
237 /* Skip over stale leaf entries */
238 for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
239 lep++, file->offset++);
240
241 db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
242
243 bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + db);
244
245 dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
246
247 buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, irec.br_blockcount);
248 data_hdr = (xfs_dir2_data_hdr_t *)buf;
249 if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
250 xfs_error("Leaf directory's data magic number does not match!");
251 goto out;
252 }
253
254 offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
255
256 dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
257
258 start_name = &dep->name[0];
259 end_name = start_name + dep->namelen;
260
261 ino = be64_to_cpu(dep->inumber);
262
263 retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
264 end_name - start_name);
265 if (retval)
266 xfs_error("Failed to fill in dirent structure");
267
268 return retval;
269
270 out:
271 xfs_dir2_dirblks_flush_cache();
272
273 return -1;
274 }
275
xfs_readdir_dir2_node(struct file * file,struct dirent * dirent,xfs_dinode_t * core)276 int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
277 xfs_dinode_t *core)
278 {
279 struct fs_info *fs = file->fs;
280 xfs_bmbt_irec_t irec;
281 uint32_t node_off = 0;
282 block_t fsblkno;
283 xfs_da_intnode_t *node = NULL;
284 struct inode *inode = file->inode;
285 int error;
286 xfs_dir2_data_hdr_t *data_hdr;
287 xfs_dir2_leaf_t *leaf;
288 xfs_dir2_leaf_entry_t *lep;
289 unsigned int offset;
290 xfs_dir2_data_entry_t *dep;
291 uint8_t *start_name;
292 uint8_t *end_name;
293 uint32_t db;
294 const uint8_t *buf = NULL;
295 int retval = 0;
296
297 xfs_debug("file %p dirent %p core %p", file, dirent, core);
298
299 do {
300 bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
301 ++node_off);
302 } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET));
303
304 fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
305
306 node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
307 if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
308 xfs_error("Node's magic number does not match!");
309 goto out;
310 }
311
312 try_next_btree:
313 if (!node->hdr.count ||
314 XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
315 goto out;
316
317 fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
318 fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
319 if (error) {
320 xfs_error("Cannot find leaf rec!");
321 goto out;
322 }
323
324 leaf = (xfs_dir2_leaf_t*)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
325 if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
326 xfs_error("Leaf's magic number does not match!");
327 goto out;
328 }
329
330 if (!leaf->hdr.count ||
331 XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
332 XFS_PVT(inode)->i_btree_offset++;
333 XFS_PVT(inode)->i_leaf_ent_offset = 0;
334 goto try_next_btree;
335 }
336
337 lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset];
338
339 /* Skip over stale leaf entries */
340 for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) &&
341 be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
342 lep++, XFS_PVT(inode)->i_leaf_ent_offset++);
343
344 if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) {
345 XFS_PVT(inode)->i_btree_offset++;
346 XFS_PVT(inode)->i_leaf_ent_offset = 0;
347 goto try_next_btree;
348 } else {
349 XFS_PVT(inode)->i_leaf_ent_offset++;
350 }
351
352 db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
353
354 fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
355 if (error) {
356 xfs_error("Cannot find data block!");
357 goto out;
358 }
359
360 buf = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
361 data_hdr = (xfs_dir2_data_hdr_t *)buf;
362 if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
363 xfs_error("Leaf directory's data magic No. does not match!");
364 goto out;
365 }
366
367 offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
368
369 dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
370
371 start_name = &dep->name[0];
372 end_name = start_name + dep->namelen;
373
374 retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber),
375 (char *)start_name, end_name - start_name);
376 if (retval)
377 xfs_error("Failed to fill in dirent structure");
378
379 return retval;
380
381 out:
382 xfs_dir2_dirblks_flush_cache();
383
384 XFS_PVT(inode)->i_btree_offset = 0;
385 XFS_PVT(inode)->i_leaf_ent_offset = 0;
386
387 return -1;
388 }
389