• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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