Line 0
Link Here
|
|
|
1 |
/* reiserfs.c - an implementation for the ReiserFS filesystem */ |
2 |
/* |
3 |
* This file was taken from GRUB and adapted to the aboot interface by |
4 |
* Ilia Mirkin [ibmirkin@gmail.com] in September 2005. Copyrights from |
5 |
* GRUB follow: |
6 |
* |
7 |
* GRUB -- GRand Unified Bootloader |
8 |
* Copyright (C) 2000, 2001 Free Software Foundation, Inc. |
9 |
* |
10 |
* This program is free software; you can redistribute it and/or modify |
11 |
* it under the terms of the GNU General Public License as published by |
12 |
* the Free Software Foundation; either version 2 of the License, or |
13 |
* (at your option) any later version. |
14 |
* |
15 |
* This program is distributed in the hope that it will be useful, |
16 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 |
* GNU General Public License for more details. |
19 |
* |
20 |
* You should have received a copy of the GNU General Public License |
21 |
* along with this program; if not, write to the Free Software |
22 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
23 |
*/ |
24 |
#include <asm/system.h> |
25 |
|
26 |
#include <config.h> |
27 |
#include <aboot.h> |
28 |
#include <bootfs.h> |
29 |
#include <cons.h> |
30 |
#include <utils.h> |
31 |
#include <disklabel.h> |
32 |
#include <string.h> |
33 |
|
34 |
#define BLOCKSIZE (16*SECT_SIZE) |
35 |
|
36 |
//#define REISERDEBUG 1 |
37 |
#undef REISERDEBUG |
38 |
|
39 |
#define ERR_FSYS_CORRUPT 2 |
40 |
|
41 |
/* Some parts of this code (mainly the structures and defines) are |
42 |
* from the original reiser fs code, as found in the linux kernel. |
43 |
*/ |
44 |
|
45 |
/* include/asm-i386/types.h */ |
46 |
/*typedef __signed__ char __s8; |
47 |
typedef unsigned char __u8; |
48 |
typedef __signed__ short __s16; |
49 |
typedef unsigned short __u16; |
50 |
typedef __signed__ int __s32; |
51 |
typedef unsigned int __u32; |
52 |
typedef unsigned long long __u64;*/ |
53 |
|
54 |
/* linux/posix_type.h */ |
55 |
typedef long linux_off_t; |
56 |
|
57 |
/* linux/little_endian.h */ |
58 |
/*#define __cpu_to_le64(x) ((__u64) (x)) |
59 |
#define __le64_to_cpu(x) ((__u64) (x)) |
60 |
#define __cpu_to_le32(x) ((__u32) (x)) |
61 |
#define __le32_to_cpu(x) ((__u32) (x)) |
62 |
#define __cpu_to_le16(x) ((__u16) (x)) |
63 |
#define __le16_to_cpu(x) ((__u16) (x))*/ |
64 |
|
65 |
/* include/linux/reiser_fs.h */ |
66 |
/* This is the new super block of a journaling reiserfs system */ |
67 |
struct reiserfs_super_block |
68 |
{ |
69 |
__u32 s_block_count; /* blocks count */ |
70 |
__u32 s_free_blocks; /* free blocks count */ |
71 |
__u32 s_root_block; /* root block number */ |
72 |
__u32 s_journal_block; /* journal block number */ |
73 |
__u32 s_journal_dev; /* journal device number */ |
74 |
__u32 s_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */ |
75 |
__u32 s_journal_trans_max; /* max number of blocks in a transaction. */ |
76 |
__u32 s_journal_magic; /* random value made on fs creation */ |
77 |
__u32 s_journal_max_batch; /* max number of blocks to batch into a trans */ |
78 |
__u32 s_journal_max_commit_age; /* in seconds, how old can an async commit be */ |
79 |
__u32 s_journal_max_trans_age; /* in seconds, how old can a transaction be */ |
80 |
__u16 s_blocksize; /* block size */ |
81 |
__u16 s_oid_maxsize; /* max size of object id array */ |
82 |
__u16 s_oid_cursize; /* current size of object id array */ |
83 |
__u16 s_state; /* valid or error */ |
84 |
char s_magic[16]; /* reiserfs magic string indicates that file system is reiserfs */ |
85 |
__u16 s_tree_height; /* height of disk tree */ |
86 |
__u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ |
87 |
__u16 s_version; |
88 |
char s_unused[128]; /* zero filled by mkreiserfs */ |
89 |
}; |
90 |
|
91 |
#define REISERFS_MAX_SUPPORTED_VERSION 2 |
92 |
#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" |
93 |
#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" |
94 |
#define REISER3FS_SUPER_MAGIC_STRING "ReIsEr3Fs" |
95 |
|
96 |
#define MAX_HEIGHT 7 |
97 |
|
98 |
/* must be correct to keep the desc and commit structs at 4k */ |
99 |
#define JOURNAL_TRANS_HALF 1018 |
100 |
|
101 |
/* first block written in a commit. */ |
102 |
struct reiserfs_journal_desc { |
103 |
__u32 j_trans_id; /* id of commit */ |
104 |
__u32 j_len; /* length of commit. len +1 is the commit block */ |
105 |
__u32 j_mount_id; /* mount id of this trans*/ |
106 |
__u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */ |
107 |
char j_magic[12]; |
108 |
}; |
109 |
|
110 |
/* last block written in a commit */ |
111 |
struct reiserfs_journal_commit { |
112 |
__u32 j_trans_id; /* must match j_trans_id from the desc block */ |
113 |
__u32 j_len; /* ditto */ |
114 |
__u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */ |
115 |
char j_digest[16]; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */ |
116 |
}; |
117 |
|
118 |
/* this header block gets written whenever a transaction is considered |
119 |
fully flushed, and is more recent than the last fully flushed |
120 |
transaction. |
121 |
fully flushed means all the log blocks and all the real blocks are |
122 |
on disk, and this transaction does not need to be replayed. |
123 |
*/ |
124 |
struct reiserfs_journal_header { |
125 |
/* id of last fully flushed transaction */ |
126 |
__u32 j_last_flush_trans_id; |
127 |
/* offset in the log of where to start replay after a crash */ |
128 |
__u32 j_first_unflushed_offset; |
129 |
/* mount id to detect very old transactions */ |
130 |
__u32 j_mount_id; |
131 |
}; |
132 |
|
133 |
/* magic string to find desc blocks in the journal */ |
134 |
#define JOURNAL_DESC_MAGIC "ReIsErLB" |
135 |
|
136 |
|
137 |
/* |
138 |
* directories use this key as well as old files |
139 |
*/ |
140 |
struct offset_v1 |
141 |
{ |
142 |
/* |
143 |
* for regular files this is the offset to the first byte of the |
144 |
* body, contained in the object-item, as measured from the start of |
145 |
* the entire body of the object. |
146 |
* |
147 |
* for directory entries, k_offset consists of hash derived from |
148 |
* hashing the name and using few bits (23 or more) of the resulting |
149 |
* hash, and generation number that allows distinguishing names with |
150 |
* hash collisions. If number of collisions overflows generation |
151 |
* number, we return EEXIST. High order bit is 0 always |
152 |
*/ |
153 |
__u32 k_offset; |
154 |
__u32 k_uniqueness; |
155 |
}; |
156 |
|
157 |
struct offset_v2 |
158 |
{ |
159 |
/* |
160 |
* for regular files this is the offset to the first byte of the |
161 |
* body, contained in the object-item, as measured from the start of |
162 |
* the entire body of the object. |
163 |
* |
164 |
* for directory entries, k_offset consists of hash derived from |
165 |
* hashing the name and using few bits (23 or more) of the resulting |
166 |
* hash, and generation number that allows distinguishing names with |
167 |
* hash collisions. If number of collisions overflows generation |
168 |
* number, we return EEXIST. High order bit is 0 always |
169 |
*/ |
170 |
__u64 k_offset:60; |
171 |
__u64 k_type: 4; |
172 |
}; |
173 |
|
174 |
|
175 |
struct key |
176 |
{ |
177 |
/* packing locality: by default parent directory object id */ |
178 |
__u32 k_dir_id; |
179 |
/* object identifier */ |
180 |
__u32 k_objectid; |
181 |
/* the offset and node type (old and new form) */ |
182 |
union |
183 |
{ |
184 |
struct offset_v1 v1; |
185 |
struct offset_v2 v2; |
186 |
} |
187 |
u; |
188 |
}; |
189 |
|
190 |
#define KEY_SIZE (sizeof (struct key)) |
191 |
|
192 |
/* Header of a disk block. More precisely, header of a formatted leaf |
193 |
or internal node, and not the header of an unformatted node. */ |
194 |
struct block_head |
195 |
{ |
196 |
__u16 blk_level; /* Level of a block in the tree. */ |
197 |
__u16 blk_nr_item; /* Number of keys/items in a block. */ |
198 |
__u16 blk_free_space; /* Block free space in bytes. */ |
199 |
struct key blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes |
200 |
only) */ |
201 |
}; |
202 |
#define BLKH_SIZE (sizeof (struct block_head)) |
203 |
#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ |
204 |
|
205 |
struct item_head |
206 |
{ |
207 |
struct key ih_key; /* Everything in the tree is found by searching for it based on its key.*/ |
208 |
|
209 |
union |
210 |
{ |
211 |
__u16 ih_free_space; /* The free space in the last unformatted node of an indirect item if this |
212 |
is an indirect item. This equals 0xFFFF iff this is a direct item or |
213 |
stat data item. Note that the key, not this field, is used to determine |
214 |
the item type, and thus which field this union contains. */ |
215 |
__u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory |
216 |
entries in the directory item. */ |
217 |
} |
218 |
u; |
219 |
__u16 ih_item_len; /* total size of the item body */ |
220 |
__u16 ih_item_location; /* an offset to the item body within the block */ |
221 |
__u16 ih_version; /* ITEM_VERSION_1 for all old items, |
222 |
ITEM_VERSION_2 for new ones. |
223 |
Highest bit is set by fsck |
224 |
temporary, cleaned after all done */ |
225 |
}; |
226 |
/* size of item header */ |
227 |
#define IH_SIZE (sizeof (struct item_head)) |
228 |
|
229 |
#define ITEM_VERSION_1 0 |
230 |
#define ITEM_VERSION_2 1 |
231 |
#define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \ |
232 |
? (ih)->ih_key.u.v1.k_offset \ |
233 |
: (ih)->ih_key.u.v2.k_offset) |
234 |
|
235 |
#define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \ |
236 |
? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \ |
237 |
: (ih)->ih_key.u.v2.k_type == V2_##type) |
238 |
|
239 |
struct disk_child |
240 |
{ |
241 |
__u32 dc_block_number; /* Disk child's block number. */ |
242 |
__u16 dc_size; /* Disk child's used space. */ |
243 |
__u16 dc_reserved; |
244 |
}; |
245 |
|
246 |
#define DC_SIZE (sizeof (struct disk_child)) |
247 |
|
248 |
/* Stat Data on disk. |
249 |
* |
250 |
* Note that reiserfs has two different forms of stat data. Luckily |
251 |
* the fields needed by grub are at the same position. |
252 |
*/ |
253 |
struct stat_data |
254 |
{ |
255 |
__u16 sd_mode; /* file type, permissions */ |
256 |
__u16 sd_notused1[3]; /* fields not needed by reiserfs */ |
257 |
__u32 sd_size; /* file size */ |
258 |
__u32 sd_size_hi; /* file size high 32 bits (since version 2) */ |
259 |
}; |
260 |
|
261 |
struct reiserfs_de_head |
262 |
{ |
263 |
__u32 deh_offset; /* third component of the directory entry key */ |
264 |
__u32 deh_dir_id; /* objectid of the parent directory of the |
265 |
object, that is referenced by directory entry */ |
266 |
__u32 deh_objectid;/* objectid of the object, that is referenced by |
267 |
directory entry */ |
268 |
__u16 deh_location;/* offset of name in the whole item */ |
269 |
__u16 deh_state; /* whether 1) entry contains stat data (for |
270 |
future), and 2) whether entry is hidden |
271 |
(unlinked) */ |
272 |
}; |
273 |
|
274 |
#define DEH_SIZE (sizeof (struct reiserfs_de_head)) |
275 |
|
276 |
#define DEH_Statdata (1 << 0) /* not used now */ |
277 |
#define DEH_Visible (1 << 2) |
278 |
|
279 |
#define SD_OFFSET 0 |
280 |
#define SD_UNIQUENESS 0 |
281 |
#define DOT_OFFSET 1 |
282 |
#define DOT_DOT_OFFSET 2 |
283 |
#define DIRENTRY_UNIQUENESS 500 |
284 |
|
285 |
#define V1_TYPE_STAT_DATA 0x0 |
286 |
#define V1_TYPE_DIRECT 0xffffffff |
287 |
#define V1_TYPE_INDIRECT 0xfffffffe |
288 |
#define V1_TYPE_DIRECTORY_MAX 0xfffffffd |
289 |
#define V2_TYPE_STAT_DATA 0 |
290 |
#define V2_TYPE_INDIRECT 1 |
291 |
#define V2_TYPE_DIRECT 2 |
292 |
#define V2_TYPE_DIRENTRY 3 |
293 |
|
294 |
#define REISERFS_ROOT_OBJECTID 2 |
295 |
#define REISERFS_ROOT_PARENT_OBJECTID 1 |
296 |
#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) |
297 |
/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */ |
298 |
#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) |
299 |
#define REISERFS_OLD_BLOCKSIZE 4096 |
300 |
|
301 |
#define S_ISREG(mode) (((mode) & 0170000) == 0100000) |
302 |
#define S_ISDIR(mode) (((mode) & 0170000) == 0040000) |
303 |
#define S_ISLNK(mode) (((mode) & 0170000) == 0120000) |
304 |
|
305 |
#define PATH_MAX 1024 /* include/linux/limits.h */ |
306 |
#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */ |
307 |
|
308 |
/* The size of the node cache */ |
309 |
#define FSYSREISER_CACHE_SIZE 24*1024 |
310 |
#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE |
311 |
#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3 |
312 |
|
313 |
/* Info about currently opened file */ |
314 |
struct fsys_reiser_fileinfo |
315 |
{ |
316 |
__u32 k_dir_id; |
317 |
__u32 k_objectid; |
318 |
}; |
319 |
|
320 |
/* In memory info about the currently mounted filesystem */ |
321 |
struct fsys_reiser_info |
322 |
{ |
323 |
/* The last read item head */ |
324 |
struct item_head *current_ih; |
325 |
/* The last read item */ |
326 |
char *current_item; |
327 |
/* The information for the currently opened file */ |
328 |
struct fsys_reiser_fileinfo fileinfo; |
329 |
/* The start of the journal */ |
330 |
__u32 journal_block; |
331 |
/* The size of the journal */ |
332 |
__u32 journal_block_count; |
333 |
/* The first valid descriptor block in journal |
334 |
(relative to journal_block) */ |
335 |
__u32 journal_first_desc; |
336 |
|
337 |
/* The ReiserFS version. */ |
338 |
__u16 version; |
339 |
/* The current depth of the reiser tree. */ |
340 |
__u16 tree_depth; |
341 |
/* SECTOR_SIZE << blocksize_shift == blocksize. */ |
342 |
__u8 blocksize_shift; |
343 |
/* 1 << full_blocksize_shift == blocksize. */ |
344 |
__u8 fullblocksize_shift; |
345 |
/* The reiserfs block size (must be a power of 2) */ |
346 |
__u16 blocksize; |
347 |
/* The number of cached tree nodes */ |
348 |
__u16 cached_slots; |
349 |
/* The number of valid transactions in journal */ |
350 |
__u16 journal_transactions; |
351 |
|
352 |
unsigned int blocks[MAX_HEIGHT]; |
353 |
unsigned int next_key_nr[MAX_HEIGHT]; |
354 |
}; |
355 |
|
356 |
/* The cached s+tree blocks in FSYS_BUF, see below |
357 |
* for a more detailed description. |
358 |
*/ |
359 |
|
360 |
#define FSYS_BUF ((__u64)fsys_buffer) |
361 |
#define FSYS_BUFLEN (0x8000L) |
362 |
|
363 |
#define ROOT ((char *) ((__u64) FSYS_BUF)) |
364 |
#define CACHE(i) (ROOT + (((__u64)i) << INFO->fullblocksize_shift)) |
365 |
#define LEAF CACHE (DISK_LEAF_NODE_LEVEL) |
366 |
|
367 |
#define BLOCKHEAD(cache) ((struct block_head *) cache) |
368 |
#define ITEMHEAD ((struct item_head *) ((__u64) LEAF + BLKH_SIZE)) |
369 |
#define KEY(cache) ((struct key *) ((__u64) cache + BLKH_SIZE)) |
370 |
#define DC(cache) ((struct disk_child *) \ |
371 |
((__u64) cache + BLKH_SIZE + KEY_SIZE * nr_item)) |
372 |
/* The fsys_reiser_info block. |
373 |
*/ |
374 |
#define INFO \ |
375 |
((struct fsys_reiser_info *) ((__u64) FSYS_BUF + FSYSREISER_CACHE_SIZE)) |
376 |
/* |
377 |
* The journal cache. For each transaction it contains the number of |
378 |
* blocks followed by the real block numbers of this transaction. |
379 |
* |
380 |
* If the block numbers of some transaction won't fit in this space, |
381 |
* this list is stopped with a 0xffffffff marker and the remaining |
382 |
* uncommitted transactions aren't cached. |
383 |
*/ |
384 |
#define JOURNAL_START ((__u32 *) (INFO + 1)) |
385 |
#define JOURNAL_END ((__u32 *) (FSYS_BUF + FSYS_BUFLEN)) |
386 |
|
387 |
#define MAX_OPEN_FILES 5 |
388 |
|
389 |
static struct fd_table_entry { |
390 |
struct item_head *ih; |
391 |
char *current_item; |
392 |
int current_item_pos; |
393 |
int used; |
394 |
char *cur_name; |
395 |
int mode; |
396 |
struct fsys_reiser_fileinfo fileinfo; |
397 |
} fd_table[MAX_OPEN_FILES]; |
398 |
|
399 |
static int errnum = 0; |
400 |
|
401 |
static __inline__ unsigned long |
402 |
log2 (unsigned long word) |
403 |
{ |
404 |
__asm__ ("bsfl %1,%0" |
405 |
: "=r" (word) |
406 |
: "r" (word)); |
407 |
return word; |
408 |
} |
409 |
|
410 |
static __inline__ int |
411 |
is_power_of_two (unsigned long word) |
412 |
{ |
413 |
return (word & -word) == word; |
414 |
} |
415 |
|
416 |
static int reiserfs_mount(long cons_dev, long p_offset, long quiet); |
417 |
static int reiserfs_bread(int fd, long blkno, long nblks, char *buffer); |
418 |
static int reiserfs_open(const char *filename); |
419 |
static void reiserfs_close(int fd); |
420 |
static const char *reiserfs_readdir(int fd, int rewind); |
421 |
static int next_key(int); |
422 |
static int search_stat(int, __u32, __u32); |
423 |
|
424 |
struct bootfs reiserfs = { |
425 |
FS_EXT2, 0, |
426 |
reiserfs_mount, |
427 |
reiserfs_open, reiserfs_bread, reiserfs_close, |
428 |
reiserfs_readdir |
429 |
}; |
430 |
|
431 |
int isspace(char ch) { |
432 |
if (ch == ' ' || ch == '\r' || ch == '\n') return 1; |
433 |
return 0; |
434 |
} |
435 |
|
436 |
static long dev = -1; |
437 |
static long partition_offset = 0; |
438 |
|
439 |
static void *fsys_buffer; |
440 |
|
441 |
static int devread(int sector, int byte_offset, int byte_len, char *buf) { |
442 |
//printf("devread(sector = %d, offt = %d, len = %d, buf = %p)\n", sector, |
443 |
// byte_offset, byte_len, buf); |
444 |
if (sector < 0) { |
445 |
return 0; |
446 |
} |
447 |
|
448 |
long offset = (((long)sector) << 9) + partition_offset + byte_offset; |
449 |
return cons_read(dev, buf, byte_len, offset); |
450 |
} |
451 |
|
452 |
static int |
453 |
journal_read (int block, int len, char *buffer) |
454 |
{ |
455 |
//printf("journal_read(block = %d, len = %d, buffer = %p)\n", block, len, buffer); |
456 |
return devread ((int)((INFO->journal_block + block) << INFO->blocksize_shift), |
457 |
0, len, buffer); |
458 |
} |
459 |
|
460 |
/* Read a block from ReiserFS file system, taking the journal into |
461 |
* account. If the block nr is in the journal, the block from the |
462 |
* journal taken. |
463 |
*/ |
464 |
static int |
465 |
block_read (int blockNr, int start, int len, char *buffer) |
466 |
{ |
467 |
|
468 |
//printf("block_read(blockNr = %d, start = %d, len = %d, buffer = %p)\n", blockNr, |
469 |
// start, len, buffer); |
470 |
|
471 |
int transactions = INFO->journal_transactions; |
472 |
int desc_block = INFO->journal_first_desc; |
473 |
int journal_mask = INFO->journal_block_count - 1; |
474 |
int translatedNr = blockNr; |
475 |
__u32 *journal_table = JOURNAL_START; |
476 |
while (transactions-- > 0) { |
477 |
int i = 0; |
478 |
int j_len; |
479 |
if (*journal_table != 0xffffffff) { |
480 |
/* Search for the blockNr in cached journal */ |
481 |
j_len = *journal_table++; |
482 |
while (i++ < j_len) { |
483 |
if (*journal_table++ == blockNr) { |
484 |
journal_table += j_len - i; |
485 |
goto found; |
486 |
} |
487 |
} |
488 |
} else { |
489 |
/* This is the end of cached journal marker. The remaining |
490 |
* transactions are still on disk. |
491 |
*/ |
492 |
struct reiserfs_journal_desc desc; |
493 |
struct reiserfs_journal_commit commit; |
494 |
|
495 |
if (! journal_read (desc_block, sizeof (desc), (char *) &desc)) |
496 |
return 0; |
497 |
|
498 |
j_len = desc.j_len; |
499 |
while (i < j_len && i < JOURNAL_TRANS_HALF) |
500 |
if (desc.j_realblock[i++] == blockNr) |
501 |
goto found; |
502 |
|
503 |
if (j_len >= JOURNAL_TRANS_HALF) { |
504 |
int commit_block = (desc_block + 1 + j_len) & journal_mask; |
505 |
if (! journal_read (commit_block, |
506 |
sizeof (commit), (char *) &commit)) |
507 |
return 0; |
508 |
while (i < j_len) |
509 |
if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr) |
510 |
goto found; |
511 |
} |
512 |
} |
513 |
goto not_found; |
514 |
|
515 |
found: |
516 |
translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask); |
517 |
#ifdef REISERDEBUG |
518 |
printf ("block_read: block %d is mapped to journal block %d.\n", |
519 |
blockNr, translatedNr - INFO->journal_block); |
520 |
#endif |
521 |
/* We must continue the search, as this block may be overwritten |
522 |
* in later transactions. |
523 |
*/ |
524 |
not_found: |
525 |
desc_block = (desc_block + 2 + j_len) & journal_mask; |
526 |
} |
527 |
return devread (translatedNr << INFO->blocksize_shift, start, len, buffer); |
528 |
} |
529 |
|
530 |
/* Init the journal data structure. We try to cache as much as |
531 |
* possible in the JOURNAL_START-JOURNAL_END space, but if it is full |
532 |
* we can still read the rest from the disk on demand. |
533 |
* |
534 |
* The first number of valid transactions and the descriptor block of the |
535 |
* first valid transaction are held in INFO. The transactions are all |
536 |
* adjacent, but we must take care of the journal wrap around. |
537 |
*/ |
538 |
static int |
539 |
journal_init (void) |
540 |
{ |
541 |
//printf("in journal_init()\n"); |
542 |
|
543 |
unsigned int block_count = INFO->journal_block_count; |
544 |
unsigned int desc_block; |
545 |
unsigned int commit_block; |
546 |
unsigned int next_trans_id; |
547 |
struct reiserfs_journal_header header; |
548 |
struct reiserfs_journal_desc desc; |
549 |
struct reiserfs_journal_commit commit; |
550 |
__u32 *journal_table = JOURNAL_START; |
551 |
|
552 |
journal_read (block_count, sizeof (header), (char *) &header); |
553 |
desc_block = header.j_first_unflushed_offset; |
554 |
if (desc_block >= block_count) |
555 |
return 0; |
556 |
|
557 |
INFO->journal_first_desc = desc_block; |
558 |
next_trans_id = header.j_last_flush_trans_id + 1; |
559 |
|
560 |
#ifdef REISERDEBUG |
561 |
printf ("journal_init: last flushed %d\n", |
562 |
header.j_last_flush_trans_id); |
563 |
#endif |
564 |
|
565 |
while (1) { |
566 |
journal_read (desc_block, sizeof (desc), (char *) &desc); |
567 |
if (strcmp(JOURNAL_DESC_MAGIC, desc.j_magic) || |
568 |
desc.j_trans_id != next_trans_id || |
569 |
desc.j_mount_id != header.j_mount_id) |
570 |
/* no more valid transactions */ |
571 |
break; |
572 |
|
573 |
commit_block = (desc_block + desc.j_len + 1) & (block_count - 1); |
574 |
journal_read (commit_block, sizeof (commit), (char *) &commit); |
575 |
if (desc.j_trans_id != commit.j_trans_id |
576 |
|| desc.j_len != commit.j_len) |
577 |
/* no more valid transactions */ |
578 |
break; |
579 |
|
580 |
#ifdef REISERDEBUG |
581 |
printf ("Found valid transaction %d/%d at %d.\n", |
582 |
desc.j_trans_id, desc.j_mount_id, desc_block); |
583 |
#endif |
584 |
|
585 |
next_trans_id++; |
586 |
if (journal_table < JOURNAL_END) { |
587 |
if ((journal_table + 1 + desc.j_len) >= JOURNAL_END) { |
588 |
/* The table is almost full; mark the end of the cached |
589 |
* journal.*/ |
590 |
*journal_table = 0xffffffff; |
591 |
journal_table = JOURNAL_END; |
592 |
} else { |
593 |
int i; |
594 |
/* Cache the length and the realblock numbers in the table. |
595 |
* The block number of descriptor can easily be computed. |
596 |
* and need not to be stored here. |
597 |
*/ |
598 |
*journal_table++ = desc.j_len; |
599 |
for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++) { |
600 |
*journal_table++ = desc.j_realblock[i]; |
601 |
#ifdef REISERDEBUG |
602 |
printf ("block %d is in journal %d.\n", |
603 |
desc.j_realblock[i], desc_block); |
604 |
#endif |
605 |
} |
606 |
for ( ; i < desc.j_len; i++) { |
607 |
*journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF]; |
608 |
#ifdef REISERDEBUG |
609 |
printf ("block %d is in journal %d.\n", |
610 |
commit.j_realblock[i-JOURNAL_TRANS_HALF], |
611 |
desc_block); |
612 |
#endif |
613 |
} |
614 |
} |
615 |
} |
616 |
desc_block = (commit_block + 1) & (block_count - 1); |
617 |
} |
618 |
#ifdef REISERDEBUG |
619 |
printf ("Transaction %d/%d at %d isn't valid.\n", |
620 |
desc.j_trans_id, desc.j_mount_id, desc_block); |
621 |
#endif |
622 |
|
623 |
INFO->journal_transactions |
624 |
= next_trans_id - header.j_last_flush_trans_id - 1; |
625 |
return errnum == 0; |
626 |
} |
627 |
|
628 |
|
629 |
/* |
630 |
* Initialize 'filesystem' |
631 |
* Returns 0 if successful, -1 on failure. |
632 |
*/ |
633 |
static int |
634 |
reiserfs_mount(long cons_dev, long p_offset, long quiet) |
635 |
{ |
636 |
struct reiserfs_super_block super; |
637 |
dev = cons_dev; |
638 |
partition_offset = p_offset; |
639 |
int superblock = REISERFS_DISK_OFFSET_IN_BYTES; |
640 |
|
641 |
memset(fd_table, 0, sizeof(fd_table)); |
642 |
|
643 |
if (!cons_read(dev, &super, sizeof(super), partition_offset + superblock) || |
644 |
(strcmp(REISER3FS_SUPER_MAGIC_STRING, super.s_magic) && |
645 |
strcmp(REISER2FS_SUPER_MAGIC_STRING, super.s_magic) && |
646 |
strcmp(REISERFS_SUPER_MAGIC_STRING, super.s_magic)) || |
647 |
(super.s_journal_block * super.s_blocksize <= |
648 |
REISERFS_DISK_OFFSET_IN_BYTES)) { |
649 |
printf("FIXME: check for old partition type.\n"); |
650 |
printf("ReiserFS partition not found\n"); |
651 |
return -1; |
652 |
} |
653 |
|
654 |
if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION) return -1; |
655 |
|
656 |
#define SECTOR_BITS 9 |
657 |
#define SECTOR_SIZE 0x200 |
658 |
|
659 |
fsys_buffer = malloc(0x8000); |
660 |
|
661 |
INFO->version = super.s_version; |
662 |
INFO->blocksize = super.s_blocksize; |
663 |
reiserfs.blocksize = super.s_blocksize; |
664 |
INFO->fullblocksize_shift = 12;//log2 (super.s_blocksize); |
665 |
//printf("expecting s_blocksize to be 4096. it is %d\n", super.s_blocksize); |
666 |
INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS; |
667 |
INFO->cached_slots = (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1; |
668 |
|
669 |
if (!quiet) { |
670 |
printf("reiserfs_mount: version = %d, blocksize = %d, root block = %d\n", |
671 |
super.s_version, super.s_blocksize, super.s_root_block); |
672 |
} |
673 |
|
674 |
memset(INFO->blocks, 0, sizeof(INFO->blocks)); |
675 |
|
676 |
if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE || |
677 |
super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE || |
678 |
(SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize) |
679 |
return -1; |
680 |
|
681 |
INFO->journal_transactions = 0; |
682 |
|
683 |
if (super.s_journal_block != 0 && super.s_journal_dev == 0) { |
684 |
INFO->journal_block = super.s_journal_block; |
685 |
INFO->journal_block_count = super.s_journal_size; |
686 |
if (is_power_of_two (INFO->journal_block_count)) |
687 |
journal_init (); |
688 |
|
689 |
/* Read in super block again, maybe it is in the journal */ |
690 |
block_read (superblock >> INFO->fullblocksize_shift, |
691 |
0, sizeof (struct reiserfs_super_block), (char *) &super); |
692 |
} |
693 |
|
694 |
if (! block_read (super.s_root_block, 0, INFO->blocksize, (char*) ROOT)) |
695 |
return -1; |
696 |
|
697 |
INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level; |
698 |
|
699 |
#ifdef REISERDEBUG |
700 |
printf ("root read_in: block=%d, depth=%d\n", |
701 |
super.s_root_block, INFO->tree_depth); |
702 |
#endif /* REISERDEBUG */ |
703 |
|
704 |
if (INFO->tree_depth >= MAX_HEIGHT) |
705 |
return -1; |
706 |
if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL) { |
707 |
/* There is only one node in the whole filesystem, |
708 |
* which is simultanously leaf and root */ |
709 |
memcpy (LEAF, ROOT, INFO->blocksize); |
710 |
} |
711 |
|
712 |
return 0; |
713 |
} |
714 |
|
715 |
|
716 |
/* |
717 |
* Read block number "blkno". |
718 |
*/ |
719 |
static int |
720 |
reiserfs_bread(int fd, long blkno, long nblks, char *buffer) |
721 |
{ |
722 |
//ok. this is going to be highly inefficient. seek to the |
723 |
//beginning of the file, then go to the block and read that data |
724 |
//into the buffer. |
725 |
search_stat(fd, fd_table[fd].fileinfo.k_dir_id, fd_table[fd].fileinfo.k_objectid); |
726 |
|
727 |
unsigned int blocksize; |
728 |
unsigned int offset; |
729 |
unsigned int to_read; |
730 |
char *prev_buf = buffer; |
731 |
long len = (blkno + nblks) * INFO->blocksize; |
732 |
long filepos = 0; |
733 |
errnum = 0; |
734 |
|
735 |
#ifdef REISERDEBUG |
736 |
printf ("reiserfs_read: filepos=%d len=%d (really %d), offset=%x:%x\n", |
737 |
filepos, len, nblks * INFO->blocksize, (__u64) IH_KEY_OFFSET (fd_table[fd].ih) - 1); |
738 |
#endif /* REISERDEBUG */ |
739 |
|
740 |
goto get_next_key; |
741 |
|
742 |
while (! errnum) { |
743 |
if (fd_table[fd].ih->ih_key.k_objectid != fd_table[fd].fileinfo.k_objectid) |
744 |
break; |
745 |
|
746 |
offset = filepos - IH_KEY_OFFSET (fd_table[fd].ih) + 1; |
747 |
blocksize = fd_table[fd].ih->ih_item_len; |
748 |
|
749 |
#ifdef REISERDEBUG |
750 |
printf (" loop: filepos=%d len=%d, offset=%d blocksize=%d\n", |
751 |
filepos, len, offset, blocksize); |
752 |
#endif /* REISERDEBUG */ |
753 |
|
754 |
if (IH_KEY_ISTYPE(fd_table[fd].ih, TYPE_DIRECT) && offset < blocksize) { |
755 |
#ifdef REISERDEBUG |
756 |
printf ("direct_read: offset=%d, blocksize=%d\n", |
757 |
offset, blocksize); |
758 |
#endif /* REISERDEBUG */ |
759 |
to_read = blocksize - offset; |
760 |
if (to_read > len) |
761 |
to_read = len; |
762 |
|
763 |
if (filepos < blkno * INFO->blocksize) { |
764 |
if (filepos + to_read > blkno * INFO->blocksize) { |
765 |
int change = blkno * INFO->blocksize - filepos; |
766 |
len -= change; |
767 |
offset += change; |
768 |
filepos += change; |
769 |
to_read -= change; |
770 |
} else { |
771 |
goto update_buf_len; |
772 |
} |
773 |
} |
774 |
memcpy (buffer, fd_table[fd].current_item + offset, to_read); |
775 |
buffer += to_read; |
776 |
goto update_buf_len; |
777 |
} else if (IH_KEY_ISTYPE(fd_table[fd].ih, TYPE_INDIRECT)) { |
778 |
blocksize = (blocksize >> 2) << INFO->fullblocksize_shift; |
779 |
#ifdef REISERDEBUG |
780 |
printf ("indirect_read: offset=%d, blocksize=%d\n", |
781 |
offset, blocksize); |
782 |
#endif /* REISERDEBUG */ |
783 |
|
784 |
while (offset < blocksize) { |
785 |
__u32 blocknr = ((__u32 *) fd_table[fd].current_item) |
786 |
[offset >> INFO->fullblocksize_shift]; |
787 |
int blk_offset = offset & (INFO->blocksize-1); |
788 |
|
789 |
to_read = INFO->blocksize - blk_offset; |
790 |
if (to_read > len) |
791 |
to_read = len; |
792 |
|
793 |
if (filepos < blkno * INFO->blocksize) { |
794 |
if (filepos + to_read > blkno * INFO->blocksize) { |
795 |
int change = blkno * INFO->blocksize - filepos; |
796 |
len -= change; |
797 |
offset += change; |
798 |
blk_offset += change; |
799 |
filepos += change; |
800 |
to_read -= change; |
801 |
} else { |
802 |
goto update_buf_len; |
803 |
} |
804 |
} |
805 |
|
806 |
/* Journal is only for meta data. Data blocks can be read |
807 |
* directly without using block_read |
808 |
*/ |
809 |
devread (blocknr << INFO->blocksize_shift, |
810 |
blk_offset, to_read, buffer); |
811 |
|
812 |
buffer += to_read; |
813 |
update_buf_len: |
814 |
len -= to_read; |
815 |
offset += to_read; |
816 |
filepos += to_read; |
817 |
if (len == 0) |
818 |
goto done; |
819 |
} |
820 |
} |
821 |
get_next_key: |
822 |
next_key (fd); |
823 |
} |
824 |
done: |
825 |
return errnum ? -errnum : buffer - prev_buf; |
826 |
} |
827 |
|
828 |
|
829 |
/* |
830 |
* Unix-like open routine. Returns a small integer |
831 |
* (does not care what file, we say it's OK) |
832 |
*/ |
833 |
static int reiserfs_open(const char *filename) |
834 |
{ |
835 |
struct reiserfs_de_head *de_head; |
836 |
__u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; |
837 |
|
838 |
int fd; |
839 |
|
840 |
char filname[128]; |
841 |
char *fname = filname; |
842 |
|
843 |
if (strlen(fname) > 127) return -1; |
844 |
strncpy(fname, filename, 127); |
845 |
|
846 |
dir_id = REISERFS_ROOT_PARENT_OBJECTID; |
847 |
objectid = REISERFS_ROOT_OBJECTID; |
848 |
|
849 |
for (fd = 0; fd < MAX_OPEN_FILES; fd++) { |
850 |
if (fd_table[fd].used == 0) { |
851 |
break; |
852 |
} |
853 |
} |
854 |
|
855 |
if (fd == MAX_OPEN_FILES) { |
856 |
printf("reiserfs: no free fd's\n"); |
857 |
return -1; |
858 |
} |
859 |
|
860 |
while (1) { |
861 |
//find object id (starts with /, then goes on from there) |
862 |
if (!search_stat(fd, dir_id, objectid)) |
863 |
return -1; |
864 |
|
865 |
fd_table[fd].mode = ((struct stat_data *)fd_table[fd].current_item)->sd_mode; |
866 |
|
867 |
if (S_ISLNK(fd_table[fd].mode)) { |
868 |
printf("symlink detected in path -- currently not supported\n"); |
869 |
return -1; |
870 |
} |
871 |
|
872 |
//remove prepended /'s |
873 |
while (*fname == '/') fname++; |
874 |
|
875 |
if (*fname == 0 || isspace(*fname)) { |
876 |
//we must have found it! |
877 |
fd_table[fd].current_item_pos = 0; |
878 |
fd_table[fd].fileinfo.k_dir_id = dir_id; |
879 |
fd_table[fd].fileinfo.k_objectid = objectid; |
880 |
//printf("calling next_key to init file (fd = %d)\n", fd); |
881 |
next_key(fd); |
882 |
//printf("open: found (fd = %d)!\n", fd); |
883 |
fd_table[fd].used = 1; |
884 |
return fd; |
885 |
} |
886 |
|
887 |
char *rest; |
888 |
char ch; |
889 |
//figure out what directory/file we want to find |
890 |
for (rest = fname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++); |
891 |
*rest = 0; |
892 |
|
893 |
//find that directory/file |
894 |
while (1) { |
895 |
char *name_end; |
896 |
int num_entries; |
897 |
|
898 |
if (!next_key(fd)) |
899 |
return -1; |
900 |
|
901 |
if (fd_table[fd].ih->ih_key.k_objectid != objectid) { |
902 |
break; |
903 |
} |
904 |
|
905 |
name_end = fd_table[fd].current_item + fd_table[fd].ih->ih_item_len; |
906 |
de_head = (struct reiserfs_de_head *) fd_table[fd].current_item; |
907 |
num_entries = fd_table[fd].ih->u.ih_entry_count; |
908 |
while (num_entries > 0) { |
909 |
char *name = fd_table[fd].current_item + de_head->deh_location; |
910 |
if ((de_head->deh_state & DEH_Visible)) { |
911 |
int cmp; |
912 |
char tmp = *name_end; |
913 |
*name_end = 0; |
914 |
cmp = strcmp(name, fname); |
915 |
*name_end = tmp; |
916 |
if (cmp == 0) goto found; |
917 |
} |
918 |
name_end = name; |
919 |
de_head++; |
920 |
num_entries--; |
921 |
} |
922 |
} |
923 |
*rest = ch; |
924 |
return -1; |
925 |
found: |
926 |
*rest = ch; |
927 |
fname = rest; |
928 |
|
929 |
parent_dir_id = dir_id; |
930 |
parent_objectid = objectid; |
931 |
dir_id = de_head->deh_dir_id; |
932 |
objectid = de_head->deh_objectid; |
933 |
} |
934 |
} |
935 |
|
936 |
|
937 |
static void reiserfs_close(int fd) |
938 |
{ |
939 |
if (fd_table[fd].cur_name) free(fd_table[fd].cur_name); |
940 |
fd_table[fd].cur_name = NULL; |
941 |
fd_table[fd].used = 0; |
942 |
} |
943 |
|
944 |
static const char *reiserfs_readdir(int fd, int rewind) |
945 |
{ |
946 |
//printf("readdir(%d)\n", fd); |
947 |
struct reiserfs_de_head *de_head; |
948 |
if (fd_table[fd].ih->u.ih_entry_count <= |
949 |
fd_table[fd].current_item_pos) return NULL; |
950 |
if (fd_table[fd].cur_name == NULL) { |
951 |
fd_table[fd].cur_name = malloc(128); |
952 |
} |
953 |
de_head = (struct reiserfs_de_head *) fd_table[fd].current_item; |
954 |
de_head += fd_table[fd].current_item_pos; |
955 |
|
956 |
/*printf("from %p for %d bytes\n", fd_table[fd].current_item + de_head->deh_location, |
957 |
fd_table[fd].ih->ih_item_len - de_head->deh_location); |
958 |
*/ |
959 |
if ((de_head->deh_state & DEH_Visible)) { |
960 |
strncpy(fd_table[fd].cur_name, |
961 |
fd_table[fd].current_item + de_head->deh_location, |
962 |
fd_table[fd].ih->ih_item_len - de_head->deh_location); |
963 |
fd_table[fd].cur_name[127] = 0; |
964 |
fd_table[fd].current_item_pos++; |
965 |
return fd_table[fd].cur_name; |
966 |
} else { |
967 |
fd_table[fd].current_item_pos++; |
968 |
return reiserfs_readdir(fd, rewind); |
969 |
} |
970 |
} |
971 |
|
972 |
/***************** TREE ACCESSING METHODS *****************************/ |
973 |
|
974 |
/* I assume you are familiar with the ReiserFS tree, if not go to |
975 |
* http://www.namesys.com/content_table.html |
976 |
* |
977 |
* My tree node cache is organized as following |
978 |
* 0 ROOT node |
979 |
* 1 LEAF node (if the ROOT is also a LEAF it is copied here |
980 |
* 2-n other nodes on current path from bottom to top. |
981 |
* if there is not enough space in the cache, the top most are |
982 |
* omitted. |
983 |
* |
984 |
* I have only two methods to find a key in the tree: |
985 |
* search_stat(dir_id, objectid) searches for the stat entry (always |
986 |
* the first entry) of an object. |
987 |
* next_key() gets the next key in tree order. |
988 |
* |
989 |
* This means, that I can only sequential reads of files are |
990 |
* efficient, but this really doesn't hurt for grub. |
991 |
*/ |
992 |
|
993 |
/* Read in the node at the current path and depth into the node cache. |
994 |
* You must set INFO->blocks[depth] before. |
995 |
*/ |
996 |
static char * |
997 |
read_tree_node (unsigned int blockNr, int depth) |
998 |
{ |
999 |
char* cache = CACHE(depth); |
1000 |
int num_cached = INFO->cached_slots; |
1001 |
if (depth < num_cached) |
1002 |
{ |
1003 |
/* This is the cached part of the path. Check if same block is |
1004 |
* needed. |
1005 |
*/ |
1006 |
if (0 && blockNr == INFO->blocks[depth]) |
1007 |
return cache; |
1008 |
} |
1009 |
else |
1010 |
cache = CACHE(num_cached); |
1011 |
|
1012 |
#ifdef REISERDEBUG |
1013 |
//printf (" next read_in: block=%d (depth=%d)\n", |
1014 |
//blockNr, depth); |
1015 |
#endif /* REISERDEBUG */ |
1016 |
if (! block_read (blockNr, 0, INFO->blocksize, cache)) |
1017 |
return 0; |
1018 |
/* Make sure it has the right node level */ |
1019 |
if (BLOCKHEAD (cache)->blk_level != depth) |
1020 |
{ |
1021 |
errnum = ERR_FSYS_CORRUPT; |
1022 |
return 0; |
1023 |
} |
1024 |
|
1025 |
INFO->blocks[depth] = blockNr; |
1026 |
return cache; |
1027 |
} |
1028 |
|
1029 |
/* Get the next key, i.e. the key following the last retrieved key in |
1030 |
* tree order. INFO->current_ih and |
1031 |
* INFO->current_info are adapted accordingly. */ |
1032 |
static int |
1033 |
next_key (int fd) |
1034 |
{ |
1035 |
int depth; |
1036 |
struct item_head *ih = fd_table[fd].ih + 1; |
1037 |
char *cache; |
1038 |
|
1039 |
if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item]) |
1040 |
{ |
1041 |
depth = DISK_LEAF_NODE_LEVEL; |
1042 |
/* The last item, was the last in the leaf node. |
1043 |
* Read in the next block |
1044 |
*/ |
1045 |
do |
1046 |
{ |
1047 |
if (depth == INFO->tree_depth) |
1048 |
{ |
1049 |
/* There are no more keys at all. |
1050 |
* Return a dummy item with MAX_KEY */ |
1051 |
ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key; |
1052 |
goto found; |
1053 |
} |
1054 |
depth++; |
1055 |
#ifdef REISERDEBUG |
1056 |
printf (" depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]); |
1057 |
#endif /* REISERDEBUG */ |
1058 |
} |
1059 |
while (INFO->next_key_nr[depth] == 0); |
1060 |
|
1061 |
if (depth == INFO->tree_depth) |
1062 |
cache = ROOT; |
1063 |
else if (depth <= INFO->cached_slots) |
1064 |
cache = CACHE (depth); |
1065 |
else |
1066 |
{ |
1067 |
cache = read_tree_node (INFO->blocks[depth], depth); |
1068 |
if (! cache) |
1069 |
return 0; |
1070 |
} |
1071 |
|
1072 |
do |
1073 |
{ |
1074 |
int nr_item = BLOCKHEAD (cache)->blk_nr_item; |
1075 |
int key_nr = INFO->next_key_nr[depth]++; |
1076 |
#ifdef REISERDEBUG |
1077 |
printf (" depth=%d, i=%d/%d\n", depth, key_nr, nr_item); |
1078 |
#endif /* REISERDEBUG */ |
1079 |
if (key_nr == nr_item) |
1080 |
/* This is the last item in this block, set the next_key_nr to 0 */ |
1081 |
INFO->next_key_nr[depth] = 0; |
1082 |
|
1083 |
cache = read_tree_node (DC (cache)[key_nr].dc_block_number, --depth); |
1084 |
if (! cache) |
1085 |
return 0; |
1086 |
} |
1087 |
while (depth > DISK_LEAF_NODE_LEVEL); |
1088 |
|
1089 |
ih = ITEMHEAD; |
1090 |
} |
1091 |
found: |
1092 |
fd_table[fd].ih = ih; |
1093 |
fd_table[fd].current_item = &LEAF[ih->ih_item_location]; |
1094 |
#ifdef REISERDEBUG |
1095 |
printf (" new ih: key %d:%d:%d:%d version:%d\n", |
1096 |
fd_table[fd].ih->ih_key.k_dir_id, |
1097 |
fd_table[fd].ih->ih_key.k_objectid, |
1098 |
fd_table[fd].ih->ih_key.u.v1.k_offset, |
1099 |
fd_table[fd].ih->ih_key.u.v1.k_uniqueness, |
1100 |
fd_table[fd].ih->ih_version); |
1101 |
#endif /* REISERDEBUG */ |
1102 |
return 1; |
1103 |
} |
1104 |
|
1105 |
/* preconditions: reiserfs_mount already executed, therefore |
1106 |
* INFO block is valid |
1107 |
* returns: 0 if error (errnum is set), |
1108 |
* nonzero iff we were able to find the key successfully. |
1109 |
* postconditions: on a nonzero return, the current_ih and |
1110 |
* current_item fields describe the key that equals the |
1111 |
* searched key. INFO->next_key contains the next key after |
1112 |
* the searched key. |
1113 |
* side effects: messes around with the cache. |
1114 |
*/ |
1115 |
static int |
1116 |
search_stat (int fd, __u32 dir_id, __u32 objectid) |
1117 |
{ |
1118 |
char *cache; |
1119 |
int depth; |
1120 |
int nr_item; |
1121 |
int i; |
1122 |
struct item_head *ih; |
1123 |
#ifdef REISERDEBUG |
1124 |
printf ("search_stat (%d):\n key %d:%d:0:0\n", fd, dir_id, objectid); |
1125 |
#endif /* REISERDEBUG */ |
1126 |
|
1127 |
depth = INFO->tree_depth; |
1128 |
cache = ROOT; |
1129 |
|
1130 |
while (depth > DISK_LEAF_NODE_LEVEL) |
1131 |
{ |
1132 |
struct key *key; |
1133 |
nr_item = BLOCKHEAD (cache)->blk_nr_item; |
1134 |
|
1135 |
key = KEY (cache); |
1136 |
|
1137 |
for (i = 0; i < nr_item; i++) |
1138 |
{ |
1139 |
if (key->k_dir_id > dir_id |
1140 |
|| (key->k_dir_id == dir_id |
1141 |
&& (key->k_objectid > objectid |
1142 |
|| (key->k_objectid == objectid |
1143 |
&& ((__u32)(key->u.v1.k_offset |
1144 |
| key->u.v1.k_uniqueness)) > 0)))) |
1145 |
break; |
1146 |
key++; |
1147 |
} |
1148 |
|
1149 |
#ifdef REISERDEBUG |
1150 |
printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); |
1151 |
//printf (" (%d:%d)\n", key->k_dir_id, key->k_objectid); |
1152 |
#endif /* REISERDEBUG */ |
1153 |
INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1; |
1154 |
cache = read_tree_node (DC (cache)[i].dc_block_number, --depth); |
1155 |
if (! cache) |
1156 |
return 0; |
1157 |
} |
1158 |
|
1159 |
/* cache == LEAF */ |
1160 |
nr_item = BLOCKHEAD (LEAF)->blk_nr_item; |
1161 |
ih = ITEMHEAD; |
1162 |
for (i = 0; i < nr_item; i++) |
1163 |
{ |
1164 |
if (ih->ih_key.k_dir_id == dir_id |
1165 |
&& ih->ih_key.k_objectid == objectid |
1166 |
&& ih->ih_key.u.v1.k_offset == 0 |
1167 |
&& ih->ih_key.u.v1.k_uniqueness == 0) |
1168 |
{ |
1169 |
#ifdef REISERDEBUG |
1170 |
printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); |
1171 |
#endif /* REISERDEBUG */ |
1172 |
fd_table[fd].ih = ih; |
1173 |
fd_table[fd].current_item = &LEAF[ih->ih_item_location]; |
1174 |
return 1; |
1175 |
} |
1176 |
ih++; |
1177 |
} |
1178 |
errnum = ERR_FSYS_CORRUPT; |
1179 |
return 0; |
1180 |
} |