]> code.delx.au - refind/blob - filesystems/fsw_reiserfs.c
Sort Fedora's rescue kernel (vmlinuz-0-rescue*) to the end of the list
[refind] / filesystems / fsw_reiserfs.c
1 /**
2 * \file fsw_reiserfs.c
3 * ReiserFS file system driver code.
4 */
5
6 /*-
7 * Copyright (c) 2006 Christoph Pfisterer
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #include "fsw_reiserfs.h"
25
26
27 // functions
28
29 static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol);
30 static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol);
31 static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb);
32
33 static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
34 static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
35 static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
36 struct fsw_dnode_stat *sb);
37 static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
38 struct fsw_extent *extent);
39
40 static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
41 struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno);
42 static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
43 struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno);
44
45 static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
46 struct fsw_string *link);
47
48 static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
49 fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
50 struct fsw_reiserfs_item *item);
51 static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
52 struct fsw_reiserfs_item *item);
53 static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
54 struct fsw_reiserfs_item *item);
55
56 //
57 // Dispatch Table
58 //
59
60 struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs) = {
61 { FSW_STRING_TYPE_ISO88591, 8, 8, "reiserfs" },
62 sizeof(struct fsw_reiserfs_volume),
63 sizeof(struct fsw_reiserfs_dnode),
64
65 fsw_reiserfs_volume_mount,
66 fsw_reiserfs_volume_free,
67 fsw_reiserfs_volume_stat,
68 fsw_reiserfs_dnode_fill,
69 fsw_reiserfs_dnode_free,
70 fsw_reiserfs_dnode_stat,
71 fsw_reiserfs_get_extent,
72 fsw_reiserfs_dir_lookup,
73 fsw_reiserfs_dir_read,
74 fsw_reiserfs_readlink,
75 };
76
77 // misc data
78
79 static fsw_u32 superblock_offsets[3] = {
80 REISERFS_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
81 REISERFS_OLD_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
82 0
83 };
84
85 /**
86 * Mount an reiserfs volume. Reads the superblock and constructs the
87 * root directory dnode.
88 */
89
90 static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol)
91 {
92 fsw_status_t status;
93 void *buffer;
94 fsw_u32 blocksize;
95 int i;
96 struct fsw_string s;
97
98 // allocate memory to keep the superblock around
99 status = fsw_alloc(sizeof(struct reiserfs_super_block), &vol->sb);
100 if (status)
101 return status;
102
103 // read the superblock into its buffer
104 fsw_set_blocksize(vol, REISERFS_SUPERBLOCK_BLOCKSIZE, REISERFS_SUPERBLOCK_BLOCKSIZE);
105 for (i = 0; superblock_offsets[i]; i++) {
106 status = fsw_block_get(vol, superblock_offsets[i], 0, &buffer);
107 if (status)
108 return status;
109 fsw_memcpy(vol->sb, buffer, sizeof(struct reiserfs_super_block));
110 fsw_block_release(vol, superblock_offsets[i], buffer);
111
112 // check for one of the magic strings
113 if (fsw_memeq(vol->sb->s_v1.s_magic,
114 REISERFS_SUPER_MAGIC_STRING, 8)) {
115 vol->version = REISERFS_VERSION_1;
116 break;
117 } else if (fsw_memeq(vol->sb->s_v1.s_magic,
118 REISER2FS_SUPER_MAGIC_STRING, 9)) {
119 vol->version = REISERFS_VERSION_2;
120 break;
121 } else if (fsw_memeq(vol->sb->s_v1.s_magic,
122 REISER2FS_JR_SUPER_MAGIC_STRING, 9)) {
123 vol->version = vol->sb->s_v1.s_version;
124 if (vol->version == REISERFS_VERSION_1 || vol->version == REISERFS_VERSION_2)
125 break;
126 }
127 }
128 if (superblock_offsets[i] == 0)
129 return FSW_UNSUPPORTED;
130
131 // check the superblock
132 if (vol->sb->s_v1.s_root_block == -1) // unfinished 'reiserfsck --rebuild-tree'
133 return FSW_VOLUME_CORRUPTED;
134
135 /*
136 if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
137 vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
138 return FSW_UNSUPPORTED;
139 if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
140 (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
141 return FSW_UNSUPPORTED;
142 */
143
144 // set real blocksize
145 blocksize = vol->sb->s_v1.s_blocksize;
146 fsw_set_blocksize(vol, blocksize, blocksize);
147
148 // get other info from superblock
149 /*
150 vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
151 vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
152 vol->inode_size = EXT2_INODE_SIZE(vol->sb);
153 */
154
155 for (i = 0; i < 16; i++)
156 if (vol->sb->s_label[i] == 0)
157 break;
158 s.type = FSW_STRING_TYPE_ISO88591;
159 s.size = s.len = i;
160 s.data = vol->sb->s_label;
161 status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
162 if (status)
163 return status;
164
165 // setup the root dnode
166 status = fsw_dnode_create_root(vol, REISERFS_ROOT_OBJECTID, &vol->g.root);
167 if (status)
168 return status;
169 vol->g.root->dir_id = REISERFS_ROOT_PARENT_OBJECTID;
170
171 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_volume_mount: success, blocksize %d tree height %d\n"),
172 blocksize, vol->sb->s_v1.s_tree_height));
173
174 return FSW_SUCCESS;
175 }
176
177 /**
178 * Free the volume data structure. Called by the core after an unmount or after
179 * an unsuccessful mount to release the memory used by the file system type specific
180 * part of the volume structure.
181 */
182
183 static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol)
184 {
185 if (vol->sb)
186 fsw_free(vol->sb);
187 }
188
189 /**
190 * Get in-depth information on a volume.
191 */
192
193 static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb)
194 {
195 sb->total_bytes = (fsw_u64)vol->sb->s_v1.s_block_count * vol->g.log_blocksize;
196 sb->free_bytes = (fsw_u64)vol->sb->s_v1.s_free_blocks * vol->g.log_blocksize;
197 return FSW_SUCCESS;
198 }
199
200 /**
201 * Get full information on a dnode from disk. This function is called by the core
202 * whenever it needs to access fields in the dnode structure that may not
203 * be filled immediately upon creation of the dnode. In the case of reiserfs, we
204 * delay fetching of the stat data until dnode_fill is called. The size and
205 * type fields are invalid until this function has been called.
206 */
207
208 static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
209 {
210 fsw_status_t status;
211 fsw_u32 item_len, mode;
212 struct fsw_reiserfs_item item;
213
214 if (dno->sd_v1 || dno->sd_v2)
215 return FSW_SUCCESS;
216
217 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_dnode_fill: object %d/%d\n"), dno->dir_id, dno->g.dnode_id));
218
219 // find stat data item in reiserfs tree
220 status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, 0, &item);
221 if (status == FSW_NOT_FOUND) {
222 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: cannot find stat_data for object %d/%d\n"),
223 dno->dir_id, dno->g.dnode_id));
224 return FSW_VOLUME_CORRUPTED;
225 }
226 if (status)
227 return status;
228 if (item.item_offset != 0) {
229 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: got item that's not stat_data\n")));
230 fsw_reiserfs_item_release(vol, &item);
231 return FSW_VOLUME_CORRUPTED;
232 }
233 item_len = item.ih.ih_item_len;
234
235 // get data in appropriate version
236 if (item.ih.ih_version == KEY_FORMAT_3_5 && item_len == SD_V1_SIZE) {
237 // have stat_data_v1 structure
238 status = fsw_memdup((void **)&dno->sd_v1, item.item_data, item_len);
239 fsw_reiserfs_item_release(vol, &item);
240 if (status)
241 return status;
242
243 // get info from the inode
244 dno->g.size = dno->sd_v1->sd_size;
245 mode = dno->sd_v1->sd_mode;
246
247 } else if (item.ih.ih_version == KEY_FORMAT_3_6 && item_len == SD_V2_SIZE) {
248 // have stat_data_v2 structure
249 status = fsw_memdup((void **)&dno->sd_v2, item.item_data, item_len);
250 fsw_reiserfs_item_release(vol, &item);
251 if (status)
252 return status;
253
254 // get info from the inode
255 dno->g.size = dno->sd_v2->sd_size;
256 mode = dno->sd_v2->sd_mode;
257
258 } else {
259 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: version %d(%d) and size %d(%d) not recognized for stat_data\n"),
260 item.ih.ih_version, KEY_FORMAT_3_6, item_len, SD_V2_SIZE));
261 fsw_reiserfs_item_release(vol, &item);
262 return FSW_VOLUME_CORRUPTED;
263 }
264
265 // get node type from mode field
266 if (S_ISREG(mode))
267 dno->g.type = FSW_DNODE_TYPE_FILE;
268 else if (S_ISDIR(mode))
269 dno->g.type = FSW_DNODE_TYPE_DIR;
270 else if (S_ISLNK(mode))
271 dno->g.type = FSW_DNODE_TYPE_SYMLINK;
272 else
273 dno->g.type = FSW_DNODE_TYPE_SPECIAL;
274
275 return FSW_SUCCESS;
276 }
277
278 /**
279 * Free the dnode data structure. Called by the core when deallocating a dnode
280 * structure to release the memory used by the file system type specific part
281 * of the dnode structure.
282 */
283
284 static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
285 {
286 if (dno->sd_v1)
287 fsw_free(dno->sd_v1);
288 if (dno->sd_v2)
289 fsw_free(dno->sd_v2);
290 }
291
292 /**
293 * Get in-depth information on a dnode. The core makes sure that fsw_reiserfs_dnode_fill
294 * has been called on the dnode before this function is called. Note that some
295 * data is not directly stored into the structure, but passed to a host-specific
296 * callback that converts it to the host-specific format.
297 */
298
299 static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
300 struct fsw_dnode_stat *sb)
301 {
302 if (dno->sd_v1) {
303 if (dno->g.type == FSW_DNODE_TYPE_SPECIAL)
304 sb->used_bytes = 0;
305 else
306 sb->used_bytes = dno->sd_v1->u.sd_blocks * vol->g.log_blocksize;
307 fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime);
308 fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime);
309 fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime);
310 fsw_store_attr_posix(sb, dno->sd_v1->sd_mode);
311 } else if (dno->sd_v2) {
312 sb->used_bytes = dno->sd_v2->sd_blocks * vol->g.log_blocksize;
313 fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime);
314 fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime);
315 fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime);
316 fsw_store_attr_posix(sb, dno->sd_v2->sd_mode);
317 }
318
319 return FSW_SUCCESS;
320 }
321
322 /**
323 * Retrieve file data mapping information. This function is called by the core when
324 * fsw_shandle_read needs to know where on the disk the required piece of the file's
325 * data can be found. The core makes sure that fsw_reiserfs_dnode_fill has been called
326 * on the dnode before. Our task here is to get the physical disk block number for
327 * the requested logical block number.
328 */
329
330 static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
331 struct fsw_extent *extent)
332 {
333 fsw_status_t status;
334 fsw_u64 search_offset, intra_offset;
335 struct fsw_reiserfs_item item;
336 fsw_u32 intra_bno, nr_item;
337
338 // Preconditions: The caller has checked that the requested logical block
339 // is within the file's size. The dnode has complete information, i.e.
340 // fsw_reiserfs_dnode_read_info was called successfully on it.
341
342 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_get_extent: mapping block %d of object %d/%d\n"),
343 extent->log_start, dno->dir_id, dno->g.dnode_id));
344
345 extent->type = FSW_EXTENT_TYPE_SPARSE;
346 extent->log_count = 1;
347
348 // get the item for the requested block
349 search_offset = (fsw_u64)extent->log_start * vol->g.log_blocksize + 1;
350 status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, search_offset, &item);
351 if (status)
352 return status;
353 if (item.item_offset == 0) {
354 fsw_reiserfs_item_release(vol, &item);
355 return FSW_SUCCESS; // no data items found, assume all-sparse file
356 }
357 intra_offset = search_offset - item.item_offset;
358
359 // check the kind of block
360 if (item.item_type == TYPE_INDIRECT || item.item_type == V1_INDIRECT_UNIQUENESS) {
361 // indirect item, contains block numbers
362
363 if (intra_offset & (vol->g.log_blocksize - 1)) {
364 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not block-aligned for indirect block\n")));
365 goto bail;
366 }
367 intra_bno = (fsw_u32)FSW_U64_DIV(intra_offset, vol->g.log_blocksize);
368 nr_item = item.ih.ih_item_len / sizeof(fsw_u32);
369 if (intra_bno >= nr_item) {
370 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: indirect block too small\n")));
371 goto bail;
372 }
373 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
374 extent->phys_start = ((fsw_u32 *)item.item_data)[intra_bno];
375
376 // TODO: check if the following blocks can be aggregated into one extent
377
378 fsw_reiserfs_item_release(vol, &item);
379 return FSW_SUCCESS;
380
381 } else if (item.item_type == TYPE_DIRECT || item.item_type == V1_DIRECT_UNIQUENESS) {
382 // direct item, contains file data
383
384 // TODO: Check if direct items always start on block boundaries. If not, we may have
385 // to do extra work here.
386
387 if (intra_offset != 0) {
388 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not aligned for direct block\n")));
389 goto bail;
390 }
391
392 extent->type = FSW_EXTENT_TYPE_BUFFER;
393 status = fsw_memdup(&extent->buffer, item.item_data, item.ih.ih_item_len);
394 fsw_reiserfs_item_release(vol, &item);
395 if (status)
396 return status;
397
398 return FSW_SUCCESS;
399
400 }
401
402 bail:
403 fsw_reiserfs_item_release(vol, &item);
404 return FSW_VOLUME_CORRUPTED;
405
406 /*
407 // check if the following blocks can be aggregated into one extent
408 file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
409 while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers
410 extent->log_start + extent->log_count < file_bcnt) { // file has more blocks
411 if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
412 extent->log_count++;
413 else
414 break;
415 }
416 */
417 }
418
419 /**
420 * Lookup a directory's child dnode by name. This function is called on a directory
421 * to retrieve the directory entry with the given name. A dnode is constructed for
422 * this entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
423 * and the dnode is actually a directory.
424 */
425
426 static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
427 struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno_out)
428 {
429 fsw_status_t status;
430 struct fsw_reiserfs_item item;
431 fsw_u32 nr_item, i, name_offset, next_name_offset, name_len;
432 fsw_u32 child_dir_id;
433 struct reiserfs_de_head *dhead;
434 struct fsw_string entry_name;
435
436 // Preconditions: The caller has checked that dno is a directory node.
437
438 // BIG TODOS: Use the hash function to start with the item containing the entry.
439 // Use binary search within the item.
440
441 entry_name.type = FSW_STRING_TYPE_ISO88591;
442
443 // get the item for that position
444 status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, FIRST_ITEM_OFFSET, &item);
445 if (status)
446 return status;
447 if (item.item_offset == 0) {
448 fsw_reiserfs_item_release(vol, &item);
449 return FSW_NOT_FOUND; // empty directory or something
450 }
451
452 for(;;) {
453
454 // search the directory item
455 dhead = (struct reiserfs_de_head *)item.item_data;
456 nr_item = item.ih.u.ih_entry_count;
457 next_name_offset = item.ih.ih_item_len;
458 for (i = 0; i < nr_item; i++, dhead++, next_name_offset = name_offset) {
459 // get the name
460 name_offset = dhead->deh_location;
461 name_len = next_name_offset - name_offset;
462 while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
463 name_len--;
464
465 entry_name.len = entry_name.size = name_len;
466 entry_name.data = item.item_data + name_offset;
467
468 // compare name
469 if (fsw_streq(lookup_name, &entry_name)) {
470 // found the entry we're looking for!
471
472 // setup a dnode for the child item
473 status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
474 child_dir_id = dhead->deh_dir_id;
475 fsw_reiserfs_item_release(vol, &item);
476 if (status)
477 return status;
478 (*child_dno_out)->dir_id = child_dir_id;
479
480 return FSW_SUCCESS;
481 }
482 }
483
484 // We didn't find the next directory entry in this item. Look for the next
485 // item of the directory.
486
487 status = fsw_reiserfs_item_next(vol, &item);
488 if (status)
489 return status;
490
491 }
492 }
493
494 /**
495 * Get the next directory entry when reading a directory. This function is called during
496 * directory iteration to retrieve the next directory entry. A dnode is constructed for
497 * the entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
498 * and the dnode is actually a directory. The shandle provided by the caller is used to
499 * record the position in the directory between calls.
500 */
501
502 static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
503 struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno_out)
504 {
505 fsw_status_t status;
506 struct fsw_reiserfs_item item;
507 fsw_u32 nr_item, i, name_offset, next_name_offset, name_len;
508 fsw_u32 child_dir_id;
509 struct reiserfs_de_head *dhead;
510 struct fsw_string entry_name;
511
512 // Preconditions: The caller has checked that dno is a directory node. The caller
513 // has opened a storage handle to the directory's storage and keeps it around between
514 // calls.
515
516 // BIG TODOS: Use binary search within the item.
517
518 // adjust pointer to first entry if necessary
519 if (shand->pos == 0)
520 shand->pos = FIRST_ITEM_OFFSET;
521
522 // get the item for that position
523 status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, shand->pos, &item);
524 if (status)
525 return status;
526 if (item.item_offset == 0) {
527 fsw_reiserfs_item_release(vol, &item);
528 return FSW_NOT_FOUND; // empty directory or something
529 }
530
531 for(;;) {
532
533 // search the directory item
534 dhead = (struct reiserfs_de_head *)item.item_data;
535 nr_item = item.ih.u.ih_entry_count;
536 for (i = 0; i < nr_item; i++, dhead++) {
537 if (dhead->deh_offset < shand->pos)
538 continue; // not yet past the last entry returned
539 if (dhead->deh_offset == DOT_OFFSET || dhead->deh_offset == DOT_DOT_OFFSET)
540 continue; // never report . or ..
541
542 // get the name
543 name_offset = dhead->deh_location;
544 if (i == 0)
545 next_name_offset = item.ih.ih_item_len;
546 else
547 next_name_offset = dhead[-1].deh_location;
548 name_len = next_name_offset - name_offset;
549 while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
550 name_len--;
551
552 entry_name.type = FSW_STRING_TYPE_ISO88591;
553 entry_name.len = entry_name.size = name_len;
554 entry_name.data = item.item_data + name_offset;
555
556 if (fsw_streq_cstr(&entry_name, ".reiserfs_priv"))
557 continue; // never report this special file
558
559 // found the next entry!
560 shand->pos = dhead->deh_offset + 1;
561
562 // setup a dnode for the child item
563 status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
564 child_dir_id = dhead->deh_dir_id;
565 fsw_reiserfs_item_release(vol, &item);
566 if (status)
567 return status;
568 (*child_dno_out)->dir_id = child_dir_id;
569
570 return FSW_SUCCESS;
571 }
572
573 // We didn't find the next directory entry in this item. Look for the next
574 // item of the directory.
575
576 status = fsw_reiserfs_item_next(vol, &item);
577 if (status)
578 return status;
579
580 }
581 }
582
583 /**
584 * Get the target path of a symbolic link. This function is called when a symbolic
585 * link needs to be resolved. The core makes sure that the fsw_reiserfs_dnode_fill has been
586 * called on the dnode and that it really is a symlink.
587 */
588
589 static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
590 struct fsw_string *link_target)
591 {
592 return fsw_dnode_readlink_data(dno, link_target);
593 }
594
595 /**
596 * Compare an on-disk tree key against the search key.
597 */
598
599 static int fsw_reiserfs_compare_key(struct reiserfs_key *key,
600 fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset)
601 {
602 fsw_u32 key_type;
603 fsw_u64 key_offset;
604
605 if (key->k_dir_id > dir_id)
606 return FIRST_GREATER;
607 if (key->k_dir_id < dir_id)
608 return SECOND_GREATER;
609
610 if (key->k_objectid > objectid)
611 return FIRST_GREATER;
612 if (key->k_objectid < objectid)
613 return SECOND_GREATER;
614
615 // determine format of the on-disk key
616 key_type = (fsw_u32)FSW_U64_SHR(key->u.k_offset_v2.v, 60);
617 if (key_type != TYPE_DIRECT && key_type != TYPE_INDIRECT && key_type != TYPE_DIRENTRY) {
618 // detected 3.5 format (_v1)
619 key_offset = key->u.k_offset_v1.k_offset;
620 } else {
621 // detected 3.6 format (_v2)
622 key_offset = key->u.k_offset_v2.v & (~0ULL >> 4);
623 }
624 if (key_offset > offset)
625 return FIRST_GREATER;
626 if (key_offset < offset)
627 return SECOND_GREATER;
628 return KEYS_IDENTICAL;
629 }
630
631 /**
632 * Find an item by key in the reiserfs tree.
633 */
634
635 static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
636 fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
637 struct fsw_reiserfs_item *item)
638 {
639 fsw_status_t status;
640 int comp_result;
641 fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, i;
642 fsw_u8 *buffer;
643 struct block_head *bhead;
644 struct reiserfs_key *key;
645 struct item_head *ihead;
646
647 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: searching %d/%d/%lld\n"), dir_id, objectid, offset));
648
649 // BIG TODOS: Use binary search within the item.
650 // Remember tree path for "get next item" function.
651
652 item->valid = 0;
653 item->block_bno = 0;
654
655 // walk the tree
656 tree_bno = vol->sb->s_v1.s_root_block;
657 for (tree_level = vol->sb->s_v1.s_tree_height - 1; ; tree_level--) {
658
659 // get the current tree block into memory
660 status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
661 if (status)
662 return status;
663 bhead = (struct block_head *)buffer;
664 if (bhead->blk_level != tree_level) {
665 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_search: tree block %d has not expected level %d\n"), tree_bno, tree_level));
666 fsw_block_release(vol, tree_bno, buffer);
667 return FSW_VOLUME_CORRUPTED;
668 }
669 nr_item = bhead->blk_nr_item;
670 FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_search: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
671 item->path_bno[tree_level] = tree_bno;
672
673 // check if we have reached a leaf block
674 if (tree_level == DISK_LEAF_NODE_LEVEL)
675 break;
676
677 // search internal node block, look for the path to follow
678 key = (struct reiserfs_key *)(buffer + BLKH_SIZE);
679 for (i = 0; i < nr_item; i++, key++) {
680 if (fsw_reiserfs_compare_key(key, dir_id, objectid, offset) == FIRST_GREATER)
681 break;
682 }
683 item->path_index[tree_level] = i;
684 next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[i].dc_block_number;
685 fsw_block_release(vol, tree_bno, buffer);
686 tree_bno = next_tree_bno;
687 }
688
689 // search leaf node block, look for our data
690 ihead = (struct item_head *)(buffer + BLKH_SIZE);
691 for (i = 0; i < nr_item; i++, ihead++) {
692 comp_result = fsw_reiserfs_compare_key(&ihead->ih_key, dir_id, objectid, offset);
693 if (comp_result == KEYS_IDENTICAL)
694 break;
695 if (comp_result == FIRST_GREATER) {
696 // Current key is greater than the search key. Use the last key before this
697 // one as the preliminary result.
698 if (i == 0) {
699 fsw_block_release(vol, tree_bno, buffer);
700 return FSW_NOT_FOUND;
701 }
702 i--, ihead--;
703 break;
704 }
705 }
706 if (i >= nr_item) {
707 // Go back to the last key, it was smaller than the search key.
708 // NOTE: The first key of the next leaf block is guaranteed to be greater than
709 // our search key.
710 i--, ihead--;
711 }
712 item->path_index[tree_level] = i;
713 // Since we may have a key that is smaller than the search key, verify that
714 // it is for the same object.
715 if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
716 fsw_block_release(vol, tree_bno, buffer);
717 return FSW_NOT_FOUND; // Found no key for this object at all
718 }
719
720 // return results
721 fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
722 item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
723 if (item->item_type != TYPE_DIRECT &&
724 item->item_type != TYPE_INDIRECT &&
725 item->item_type != TYPE_DIRENTRY) {
726 // 3.5 format (_v1)
727 item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
728 item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
729 } else {
730 // 3.6 format (_v2)
731 item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
732 }
733 item->item_data = buffer + ihead->ih_item_location;
734 item->valid = 1;
735
736 // add information for block release
737 item->block_bno = tree_bno;
738 item->block_buffer = buffer;
739
740 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: found %d/%d/%lld (%d)\n"),
741 ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
742 return FSW_SUCCESS;
743 }
744
745 /**
746 * Find the next item in the reiserfs tree for an already-found item.
747 */
748
749 static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
750 struct fsw_reiserfs_item *item)
751 {
752 fsw_status_t status;
753 fsw_u32 dir_id, objectid;
754 fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, nr_ptr_item;
755 fsw_u8 *buffer;
756 struct block_head *bhead;
757 struct item_head *ihead;
758
759 if (!item->valid)
760 return FSW_NOT_FOUND;
761 fsw_reiserfs_item_release(vol, item); // TODO: maybe delay this and/or use the cached block!
762
763 dir_id = item->ih.ih_key.k_dir_id;
764 objectid = item->ih.ih_key.k_objectid;
765
766 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: next for %d/%d/%lld\n"), dir_id, objectid, item->item_offset));
767
768 // find a node that has more items, moving up until we find one
769
770 for (tree_level = DISK_LEAF_NODE_LEVEL; tree_level < vol->sb->s_v1.s_tree_height; tree_level++) {
771
772 // get the current tree block into memory
773 tree_bno = item->path_bno[tree_level];
774 status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
775 if (status)
776 return status;
777 bhead = (struct block_head *)buffer;
778 if (bhead->blk_level != tree_level) {
779 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
780 fsw_block_release(vol, tree_bno, buffer);
781 return FSW_VOLUME_CORRUPTED;
782 }
783 nr_item = bhead->blk_nr_item;
784 FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
785
786 nr_ptr_item = nr_item + ((tree_level > DISK_LEAF_NODE_LEVEL) ? 1 : 0); // internal nodes have (nr_item) keys and (nr_item+1) pointers
787 item->path_index[tree_level]++;
788 if (item->path_index[tree_level] >= nr_ptr_item) {
789 item->path_index[tree_level] = 0;
790 fsw_block_release(vol, tree_bno, buffer);
791 continue; // this node doesn't have any more items, move up one level
792 }
793
794 // we have a new path to follow, move down to the leaf node again
795 while (tree_level > DISK_LEAF_NODE_LEVEL) {
796 // get next pointer from current block
797 next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[item->path_index[tree_level]].dc_block_number;
798 fsw_block_release(vol, tree_bno, buffer);
799 tree_bno = next_tree_bno;
800 tree_level--;
801
802 // get the current tree block into memory
803 status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
804 if (status)
805 return status;
806 bhead = (struct block_head *)buffer;
807 if (bhead->blk_level != tree_level) {
808 FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
809 fsw_block_release(vol, tree_bno, buffer);
810 return FSW_VOLUME_CORRUPTED;
811 }
812 nr_item = bhead->blk_nr_item;
813 FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
814 item->path_bno[tree_level] = tree_bno;
815 }
816
817 // get the item from the leaf node
818 ihead = ((struct item_head *)(buffer + BLKH_SIZE)) + item->path_index[tree_level];
819
820 // We now have the item that follows the previous one in the tree. Check that it
821 // belongs to the same object.
822 if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
823 fsw_block_release(vol, tree_bno, buffer);
824 return FSW_NOT_FOUND; // Found no next key for this object
825 }
826
827 // return results
828 fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
829 item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
830 if (item->item_type != TYPE_DIRECT &&
831 item->item_type != TYPE_INDIRECT &&
832 item->item_type != TYPE_DIRENTRY) {
833 // 3.5 format (_v1)
834 item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
835 item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
836 } else {
837 // 3.6 format (_v2)
838 item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
839 }
840 item->item_data = buffer + ihead->ih_item_location;
841 item->valid = 1;
842
843 // add information for block release
844 item->block_bno = tree_bno;
845 item->block_buffer = buffer;
846
847 FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: found %d/%d/%lld (%d)\n"),
848 ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
849 return FSW_SUCCESS;
850 }
851
852 // we went to the highest level node and there still were no more items...
853 return FSW_NOT_FOUND;
854 }
855
856 /**
857 * Release the disk block still referenced by an item search result.
858 */
859
860 static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
861 struct fsw_reiserfs_item *item)
862 {
863 if (!item->valid)
864 return;
865
866 if (item->block_bno > 0) {
867 fsw_block_release(vol, item->block_bno, item->block_buffer);
868 item->block_bno = 0;
869 }
870 }
871
872 // EOF