17c478bd9Sstevel@tonic-gate /* fsys_reiserfs.c - an implementation for the ReiserFS filesystem */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
47c478bd9Sstevel@tonic-gate  *  Copyright (C) 2000, 2001  Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate  */
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate #ifdef FSYS_REISERFS
227c478bd9Sstevel@tonic-gate #include "shared.h"
237c478bd9Sstevel@tonic-gate #include "filesys.h"
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #undef REISERDEBUG
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /* Some parts of this code (mainly the structures and defines) are
287c478bd9Sstevel@tonic-gate  * from the original reiser fs code, as found in the linux kernel.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /* include/asm-i386/types.h */
327c478bd9Sstevel@tonic-gate typedef __signed__ char __s8;
337c478bd9Sstevel@tonic-gate typedef unsigned char __u8;
347c478bd9Sstevel@tonic-gate typedef __signed__ short __s16;
357c478bd9Sstevel@tonic-gate typedef unsigned short __u16;
367c478bd9Sstevel@tonic-gate typedef __signed__ int __s32;
377c478bd9Sstevel@tonic-gate typedef unsigned int __u32;
387c478bd9Sstevel@tonic-gate typedef unsigned long long __u64;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /* linux/posix_type.h */
417c478bd9Sstevel@tonic-gate typedef long linux_off_t;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* linux/little_endian.h */
447c478bd9Sstevel@tonic-gate #define __cpu_to_le64(x) ((__u64) (x))
457c478bd9Sstevel@tonic-gate #define __le64_to_cpu(x) ((__u64) (x))
467c478bd9Sstevel@tonic-gate #define __cpu_to_le32(x) ((__u32) (x))
477c478bd9Sstevel@tonic-gate #define __le32_to_cpu(x) ((__u32) (x))
487c478bd9Sstevel@tonic-gate #define __cpu_to_le16(x) ((__u16) (x))
497c478bd9Sstevel@tonic-gate #define __le16_to_cpu(x) ((__u16) (x))
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /* include/linux/reiser_fs.h */
527c478bd9Sstevel@tonic-gate /* This is the new super block of a journaling reiserfs system */
537c478bd9Sstevel@tonic-gate struct reiserfs_super_block
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate   __u32 s_block_count;			/* blocks count         */
567c478bd9Sstevel@tonic-gate   __u32 s_free_blocks;                  /* free blocks count    */
577c478bd9Sstevel@tonic-gate   __u32 s_root_block;           	/* root block number    */
587c478bd9Sstevel@tonic-gate   __u32 s_journal_block;           	/* journal block number    */
597c478bd9Sstevel@tonic-gate   __u32 s_journal_dev;           	/* journal device number  */
607c478bd9Sstevel@tonic-gate   __u32 s_journal_size; 		/* size of the journal on FS creation.  used to make sure they don't overflow it */
617c478bd9Sstevel@tonic-gate   __u32 s_journal_trans_max;            /* max number of blocks in a transaction.  */
627c478bd9Sstevel@tonic-gate   __u32 s_journal_magic;                /* random value made on fs creation */
637c478bd9Sstevel@tonic-gate   __u32 s_journal_max_batch;            /* max number of blocks to batch into a trans */
647c478bd9Sstevel@tonic-gate   __u32 s_journal_max_commit_age;       /* in seconds, how old can an async commit be */
657c478bd9Sstevel@tonic-gate   __u32 s_journal_max_trans_age;        /* in seconds, how old can a transaction be */
667c478bd9Sstevel@tonic-gate   __u16 s_blocksize;                   	/* block size           */
677c478bd9Sstevel@tonic-gate   __u16 s_oid_maxsize;			/* max size of object id array  */
687c478bd9Sstevel@tonic-gate   __u16 s_oid_cursize;			/* current size of object id array */
697c478bd9Sstevel@tonic-gate   __u16 s_state;                       	/* valid or error       */
707c478bd9Sstevel@tonic-gate   char s_magic[16];                     /* reiserfs magic string indicates that file system is reiserfs */
717c478bd9Sstevel@tonic-gate   __u16 s_tree_height;                  /* height of disk tree */
727c478bd9Sstevel@tonic-gate   __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to address each block of file system */
737c478bd9Sstevel@tonic-gate   __u16 s_version;
747c478bd9Sstevel@tonic-gate   char s_unused[128];			/* zero filled by mkreiserfs */
757c478bd9Sstevel@tonic-gate };
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define REISERFS_MAX_SUPPORTED_VERSION 2
787c478bd9Sstevel@tonic-gate #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
797c478bd9Sstevel@tonic-gate #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
807c478bd9Sstevel@tonic-gate #define REISER3FS_SUPER_MAGIC_STRING "ReIsEr3Fs"
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate #define MAX_HEIGHT 7
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /* must be correct to keep the desc and commit structs at 4k */
857c478bd9Sstevel@tonic-gate #define JOURNAL_TRANS_HALF 1018
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* first block written in a commit.  */
887c478bd9Sstevel@tonic-gate struct reiserfs_journal_desc {
897c478bd9Sstevel@tonic-gate   __u32 j_trans_id;			/* id of commit */
907c478bd9Sstevel@tonic-gate   __u32 j_len;				/* length of commit. len +1 is the commit block */
917c478bd9Sstevel@tonic-gate   __u32 j_mount_id;			/* mount id of this trans*/
927c478bd9Sstevel@tonic-gate   __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */
937c478bd9Sstevel@tonic-gate   char j_magic[12];
947c478bd9Sstevel@tonic-gate };
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /* last block written in a commit */
977c478bd9Sstevel@tonic-gate struct reiserfs_journal_commit {
987c478bd9Sstevel@tonic-gate   __u32 j_trans_id;			/* must match j_trans_id from the desc block */
997c478bd9Sstevel@tonic-gate   __u32 j_len;			/* ditto */
1007c478bd9Sstevel@tonic-gate   __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */
1017c478bd9Sstevel@tonic-gate   char j_digest[16];			/* md5 sum of all the blocks involved, including desc and commit. not used, kill it */
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* this header block gets written whenever a transaction is considered
1057c478bd9Sstevel@tonic-gate    fully flushed, and is more recent than the last fully flushed
1067c478bd9Sstevel@tonic-gate    transaction.
1077c478bd9Sstevel@tonic-gate    fully flushed means all the log blocks and all the real blocks are
1087c478bd9Sstevel@tonic-gate    on disk, and this transaction does not need to be replayed.
1097c478bd9Sstevel@tonic-gate */
1107c478bd9Sstevel@tonic-gate struct reiserfs_journal_header {
1117c478bd9Sstevel@tonic-gate   /* id of last fully flushed transaction */
1127c478bd9Sstevel@tonic-gate   __u32 j_last_flush_trans_id;
1137c478bd9Sstevel@tonic-gate   /* offset in the log of where to start replay after a crash */
1147c478bd9Sstevel@tonic-gate   __u32 j_first_unflushed_offset;
1157c478bd9Sstevel@tonic-gate   /* mount id to detect very old transactions */
1167c478bd9Sstevel@tonic-gate   __u32 j_mount_id;
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /* magic string to find desc blocks in the journal */
1207c478bd9Sstevel@tonic-gate #define JOURNAL_DESC_MAGIC "ReIsErLB"
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate  * directories use this key as well as old files
1257c478bd9Sstevel@tonic-gate  */
1267c478bd9Sstevel@tonic-gate struct offset_v1
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate   /*
1297c478bd9Sstevel@tonic-gate    * for regular files this is the offset to the first byte of the
1307c478bd9Sstevel@tonic-gate    * body, contained in the object-item, as measured from the start of
1317c478bd9Sstevel@tonic-gate    * the entire body of the object.
1327c478bd9Sstevel@tonic-gate    *
1337c478bd9Sstevel@tonic-gate    * for directory entries, k_offset consists of hash derived from
1347c478bd9Sstevel@tonic-gate    * hashing the name and using few bits (23 or more) of the resulting
1357c478bd9Sstevel@tonic-gate    * hash, and generation number that allows distinguishing names with
1367c478bd9Sstevel@tonic-gate    * hash collisions. If number of collisions overflows generation
1377c478bd9Sstevel@tonic-gate    * number, we return EEXIST.  High order bit is 0 always
1387c478bd9Sstevel@tonic-gate    */
1397c478bd9Sstevel@tonic-gate   __u32 k_offset;
1407c478bd9Sstevel@tonic-gate   __u32 k_uniqueness;
1417c478bd9Sstevel@tonic-gate };
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate struct offset_v2
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate   /*
1467c478bd9Sstevel@tonic-gate    * for regular files this is the offset to the first byte of the
1477c478bd9Sstevel@tonic-gate    * body, contained in the object-item, as measured from the start of
1487c478bd9Sstevel@tonic-gate    * the entire body of the object.
1497c478bd9Sstevel@tonic-gate    *
1507c478bd9Sstevel@tonic-gate    * for directory entries, k_offset consists of hash derived from
1517c478bd9Sstevel@tonic-gate    * hashing the name and using few bits (23 or more) of the resulting
1527c478bd9Sstevel@tonic-gate    * hash, and generation number that allows distinguishing names with
1537c478bd9Sstevel@tonic-gate    * hash collisions. If number of collisions overflows generation
1547c478bd9Sstevel@tonic-gate    * number, we return EEXIST.  High order bit is 0 always
1557c478bd9Sstevel@tonic-gate    */
1567c478bd9Sstevel@tonic-gate   __u64 k_offset:60;
1577c478bd9Sstevel@tonic-gate   __u64 k_type: 4;
1587c478bd9Sstevel@tonic-gate };
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate struct key
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate   /* packing locality: by default parent directory object id */
1647c478bd9Sstevel@tonic-gate   __u32 k_dir_id;
1657c478bd9Sstevel@tonic-gate   /* object identifier */
1667c478bd9Sstevel@tonic-gate   __u32 k_objectid;
1677c478bd9Sstevel@tonic-gate   /* the offset and node type (old and new form) */
1687c478bd9Sstevel@tonic-gate   union
1697c478bd9Sstevel@tonic-gate   {
1707c478bd9Sstevel@tonic-gate     struct offset_v1 v1;
1717c478bd9Sstevel@tonic-gate     struct offset_v2 v2;
1727c478bd9Sstevel@tonic-gate   }
1737c478bd9Sstevel@tonic-gate   u;
1747c478bd9Sstevel@tonic-gate };
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate #define KEY_SIZE (sizeof (struct key))
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate /* Header of a disk block.  More precisely, header of a formatted leaf
1797c478bd9Sstevel@tonic-gate    or internal node, and not the header of an unformatted node. */
1807c478bd9Sstevel@tonic-gate struct block_head
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate   __u16 blk_level;        /* Level of a block in the tree. */
1837c478bd9Sstevel@tonic-gate   __u16 blk_nr_item;      /* Number of keys/items in a block. */
1847c478bd9Sstevel@tonic-gate   __u16 blk_free_space;   /* Block free space in bytes. */
1857c478bd9Sstevel@tonic-gate   struct key  blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes
1867c478bd9Sstevel@tonic-gate 				      only) */
1877c478bd9Sstevel@tonic-gate };
1887c478bd9Sstevel@tonic-gate #define BLKH_SIZE (sizeof (struct block_head))
1897c478bd9Sstevel@tonic-gate #define DISK_LEAF_NODE_LEVEL  1 /* Leaf node level.                       */
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate struct item_head
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate   struct key ih_key; 	/* Everything in the tree is found by searching for it based on its key.*/
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate   union
1967c478bd9Sstevel@tonic-gate   {
1977c478bd9Sstevel@tonic-gate     __u16 ih_free_space; /* The free space in the last unformatted node of an indirect item if this
1987c478bd9Sstevel@tonic-gate 			    is an indirect item.  This equals 0xFFFF iff this is a direct item or
1997c478bd9Sstevel@tonic-gate 			    stat data item. Note that the key, not this field, is used to determine
2007c478bd9Sstevel@tonic-gate 			    the item type, and thus which field this union contains. */
2017c478bd9Sstevel@tonic-gate     __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory
2027c478bd9Sstevel@tonic-gate 			     entries in the directory item. */
2037c478bd9Sstevel@tonic-gate   }
2047c478bd9Sstevel@tonic-gate   u;
2057c478bd9Sstevel@tonic-gate   __u16 ih_item_len;           /* total size of the item body                  */
2067c478bd9Sstevel@tonic-gate   __u16 ih_item_location;      /* an offset to the item body within the block  */
2077c478bd9Sstevel@tonic-gate   __u16 ih_version;	       /* ITEM_VERSION_1 for all old items,
2087c478bd9Sstevel@tonic-gate 				  ITEM_VERSION_2 for new ones.
2097c478bd9Sstevel@tonic-gate 				  Highest bit is set by fsck
2107c478bd9Sstevel@tonic-gate                                   temporary, cleaned after all done */
2117c478bd9Sstevel@tonic-gate };
2127c478bd9Sstevel@tonic-gate /* size of item header     */
2137c478bd9Sstevel@tonic-gate #define IH_SIZE (sizeof (struct item_head))
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate #define ITEM_VERSION_1 0
2167c478bd9Sstevel@tonic-gate #define ITEM_VERSION_2 1
2177c478bd9Sstevel@tonic-gate #define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \
2187c478bd9Sstevel@tonic-gate 			   ? (ih)->ih_key.u.v1.k_offset \
2197c478bd9Sstevel@tonic-gate 			   : (ih)->ih_key.u.v2.k_offset)
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate #define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \
2227c478bd9Sstevel@tonic-gate 				 ? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \
2237c478bd9Sstevel@tonic-gate 				 : (ih)->ih_key.u.v2.k_type == V2_##type)
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate struct disk_child
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate   unsigned long       dc_block_number;              /* Disk child's block number. */
2287c478bd9Sstevel@tonic-gate   unsigned short      dc_size;		            /* Disk child's used space.   */
2297c478bd9Sstevel@tonic-gate };
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate #define DC_SIZE (sizeof (struct disk_child))
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /* Stat Data on disk.
2347c478bd9Sstevel@tonic-gate  *
2357c478bd9Sstevel@tonic-gate  * Note that reiserfs has two different forms of stat data.  Luckily
2367c478bd9Sstevel@tonic-gate  * the fields needed by grub are at the same position.
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate struct stat_data
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate   __u16 sd_mode;	/* file type, permissions */
2417c478bd9Sstevel@tonic-gate   __u16 sd_notused1[3]; /* fields not needed by reiserfs */
2427c478bd9Sstevel@tonic-gate   __u32 sd_size;	/* file size */
2437c478bd9Sstevel@tonic-gate   __u32 sd_size_hi;	/* file size high 32 bits (since version 2) */
2447c478bd9Sstevel@tonic-gate };
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate struct reiserfs_de_head
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate   __u32 deh_offset;  /* third component of the directory entry key */
2497c478bd9Sstevel@tonic-gate   __u32 deh_dir_id;  /* objectid of the parent directory of the
2507c478bd9Sstevel@tonic-gate 			object, that is referenced by directory entry */
2517c478bd9Sstevel@tonic-gate   __u32 deh_objectid;/* objectid of the object, that is referenced by
2527c478bd9Sstevel@tonic-gate                         directory entry */
2537c478bd9Sstevel@tonic-gate   __u16 deh_location;/* offset of name in the whole item */
2547c478bd9Sstevel@tonic-gate   __u16 deh_state;   /* whether 1) entry contains stat data (for
2557c478bd9Sstevel@tonic-gate 			future), and 2) whether entry is hidden
2567c478bd9Sstevel@tonic-gate 			(unlinked) */
2577c478bd9Sstevel@tonic-gate };
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate #define DEH_SIZE (sizeof (struct reiserfs_de_head))
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #define DEH_Statdata (1 << 0)			/* not used now */
2627c478bd9Sstevel@tonic-gate #define DEH_Visible  (1 << 2)
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate #define SD_OFFSET  0
2657c478bd9Sstevel@tonic-gate #define SD_UNIQUENESS 0
2667c478bd9Sstevel@tonic-gate #define DOT_OFFSET 1
2677c478bd9Sstevel@tonic-gate #define DOT_DOT_OFFSET 2
2687c478bd9Sstevel@tonic-gate #define DIRENTRY_UNIQUENESS 500
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate #define V1_TYPE_STAT_DATA 0x0
2717c478bd9Sstevel@tonic-gate #define V1_TYPE_DIRECT 0xffffffff
2727c478bd9Sstevel@tonic-gate #define V1_TYPE_INDIRECT 0xfffffffe
2737c478bd9Sstevel@tonic-gate #define V1_TYPE_DIRECTORY_MAX 0xfffffffd
2747c478bd9Sstevel@tonic-gate #define V2_TYPE_STAT_DATA 0
2757c478bd9Sstevel@tonic-gate #define V2_TYPE_INDIRECT 1
2767c478bd9Sstevel@tonic-gate #define V2_TYPE_DIRECT 2
2777c478bd9Sstevel@tonic-gate #define V2_TYPE_DIRENTRY 3
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate #define REISERFS_ROOT_OBJECTID 2
2807c478bd9Sstevel@tonic-gate #define REISERFS_ROOT_PARENT_OBJECTID 1
2817c478bd9Sstevel@tonic-gate #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
2827c478bd9Sstevel@tonic-gate /* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */
2837c478bd9Sstevel@tonic-gate #define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
2847c478bd9Sstevel@tonic-gate #define REISERFS_OLD_BLOCKSIZE 4096
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate #define S_ISREG(mode) (((mode) & 0170000) == 0100000)
2877c478bd9Sstevel@tonic-gate #define S_ISDIR(mode) (((mode) & 0170000) == 0040000)
2887c478bd9Sstevel@tonic-gate #define S_ISLNK(mode) (((mode) & 0170000) == 0120000)
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate #define PATH_MAX       1024	/* include/linux/limits.h */
2917c478bd9Sstevel@tonic-gate #define MAX_LINK_COUNT    5	/* number of symbolic links to follow */
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /* The size of the node cache */
2947c478bd9Sstevel@tonic-gate #define FSYSREISER_CACHE_SIZE 24*1024
2957c478bd9Sstevel@tonic-gate #define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE
2967c478bd9Sstevel@tonic-gate #define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate /* Info about currently opened file */
2997c478bd9Sstevel@tonic-gate struct fsys_reiser_fileinfo
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate   __u32 k_dir_id;
3027c478bd9Sstevel@tonic-gate   __u32 k_objectid;
3037c478bd9Sstevel@tonic-gate };
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /* In memory info about the currently mounted filesystem */
3067c478bd9Sstevel@tonic-gate struct fsys_reiser_info
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate   /* The last read item head */
3097c478bd9Sstevel@tonic-gate   struct item_head *current_ih;
3107c478bd9Sstevel@tonic-gate   /* The last read item */
3117c478bd9Sstevel@tonic-gate   char *current_item;
3127c478bd9Sstevel@tonic-gate   /* The information for the currently opened file */
3137c478bd9Sstevel@tonic-gate   struct fsys_reiser_fileinfo fileinfo;
3147c478bd9Sstevel@tonic-gate   /* The start of the journal */
3157c478bd9Sstevel@tonic-gate   __u32 journal_block;
3167c478bd9Sstevel@tonic-gate   /* The size of the journal */
3177c478bd9Sstevel@tonic-gate   __u32 journal_block_count;
3187c478bd9Sstevel@tonic-gate   /* The first valid descriptor block in journal
3197c478bd9Sstevel@tonic-gate      (relative to journal_block) */
3207c478bd9Sstevel@tonic-gate   __u32 journal_first_desc;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate   /* The ReiserFS version. */
3237c478bd9Sstevel@tonic-gate   __u16 version;
3247c478bd9Sstevel@tonic-gate   /* The current depth of the reiser tree. */
3257c478bd9Sstevel@tonic-gate   __u16 tree_depth;
3267c478bd9Sstevel@tonic-gate   /* SECTOR_SIZE << blocksize_shift == blocksize. */
3277c478bd9Sstevel@tonic-gate   __u8  blocksize_shift;
3287c478bd9Sstevel@tonic-gate   /* 1 << full_blocksize_shift == blocksize. */
3297c478bd9Sstevel@tonic-gate   __u8  fullblocksize_shift;
3307c478bd9Sstevel@tonic-gate   /* The reiserfs block size  (must be a power of 2) */
3317c478bd9Sstevel@tonic-gate   __u16 blocksize;
3327c478bd9Sstevel@tonic-gate   /* The number of cached tree nodes */
3337c478bd9Sstevel@tonic-gate   __u16 cached_slots;
3347c478bd9Sstevel@tonic-gate   /* The number of valid transactions in journal */
3357c478bd9Sstevel@tonic-gate   __u16 journal_transactions;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate   unsigned int blocks[MAX_HEIGHT];
3387c478bd9Sstevel@tonic-gate   unsigned int next_key_nr[MAX_HEIGHT];
3397c478bd9Sstevel@tonic-gate };
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate /* The cached s+tree blocks in FSYS_BUF,  see below
3427c478bd9Sstevel@tonic-gate  * for a more detailed description.
3437c478bd9Sstevel@tonic-gate  */
3447c478bd9Sstevel@tonic-gate #define ROOT     ((char *) ((int) FSYS_BUF))
3457c478bd9Sstevel@tonic-gate #define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift))
3467c478bd9Sstevel@tonic-gate #define LEAF     CACHE (DISK_LEAF_NODE_LEVEL)
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate #define BLOCKHEAD(cache) ((struct block_head *) cache)
3497c478bd9Sstevel@tonic-gate #define ITEMHEAD         ((struct item_head  *) ((int) LEAF + BLKH_SIZE))
3507c478bd9Sstevel@tonic-gate #define KEY(cache)       ((struct key        *) ((int) cache + BLKH_SIZE))
3517c478bd9Sstevel@tonic-gate #define DC(cache)        ((struct disk_child *) \
3527c478bd9Sstevel@tonic-gate 			  ((int) cache + BLKH_SIZE + KEY_SIZE * nr_item))
3537c478bd9Sstevel@tonic-gate /* The fsys_reiser_info block.
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate #define INFO \
3567c478bd9Sstevel@tonic-gate     ((struct fsys_reiser_info *) ((int) FSYS_BUF + FSYSREISER_CACHE_SIZE))
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * The journal cache.  For each transaction it contains the number of
3597c478bd9Sstevel@tonic-gate  * blocks followed by the real block numbers of this transaction.
3607c478bd9Sstevel@tonic-gate  *
3617c478bd9Sstevel@tonic-gate  * If the block numbers of some transaction won't fit in this space,
3627c478bd9Sstevel@tonic-gate  * this list is stopped with a 0xffffffff marker and the remaining
3637c478bd9Sstevel@tonic-gate  * uncommitted transactions aren't cached.
3647c478bd9Sstevel@tonic-gate  */
3657c478bd9Sstevel@tonic-gate #define JOURNAL_START    ((__u32 *) (INFO + 1))
3667c478bd9Sstevel@tonic-gate #define JOURNAL_END      ((__u32 *) (FSYS_BUF + FSYS_BUFLEN))
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static __inline__ unsigned long
grub_log2(unsigned long word)3707c478bd9Sstevel@tonic-gate grub_log2 (unsigned long word)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate   __asm__ ("bsfl %1,%0"
3737c478bd9Sstevel@tonic-gate 	   : "=r" (word)
3747c478bd9Sstevel@tonic-gate 	   : "r" (word));
3757c478bd9Sstevel@tonic-gate   return word;
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate #define log2 grub_log2
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate static __inline__ int
is_power_of_two(unsigned long word)3807c478bd9Sstevel@tonic-gate is_power_of_two (unsigned long word)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate   return (word & -word) == word;
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate static int
journal_read(int block,int len,char * buffer)3867c478bd9Sstevel@tonic-gate journal_read (int block, int len, char *buffer)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate   return devread ((INFO->journal_block + block) << INFO->blocksize_shift,
3897c478bd9Sstevel@tonic-gate 		  0, len, buffer);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /* Read a block from ReiserFS file system, taking the journal into
3937c478bd9Sstevel@tonic-gate  * account.  If the block nr is in the journal, the block from the
3947c478bd9Sstevel@tonic-gate  * journal taken.
3957c478bd9Sstevel@tonic-gate  */
3967c478bd9Sstevel@tonic-gate static int
block_read(int blockNr,int start,int len,char * buffer)3977c478bd9Sstevel@tonic-gate block_read (int blockNr, int start, int len, char *buffer)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate   int transactions = INFO->journal_transactions;
4007c478bd9Sstevel@tonic-gate   int desc_block = INFO->journal_first_desc;
4017c478bd9Sstevel@tonic-gate   int journal_mask = INFO->journal_block_count - 1;
4027c478bd9Sstevel@tonic-gate   int translatedNr = blockNr;
4037c478bd9Sstevel@tonic-gate   __u32 *journal_table = JOURNAL_START;
4047c478bd9Sstevel@tonic-gate   while (transactions-- > 0)
4057c478bd9Sstevel@tonic-gate     {
4067c478bd9Sstevel@tonic-gate       int i = 0;
4077c478bd9Sstevel@tonic-gate       int j_len;
4087c478bd9Sstevel@tonic-gate       if (*journal_table != 0xffffffff)
4097c478bd9Sstevel@tonic-gate 	{
4107c478bd9Sstevel@tonic-gate 	  /* Search for the blockNr in cached journal */
4117c478bd9Sstevel@tonic-gate 	  j_len = *journal_table++;
4127c478bd9Sstevel@tonic-gate 	  while (i++ < j_len)
4137c478bd9Sstevel@tonic-gate 	    {
4147c478bd9Sstevel@tonic-gate 	      if (*journal_table++ == blockNr)
4157c478bd9Sstevel@tonic-gate 		{
4167c478bd9Sstevel@tonic-gate 		  journal_table += j_len - i;
4177c478bd9Sstevel@tonic-gate 		  goto found;
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 	    }
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate       else
4227c478bd9Sstevel@tonic-gate 	{
4237c478bd9Sstevel@tonic-gate 	  /* This is the end of cached journal marker.  The remaining
4247c478bd9Sstevel@tonic-gate 	   * transactions are still on disk.
4257c478bd9Sstevel@tonic-gate 	   */
4267c478bd9Sstevel@tonic-gate 	  struct reiserfs_journal_desc   desc;
4277c478bd9Sstevel@tonic-gate 	  struct reiserfs_journal_commit commit;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	  if (! journal_read (desc_block, sizeof (desc), (char *) &desc))
4307c478bd9Sstevel@tonic-gate 	    return 0;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	  j_len = desc.j_len;
4337c478bd9Sstevel@tonic-gate 	  while (i < j_len && i < JOURNAL_TRANS_HALF)
4347c478bd9Sstevel@tonic-gate 	    if (desc.j_realblock[i++] == blockNr)
4357c478bd9Sstevel@tonic-gate 	      goto found;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	  if (j_len >= JOURNAL_TRANS_HALF)
4387c478bd9Sstevel@tonic-gate 	    {
4397c478bd9Sstevel@tonic-gate 	      int commit_block = (desc_block + 1 + j_len) & journal_mask;
4407c478bd9Sstevel@tonic-gate 	      if (! journal_read (commit_block,
4417c478bd9Sstevel@tonic-gate 				  sizeof (commit), (char *) &commit))
4427c478bd9Sstevel@tonic-gate 		return 0;
4437c478bd9Sstevel@tonic-gate 	      while (i < j_len)
4447c478bd9Sstevel@tonic-gate 		if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr)
4457c478bd9Sstevel@tonic-gate 		  goto found;
4467c478bd9Sstevel@tonic-gate 	    }
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate       goto not_found;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate     found:
4517c478bd9Sstevel@tonic-gate       translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask);
4527c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
4537c478bd9Sstevel@tonic-gate       printf ("block_read: block %d is mapped to journal block %d.\n",
4547c478bd9Sstevel@tonic-gate 	      blockNr, translatedNr - INFO->journal_block);
4557c478bd9Sstevel@tonic-gate #endif
4567c478bd9Sstevel@tonic-gate       /* We must continue the search, as this block may be overwritten
4577c478bd9Sstevel@tonic-gate        * in later transactions.
4587c478bd9Sstevel@tonic-gate        */
4597c478bd9Sstevel@tonic-gate     not_found:
4607c478bd9Sstevel@tonic-gate       desc_block = (desc_block + 2 + j_len) & journal_mask;
4617c478bd9Sstevel@tonic-gate     }
4627c478bd9Sstevel@tonic-gate   return devread (translatedNr << INFO->blocksize_shift, start, len, buffer);
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate /* Init the journal data structure.  We try to cache as much as
4667c478bd9Sstevel@tonic-gate  * possible in the JOURNAL_START-JOURNAL_END space, but if it is full
4677c478bd9Sstevel@tonic-gate  * we can still read the rest from the disk on demand.
4687c478bd9Sstevel@tonic-gate  *
4697c478bd9Sstevel@tonic-gate  * The first number of valid transactions and the descriptor block of the
4707c478bd9Sstevel@tonic-gate  * first valid transaction are held in INFO.  The transactions are all
4717c478bd9Sstevel@tonic-gate  * adjacent, but we must take care of the journal wrap around.
4727c478bd9Sstevel@tonic-gate  */
4737c478bd9Sstevel@tonic-gate static int
journal_init(void)4747c478bd9Sstevel@tonic-gate journal_init (void)
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate   unsigned int block_count = INFO->journal_block_count;
4777c478bd9Sstevel@tonic-gate   unsigned int desc_block;
4787c478bd9Sstevel@tonic-gate   unsigned int commit_block;
4797c478bd9Sstevel@tonic-gate   unsigned int next_trans_id;
4807c478bd9Sstevel@tonic-gate   struct reiserfs_journal_header header;
4817c478bd9Sstevel@tonic-gate   struct reiserfs_journal_desc   desc;
4827c478bd9Sstevel@tonic-gate   struct reiserfs_journal_commit commit;
4837c478bd9Sstevel@tonic-gate   __u32 *journal_table = JOURNAL_START;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate   journal_read (block_count, sizeof (header), (char *) &header);
4867c478bd9Sstevel@tonic-gate   desc_block = header.j_first_unflushed_offset;
4877c478bd9Sstevel@tonic-gate   if (desc_block >= block_count)
4887c478bd9Sstevel@tonic-gate     return 0;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate   INFO->journal_first_desc = desc_block;
4917c478bd9Sstevel@tonic-gate   next_trans_id = header.j_last_flush_trans_id + 1;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
4947c478bd9Sstevel@tonic-gate   printf ("journal_init: last flushed %d\n",
4957c478bd9Sstevel@tonic-gate 	  header.j_last_flush_trans_id);
4967c478bd9Sstevel@tonic-gate #endif
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate   while (1)
4997c478bd9Sstevel@tonic-gate     {
5007c478bd9Sstevel@tonic-gate       journal_read (desc_block, sizeof (desc), (char *) &desc);
5017c478bd9Sstevel@tonic-gate       if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0
5027c478bd9Sstevel@tonic-gate 	  || desc.j_trans_id != next_trans_id
5037c478bd9Sstevel@tonic-gate 	  || desc.j_mount_id != header.j_mount_id)
5047c478bd9Sstevel@tonic-gate 	/* no more valid transactions */
5057c478bd9Sstevel@tonic-gate 	break;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate       commit_block = (desc_block + desc.j_len + 1) & (block_count - 1);
5087c478bd9Sstevel@tonic-gate       journal_read (commit_block, sizeof (commit), (char *) &commit);
5097c478bd9Sstevel@tonic-gate       if (desc.j_trans_id != commit.j_trans_id
5107c478bd9Sstevel@tonic-gate 	  || desc.j_len != commit.j_len)
5117c478bd9Sstevel@tonic-gate 	/* no more valid transactions */
5127c478bd9Sstevel@tonic-gate 	break;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
5157c478bd9Sstevel@tonic-gate       printf ("Found valid transaction %d/%d at %d.\n",
5167c478bd9Sstevel@tonic-gate 	      desc.j_trans_id, desc.j_mount_id, desc_block);
5177c478bd9Sstevel@tonic-gate #endif
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate       next_trans_id++;
5207c478bd9Sstevel@tonic-gate       if (journal_table < JOURNAL_END)
5217c478bd9Sstevel@tonic-gate 	{
5227c478bd9Sstevel@tonic-gate 	  if ((journal_table + 1 + desc.j_len) >= JOURNAL_END)
5237c478bd9Sstevel@tonic-gate 	    {
5247c478bd9Sstevel@tonic-gate 	      /* The table is almost full; mark the end of the cached
5257c478bd9Sstevel@tonic-gate 	       * journal.*/
5267c478bd9Sstevel@tonic-gate 	      *journal_table = 0xffffffff;
5277c478bd9Sstevel@tonic-gate 	      journal_table = JOURNAL_END;
5287c478bd9Sstevel@tonic-gate 	    }
5297c478bd9Sstevel@tonic-gate 	  else
5307c478bd9Sstevel@tonic-gate 	    {
5317c478bd9Sstevel@tonic-gate 	      int i;
5327c478bd9Sstevel@tonic-gate 	      /* Cache the length and the realblock numbers in the table.
5337c478bd9Sstevel@tonic-gate 	       * The block number of descriptor can easily be computed.
5347c478bd9Sstevel@tonic-gate 	       * and need not to be stored here.
5357c478bd9Sstevel@tonic-gate 	       */
5367c478bd9Sstevel@tonic-gate 	      *journal_table++ = desc.j_len;
5377c478bd9Sstevel@tonic-gate 	      for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++)
5387c478bd9Sstevel@tonic-gate 		{
5397c478bd9Sstevel@tonic-gate 		  *journal_table++ = desc.j_realblock[i];
5407c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
5417c478bd9Sstevel@tonic-gate 		  printf ("block %d is in journal %d.\n",
5427c478bd9Sstevel@tonic-gate 			  desc.j_realblock[i], desc_block);
5437c478bd9Sstevel@tonic-gate #endif
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 	      for (     ; i < desc.j_len; i++)
5467c478bd9Sstevel@tonic-gate 		{
5477c478bd9Sstevel@tonic-gate 		  *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF];
5487c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
5497c478bd9Sstevel@tonic-gate 		  printf ("block %d is in journal %d.\n",
5507c478bd9Sstevel@tonic-gate 			  commit.j_realblock[i-JOURNAL_TRANS_HALF],
5517c478bd9Sstevel@tonic-gate 			  desc_block);
5527c478bd9Sstevel@tonic-gate #endif
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 	    }
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate       desc_block = (commit_block + 1) & (block_count - 1);
5577c478bd9Sstevel@tonic-gate     }
5587c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
5597c478bd9Sstevel@tonic-gate   printf ("Transaction %d/%d at %d isn't valid.\n",
5607c478bd9Sstevel@tonic-gate 	  desc.j_trans_id, desc.j_mount_id, desc_block);
5617c478bd9Sstevel@tonic-gate #endif
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate   INFO->journal_transactions
5647c478bd9Sstevel@tonic-gate     = next_trans_id - header.j_last_flush_trans_id - 1;
5657c478bd9Sstevel@tonic-gate   return errnum == 0;
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate /* check filesystem types and read superblock into memory buffer */
5697c478bd9Sstevel@tonic-gate int
reiserfs_mount(void)5707c478bd9Sstevel@tonic-gate reiserfs_mount (void)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate   struct reiserfs_super_block super;
5737c478bd9Sstevel@tonic-gate   int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate   if (part_length < superblock + (sizeof (super) >> SECTOR_BITS)
5767c478bd9Sstevel@tonic-gate       || ! devread (superblock, 0, sizeof (struct reiserfs_super_block),
5777c478bd9Sstevel@tonic-gate 		(char *) &super)
5787c478bd9Sstevel@tonic-gate       || (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
5797c478bd9Sstevel@tonic-gate 	  && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
5807c478bd9Sstevel@tonic-gate 	  && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
5817c478bd9Sstevel@tonic-gate       || (/* check that this is not a copy inside the journal log */
5827c478bd9Sstevel@tonic-gate 	  super.s_journal_block * super.s_blocksize
5837c478bd9Sstevel@tonic-gate 	  <= REISERFS_DISK_OFFSET_IN_BYTES))
5847c478bd9Sstevel@tonic-gate     {
5857c478bd9Sstevel@tonic-gate       /* Try old super block position */
5867c478bd9Sstevel@tonic-gate       superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
5877c478bd9Sstevel@tonic-gate       if (part_length < superblock + (sizeof (super) >> SECTOR_BITS)
5887c478bd9Sstevel@tonic-gate 	  || ! devread (superblock, 0, sizeof (struct reiserfs_super_block),
5897c478bd9Sstevel@tonic-gate 			(char *) &super))
5907c478bd9Sstevel@tonic-gate 	return 0;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate       if (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
5937c478bd9Sstevel@tonic-gate 	  && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
5947c478bd9Sstevel@tonic-gate 	  && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
5957c478bd9Sstevel@tonic-gate 	{
5967c478bd9Sstevel@tonic-gate 	  /* pre journaling super block ? */
5977c478bd9Sstevel@tonic-gate 	  if (substring (REISERFS_SUPER_MAGIC_STRING,
5987c478bd9Sstevel@tonic-gate 			 (char*) ((int) &super + 20)) > 0)
5997c478bd9Sstevel@tonic-gate 	    return 0;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	  super.s_blocksize = REISERFS_OLD_BLOCKSIZE;
6027c478bd9Sstevel@tonic-gate 	  super.s_journal_block = 0;
6037c478bd9Sstevel@tonic-gate 	  super.s_version = 0;
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate     }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate   /* check the version number.  */
6087c478bd9Sstevel@tonic-gate   if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION)
6097c478bd9Sstevel@tonic-gate     return 0;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate   INFO->version = super.s_version;
6127c478bd9Sstevel@tonic-gate   INFO->blocksize = super.s_blocksize;
6137c478bd9Sstevel@tonic-gate   INFO->fullblocksize_shift = log2 (super.s_blocksize);
6147c478bd9Sstevel@tonic-gate   INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS;
6157c478bd9Sstevel@tonic-gate   INFO->cached_slots =
6167c478bd9Sstevel@tonic-gate     (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
6197c478bd9Sstevel@tonic-gate   printf ("reiserfs_mount: version=%d, blocksize=%d\n",
6207c478bd9Sstevel@tonic-gate 	  INFO->version, INFO->blocksize);
6217c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate   /* Clear node cache. */
6247c478bd9Sstevel@tonic-gate   memset (INFO->blocks, 0, sizeof (INFO->blocks));
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate   if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE
6277c478bd9Sstevel@tonic-gate       || super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE
6287c478bd9Sstevel@tonic-gate       || (SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize)
6297c478bd9Sstevel@tonic-gate     return 0;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate   /* Initialize journal code.  If something fails we end with zero
6327c478bd9Sstevel@tonic-gate    * journal_transactions, so we don't access the journal at all.
6337c478bd9Sstevel@tonic-gate    */
6347c478bd9Sstevel@tonic-gate   INFO->journal_transactions = 0;
6357c478bd9Sstevel@tonic-gate   if (super.s_journal_block != 0 && super.s_journal_dev == 0)
6367c478bd9Sstevel@tonic-gate     {
6377c478bd9Sstevel@tonic-gate       INFO->journal_block = super.s_journal_block;
6387c478bd9Sstevel@tonic-gate       INFO->journal_block_count = super.s_journal_size;
6397c478bd9Sstevel@tonic-gate       if (is_power_of_two (INFO->journal_block_count))
6407c478bd9Sstevel@tonic-gate 	journal_init ();
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate       /* Read in super block again, maybe it is in the journal */
6437c478bd9Sstevel@tonic-gate       block_read (superblock >> INFO->blocksize_shift,
6447c478bd9Sstevel@tonic-gate 		  0, sizeof (struct reiserfs_super_block), (char *) &super);
6457c478bd9Sstevel@tonic-gate     }
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate   if (! block_read (super.s_root_block, 0, INFO->blocksize, (char*) ROOT))
6487c478bd9Sstevel@tonic-gate     return 0;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate   INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
6537c478bd9Sstevel@tonic-gate   printf ("root read_in: block=%d, depth=%d\n",
6547c478bd9Sstevel@tonic-gate 	  super.s_root_block, INFO->tree_depth);
6557c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate   if (INFO->tree_depth >= MAX_HEIGHT)
6587c478bd9Sstevel@tonic-gate     return 0;
6597c478bd9Sstevel@tonic-gate   if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL)
6607c478bd9Sstevel@tonic-gate     {
6617c478bd9Sstevel@tonic-gate       /* There is only one node in the whole filesystem,
6627c478bd9Sstevel@tonic-gate        * which is simultanously leaf and root */
6637c478bd9Sstevel@tonic-gate       memcpy (LEAF, ROOT, INFO->blocksize);
6647c478bd9Sstevel@tonic-gate     }
6657c478bd9Sstevel@tonic-gate   return 1;
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate /***************** TREE ACCESSING METHODS *****************************/
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /* I assume you are familiar with the ReiserFS tree, if not go to
6717c478bd9Sstevel@tonic-gate  * http://www.namesys.com/content_table.html
6727c478bd9Sstevel@tonic-gate  *
6737c478bd9Sstevel@tonic-gate  * My tree node cache is organized as following
6747c478bd9Sstevel@tonic-gate  *   0   ROOT node
6757c478bd9Sstevel@tonic-gate  *   1   LEAF node  (if the ROOT is also a LEAF it is copied here
6767c478bd9Sstevel@tonic-gate  *   2-n other nodes on current path from bottom to top.
6777c478bd9Sstevel@tonic-gate  *       if there is not enough space in the cache, the top most are
6787c478bd9Sstevel@tonic-gate  *       omitted.
6797c478bd9Sstevel@tonic-gate  *
6807c478bd9Sstevel@tonic-gate  * I have only two methods to find a key in the tree:
6817c478bd9Sstevel@tonic-gate  *   search_stat(dir_id, objectid) searches for the stat entry (always
6827c478bd9Sstevel@tonic-gate  *       the first entry) of an object.
6837c478bd9Sstevel@tonic-gate  *   next_key() gets the next key in tree order.
6847c478bd9Sstevel@tonic-gate  *
6857c478bd9Sstevel@tonic-gate  * This means, that I can only sequential reads of files are
6867c478bd9Sstevel@tonic-gate  * efficient, but this really doesn't hurt for grub.
6877c478bd9Sstevel@tonic-gate  */
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate /* Read in the node at the current path and depth into the node cache.
6907c478bd9Sstevel@tonic-gate  * You must set INFO->blocks[depth] before.
6917c478bd9Sstevel@tonic-gate  */
6927c478bd9Sstevel@tonic-gate static char *
read_tree_node(unsigned int blockNr,int depth)6937c478bd9Sstevel@tonic-gate read_tree_node (unsigned int blockNr, int depth)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate   char* cache = CACHE(depth);
6967c478bd9Sstevel@tonic-gate   int num_cached = INFO->cached_slots;
6977c478bd9Sstevel@tonic-gate   if (depth < num_cached)
6987c478bd9Sstevel@tonic-gate     {
6997c478bd9Sstevel@tonic-gate       /* This is the cached part of the path.  Check if same block is
7007c478bd9Sstevel@tonic-gate        * needed.
7017c478bd9Sstevel@tonic-gate        */
7027c478bd9Sstevel@tonic-gate       if (blockNr == INFO->blocks[depth])
7037c478bd9Sstevel@tonic-gate 	return cache;
7047c478bd9Sstevel@tonic-gate     }
7057c478bd9Sstevel@tonic-gate   else
7067c478bd9Sstevel@tonic-gate     cache = CACHE(num_cached);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
7097c478bd9Sstevel@tonic-gate   printf ("  next read_in: block=%d (depth=%d)\n",
7107c478bd9Sstevel@tonic-gate 	  blockNr, depth);
7117c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
7127c478bd9Sstevel@tonic-gate   if (! block_read (blockNr, 0, INFO->blocksize, cache))
7137c478bd9Sstevel@tonic-gate     return 0;
7147c478bd9Sstevel@tonic-gate   /* Make sure it has the right node level */
7157c478bd9Sstevel@tonic-gate   if (BLOCKHEAD (cache)->blk_level != depth)
7167c478bd9Sstevel@tonic-gate     {
7177c478bd9Sstevel@tonic-gate       errnum = ERR_FSYS_CORRUPT;
7187c478bd9Sstevel@tonic-gate       return 0;
7197c478bd9Sstevel@tonic-gate     }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate   INFO->blocks[depth] = blockNr;
7227c478bd9Sstevel@tonic-gate   return cache;
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate /* Get the next key, i.e. the key following the last retrieved key in
7267c478bd9Sstevel@tonic-gate  * tree order.  INFO->current_ih and
7277c478bd9Sstevel@tonic-gate  * INFO->current_info are adapted accordingly.  */
7287c478bd9Sstevel@tonic-gate static int
next_key(void)7297c478bd9Sstevel@tonic-gate next_key (void)
7307c478bd9Sstevel@tonic-gate {
7317c478bd9Sstevel@tonic-gate   int depth;
7327c478bd9Sstevel@tonic-gate   struct item_head *ih = INFO->current_ih + 1;
7337c478bd9Sstevel@tonic-gate   char *cache;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
7367c478bd9Sstevel@tonic-gate   printf ("next_key:\n  old ih: key %d:%d:%d:%d version:%d\n",
7377c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.k_dir_id,
7387c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.k_objectid,
7397c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.u.v1.k_offset,
7407c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.u.v1.k_uniqueness,
7417c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_version);
7427c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate   if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item])
7457c478bd9Sstevel@tonic-gate     {
7467c478bd9Sstevel@tonic-gate       depth = DISK_LEAF_NODE_LEVEL;
7477c478bd9Sstevel@tonic-gate       /* The last item, was the last in the leaf node.
7487c478bd9Sstevel@tonic-gate        * Read in the next block
7497c478bd9Sstevel@tonic-gate        */
7507c478bd9Sstevel@tonic-gate       do
7517c478bd9Sstevel@tonic-gate 	{
7527c478bd9Sstevel@tonic-gate 	  if (depth == INFO->tree_depth)
7537c478bd9Sstevel@tonic-gate 	    {
7547c478bd9Sstevel@tonic-gate 	      /* There are no more keys at all.
7557c478bd9Sstevel@tonic-gate 	       * Return a dummy item with MAX_KEY */
7567c478bd9Sstevel@tonic-gate 	      ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key;
7577c478bd9Sstevel@tonic-gate 	      goto found;
7587c478bd9Sstevel@tonic-gate 	    }
7597c478bd9Sstevel@tonic-gate 	  depth++;
7607c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
7617c478bd9Sstevel@tonic-gate 	  printf ("  depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]);
7627c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate       while (INFO->next_key_nr[depth] == 0);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate       if (depth == INFO->tree_depth)
7677c478bd9Sstevel@tonic-gate 	cache = ROOT;
7687c478bd9Sstevel@tonic-gate       else if (depth <= INFO->cached_slots)
7697c478bd9Sstevel@tonic-gate 	cache = CACHE (depth);
7707c478bd9Sstevel@tonic-gate       else
7717c478bd9Sstevel@tonic-gate 	{
7727c478bd9Sstevel@tonic-gate 	  cache = read_tree_node (INFO->blocks[depth], depth);
7737c478bd9Sstevel@tonic-gate 	  if (! cache)
7747c478bd9Sstevel@tonic-gate 	    return 0;
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate       do
7787c478bd9Sstevel@tonic-gate 	{
7797c478bd9Sstevel@tonic-gate 	  int nr_item = BLOCKHEAD (cache)->blk_nr_item;
7807c478bd9Sstevel@tonic-gate 	  int key_nr = INFO->next_key_nr[depth]++;
7817c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
7827c478bd9Sstevel@tonic-gate 	  printf ("  depth=%d, i=%d/%d\n", depth, key_nr, nr_item);
7837c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
7847c478bd9Sstevel@tonic-gate 	  if (key_nr == nr_item)
7857c478bd9Sstevel@tonic-gate 	    /* This is the last item in this block, set the next_key_nr to 0 */
7867c478bd9Sstevel@tonic-gate 	    INFO->next_key_nr[depth] = 0;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	  cache = read_tree_node (DC (cache)[key_nr].dc_block_number, --depth);
7897c478bd9Sstevel@tonic-gate 	  if (! cache)
7907c478bd9Sstevel@tonic-gate 	    return 0;
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate       while (depth > DISK_LEAF_NODE_LEVEL);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate       ih = ITEMHEAD;
7957c478bd9Sstevel@tonic-gate     }
7967c478bd9Sstevel@tonic-gate  found:
7977c478bd9Sstevel@tonic-gate   INFO->current_ih   = ih;
7987c478bd9Sstevel@tonic-gate   INFO->current_item = &LEAF[ih->ih_item_location];
7997c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
8007c478bd9Sstevel@tonic-gate   printf ("  new ih: key %d:%d:%d:%d version:%d\n",
8017c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.k_dir_id,
8027c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.k_objectid,
8037c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.u.v1.k_offset,
8047c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_key.u.v1.k_uniqueness,
8057c478bd9Sstevel@tonic-gate 	  INFO->current_ih->ih_version);
8067c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
8077c478bd9Sstevel@tonic-gate   return 1;
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /* preconditions: reiserfs_mount already executed, therefore
8117c478bd9Sstevel@tonic-gate  *   INFO block is valid
8127c478bd9Sstevel@tonic-gate  * returns: 0 if error (errnum is set),
8137c478bd9Sstevel@tonic-gate  *   nonzero iff we were able to find the key successfully.
8147c478bd9Sstevel@tonic-gate  * postconditions: on a nonzero return, the current_ih and
8157c478bd9Sstevel@tonic-gate  *   current_item fields describe the key that equals the
8167c478bd9Sstevel@tonic-gate  *   searched key.  INFO->next_key contains the next key after
8177c478bd9Sstevel@tonic-gate  *   the searched key.
8187c478bd9Sstevel@tonic-gate  * side effects: messes around with the cache.
8197c478bd9Sstevel@tonic-gate  */
8207c478bd9Sstevel@tonic-gate static int
search_stat(__u32 dir_id,__u32 objectid)8217c478bd9Sstevel@tonic-gate search_stat (__u32 dir_id, __u32 objectid)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate   char *cache;
8247c478bd9Sstevel@tonic-gate   int depth;
8257c478bd9Sstevel@tonic-gate   int nr_item;
8267c478bd9Sstevel@tonic-gate   int i;
8277c478bd9Sstevel@tonic-gate   struct item_head *ih;
8287c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
8297c478bd9Sstevel@tonic-gate   printf ("search_stat:\n  key %d:%d:0:0\n", dir_id, objectid);
8307c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate   depth = INFO->tree_depth;
8337c478bd9Sstevel@tonic-gate   cache = ROOT;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate   while (depth > DISK_LEAF_NODE_LEVEL)
8367c478bd9Sstevel@tonic-gate     {
8377c478bd9Sstevel@tonic-gate       struct key *key;
8387c478bd9Sstevel@tonic-gate       nr_item = BLOCKHEAD (cache)->blk_nr_item;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate       key = KEY (cache);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate       for (i = 0; i < nr_item; i++)
8437c478bd9Sstevel@tonic-gate 	{
8447c478bd9Sstevel@tonic-gate 	  if (key->k_dir_id > dir_id
8457c478bd9Sstevel@tonic-gate 	      || (key->k_dir_id == dir_id
8467c478bd9Sstevel@tonic-gate 		  && (key->k_objectid > objectid
8477c478bd9Sstevel@tonic-gate 		      || (key->k_objectid == objectid
8487c478bd9Sstevel@tonic-gate 			  && (key->u.v1.k_offset
8497c478bd9Sstevel@tonic-gate 			      | key->u.v1.k_uniqueness) > 0))))
8507c478bd9Sstevel@tonic-gate 	    break;
8517c478bd9Sstevel@tonic-gate 	  key++;
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
8557c478bd9Sstevel@tonic-gate       printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item);
8567c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
8577c478bd9Sstevel@tonic-gate       INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1;
8587c478bd9Sstevel@tonic-gate       cache = read_tree_node (DC (cache)[i].dc_block_number, --depth);
8597c478bd9Sstevel@tonic-gate       if (! cache)
8607c478bd9Sstevel@tonic-gate 	return 0;
8617c478bd9Sstevel@tonic-gate     }
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate   /* cache == LEAF */
8647c478bd9Sstevel@tonic-gate   nr_item = BLOCKHEAD (LEAF)->blk_nr_item;
8657c478bd9Sstevel@tonic-gate   ih = ITEMHEAD;
8667c478bd9Sstevel@tonic-gate   for (i = 0; i < nr_item; i++)
8677c478bd9Sstevel@tonic-gate     {
8687c478bd9Sstevel@tonic-gate       if (ih->ih_key.k_dir_id == dir_id
8697c478bd9Sstevel@tonic-gate 	  && ih->ih_key.k_objectid == objectid
8707c478bd9Sstevel@tonic-gate 	  && ih->ih_key.u.v1.k_offset == 0
8717c478bd9Sstevel@tonic-gate 	  && ih->ih_key.u.v1.k_uniqueness == 0)
8727c478bd9Sstevel@tonic-gate 	{
8737c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
8747c478bd9Sstevel@tonic-gate 	  printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item);
8757c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
8767c478bd9Sstevel@tonic-gate 	  INFO->current_ih   = ih;
8777c478bd9Sstevel@tonic-gate 	  INFO->current_item = &LEAF[ih->ih_item_location];
8787c478bd9Sstevel@tonic-gate 	  return 1;
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate       ih++;
8817c478bd9Sstevel@tonic-gate     }
8827c478bd9Sstevel@tonic-gate   errnum = ERR_FSYS_CORRUPT;
8837c478bd9Sstevel@tonic-gate   return 0;
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate int
reiserfs_read(char * buf,int len)8877c478bd9Sstevel@tonic-gate reiserfs_read (char *buf, int len)
8887c478bd9Sstevel@tonic-gate {
8897c478bd9Sstevel@tonic-gate   unsigned int blocksize;
8907c478bd9Sstevel@tonic-gate   unsigned int offset;
8917c478bd9Sstevel@tonic-gate   unsigned int to_read;
8927c478bd9Sstevel@tonic-gate   char *prev_buf = buf;
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
8957c478bd9Sstevel@tonic-gate   printf ("reiserfs_read: filepos=%d len=%d, offset=%x:%x\n",
8967c478bd9Sstevel@tonic-gate 	  filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1);
8977c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate   if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid
9007c478bd9Sstevel@tonic-gate       || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1)
9017c478bd9Sstevel@tonic-gate     {
9027c478bd9Sstevel@tonic-gate       search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid);
9037c478bd9Sstevel@tonic-gate       goto get_next_key;
9047c478bd9Sstevel@tonic-gate     }
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate   while (! errnum)
9077c478bd9Sstevel@tonic-gate     {
9087c478bd9Sstevel@tonic-gate       if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid)
9097c478bd9Sstevel@tonic-gate 	break;
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate       offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1;
9127c478bd9Sstevel@tonic-gate       blocksize = INFO->current_ih->ih_item_len;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
9157c478bd9Sstevel@tonic-gate       printf ("  loop: filepos=%d len=%d, offset=%d blocksize=%d\n",
9167c478bd9Sstevel@tonic-gate 	      filepos, len, offset, blocksize);
9177c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate       if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT)
9207c478bd9Sstevel@tonic-gate 	  && offset < blocksize)
9217c478bd9Sstevel@tonic-gate 	{
9227c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
9237c478bd9Sstevel@tonic-gate 	  printf ("direct_read: offset=%d, blocksize=%d\n",
9247c478bd9Sstevel@tonic-gate 		  offset, blocksize);
9257c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
9267c478bd9Sstevel@tonic-gate 	  to_read = blocksize - offset;
9277c478bd9Sstevel@tonic-gate 	  if (to_read > len)
9287c478bd9Sstevel@tonic-gate 	    to_read = len;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	  if (disk_read_hook != NULL)
9317c478bd9Sstevel@tonic-gate 	    {
9327c478bd9Sstevel@tonic-gate 	      disk_read_func = disk_read_hook;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	      block_read (INFO->blocks[DISK_LEAF_NODE_LEVEL],
9357c478bd9Sstevel@tonic-gate 			  (INFO->current_item - LEAF + offset), to_read, buf);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	      disk_read_func = NULL;
9387c478bd9Sstevel@tonic-gate 	    }
9397c478bd9Sstevel@tonic-gate 	  else
9407c478bd9Sstevel@tonic-gate 	    memcpy (buf, INFO->current_item + offset, to_read);
9417c478bd9Sstevel@tonic-gate 	  goto update_buf_len;
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate       else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT))
9447c478bd9Sstevel@tonic-gate 	{
9457c478bd9Sstevel@tonic-gate 	  blocksize = (blocksize >> 2) << INFO->fullblocksize_shift;
9467c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
9477c478bd9Sstevel@tonic-gate 	  printf ("indirect_read: offset=%d, blocksize=%d\n",
9487c478bd9Sstevel@tonic-gate 		  offset, blocksize);
9497c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	  while (offset < blocksize)
9527c478bd9Sstevel@tonic-gate 	    {
9537c478bd9Sstevel@tonic-gate 	      __u32 blocknr = ((__u32 *) INFO->current_item)
9547c478bd9Sstevel@tonic-gate 		[offset >> INFO->fullblocksize_shift];
9557c478bd9Sstevel@tonic-gate 	      int blk_offset = offset & (INFO->blocksize-1);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	      to_read = INFO->blocksize - blk_offset;
9587c478bd9Sstevel@tonic-gate 	      if (to_read > len)
9597c478bd9Sstevel@tonic-gate 		to_read = len;
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	      disk_read_func = disk_read_hook;
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	      /* Journal is only for meta data.  Data blocks can be read
9647c478bd9Sstevel@tonic-gate 	       * directly without using block_read
9657c478bd9Sstevel@tonic-gate 	       */
9667c478bd9Sstevel@tonic-gate 	      devread (blocknr << INFO->blocksize_shift,
9677c478bd9Sstevel@tonic-gate 		       blk_offset, to_read, buf);
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	      disk_read_func = NULL;
9707c478bd9Sstevel@tonic-gate 	    update_buf_len:
9717c478bd9Sstevel@tonic-gate 	      len -= to_read;
9727c478bd9Sstevel@tonic-gate 	      buf += to_read;
9737c478bd9Sstevel@tonic-gate 	      offset += to_read;
9747c478bd9Sstevel@tonic-gate 	      filepos += to_read;
9757c478bd9Sstevel@tonic-gate 	      if (len == 0)
9767c478bd9Sstevel@tonic-gate 		goto done;
9777c478bd9Sstevel@tonic-gate 	    }
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate     get_next_key:
9807c478bd9Sstevel@tonic-gate       next_key ();
9817c478bd9Sstevel@tonic-gate     }
9827c478bd9Sstevel@tonic-gate  done:
9837c478bd9Sstevel@tonic-gate   return errnum ? 0 : buf - prev_buf;
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate /* preconditions: reiserfs_mount already executed, therefore
9887c478bd9Sstevel@tonic-gate  *   INFO block is valid
9897c478bd9Sstevel@tonic-gate  * returns: 0 if error, nonzero iff we were able to find the file successfully
9907c478bd9Sstevel@tonic-gate  * postconditions: on a nonzero return, INFO->fileinfo contains the info
9917c478bd9Sstevel@tonic-gate  *   of the file we were trying to look up, filepos is 0 and filemax is
9927c478bd9Sstevel@tonic-gate  *   the size of the file.
9937c478bd9Sstevel@tonic-gate  */
9947c478bd9Sstevel@tonic-gate int
reiserfs_dir(char * dirname)9957c478bd9Sstevel@tonic-gate reiserfs_dir (char *dirname)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate   struct reiserfs_de_head *de_head;
9987c478bd9Sstevel@tonic-gate   char *rest, ch;
9997c478bd9Sstevel@tonic-gate   __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0;
10007c478bd9Sstevel@tonic-gate #ifndef STAGE1_5
10017c478bd9Sstevel@tonic-gate   int do_possibilities = 0;
10027c478bd9Sstevel@tonic-gate #endif /* ! STAGE1_5 */
10037c478bd9Sstevel@tonic-gate   char linkbuf[PATH_MAX];	/* buffer for following symbolic links */
10047c478bd9Sstevel@tonic-gate   int link_count = 0;
10057c478bd9Sstevel@tonic-gate   int mode;
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate   dir_id = REISERFS_ROOT_PARENT_OBJECTID;
10087c478bd9Sstevel@tonic-gate   objectid = REISERFS_ROOT_OBJECTID;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate   while (1)
10117c478bd9Sstevel@tonic-gate     {
10127c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
10137c478bd9Sstevel@tonic-gate       printf ("dirname=%s\n", dirname);
10147c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate       /* Search for the stat info first. */
10177c478bd9Sstevel@tonic-gate       if (! search_stat (dir_id, objectid))
10187c478bd9Sstevel@tonic-gate 	return 0;
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
10217c478bd9Sstevel@tonic-gate       printf ("sd_mode=%x sd_size=%d\n",
10227c478bd9Sstevel@tonic-gate 	      ((struct stat_data *) INFO->current_item)->sd_mode,
10237c478bd9Sstevel@tonic-gate 	      ((struct stat_data *) INFO->current_item)->sd_size);
10247c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate       mode = ((struct stat_data *) INFO->current_item)->sd_mode;
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate       /* If we've got a symbolic link, then chase it. */
10297c478bd9Sstevel@tonic-gate       if (S_ISLNK (mode))
10307c478bd9Sstevel@tonic-gate 	{
10317c478bd9Sstevel@tonic-gate 	  int len;
10327c478bd9Sstevel@tonic-gate 	  if (++link_count > MAX_LINK_COUNT)
10337c478bd9Sstevel@tonic-gate 	    {
10347c478bd9Sstevel@tonic-gate 	      errnum = ERR_SYMLINK_LOOP;
10357c478bd9Sstevel@tonic-gate 	      return 0;
10367c478bd9Sstevel@tonic-gate 	    }
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	  /* Get the symlink size. */
10397c478bd9Sstevel@tonic-gate 	  filemax = ((struct stat_data *) INFO->current_item)->sd_size;
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	  /* Find out how long our remaining name is. */
10427c478bd9Sstevel@tonic-gate 	  len = 0;
10437c478bd9Sstevel@tonic-gate 	  while (dirname[len] && !isspace (dirname[len]))
10447c478bd9Sstevel@tonic-gate 	    len++;
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	  if (filemax + len > sizeof (linkbuf) - 1)
10477c478bd9Sstevel@tonic-gate 	    {
10487c478bd9Sstevel@tonic-gate 	      errnum = ERR_FILELENGTH;
10497c478bd9Sstevel@tonic-gate 	      return 0;
10507c478bd9Sstevel@tonic-gate 	    }
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	  /* Copy the remaining name to the end of the symlink data.
10537c478bd9Sstevel@tonic-gate 	     Note that DIRNAME and LINKBUF may overlap! */
10547c478bd9Sstevel@tonic-gate 	  grub_memmove (linkbuf + filemax, dirname, len+1);
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	  INFO->fileinfo.k_dir_id = dir_id;
10577c478bd9Sstevel@tonic-gate 	  INFO->fileinfo.k_objectid = objectid;
10587c478bd9Sstevel@tonic-gate   	  filepos = 0;
10597c478bd9Sstevel@tonic-gate 	  if (! next_key ()
10607c478bd9Sstevel@tonic-gate 	      || reiserfs_read (linkbuf, filemax) != filemax)
10617c478bd9Sstevel@tonic-gate 	    {
10627c478bd9Sstevel@tonic-gate 	      if (! errnum)
10637c478bd9Sstevel@tonic-gate 		errnum = ERR_FSYS_CORRUPT;
10647c478bd9Sstevel@tonic-gate 	      return 0;
10657c478bd9Sstevel@tonic-gate 	    }
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
10687c478bd9Sstevel@tonic-gate 	  printf ("symlink=%s\n", linkbuf);
10697c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	  dirname = linkbuf;
10727c478bd9Sstevel@tonic-gate 	  if (*dirname == '/')
10737c478bd9Sstevel@tonic-gate 	    {
10747c478bd9Sstevel@tonic-gate 	      /* It's an absolute link, so look it up in root. */
10757c478bd9Sstevel@tonic-gate 	      dir_id = REISERFS_ROOT_PARENT_OBJECTID;
10767c478bd9Sstevel@tonic-gate 	      objectid = REISERFS_ROOT_OBJECTID;
10777c478bd9Sstevel@tonic-gate 	    }
10787c478bd9Sstevel@tonic-gate 	  else
10797c478bd9Sstevel@tonic-gate 	    {
10807c478bd9Sstevel@tonic-gate 	      /* Relative, so look it up in our parent directory. */
10817c478bd9Sstevel@tonic-gate 	      dir_id   = parent_dir_id;
10827c478bd9Sstevel@tonic-gate 	      objectid = parent_objectid;
10837c478bd9Sstevel@tonic-gate 	    }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	  /* Now lookup the new name. */
10867c478bd9Sstevel@tonic-gate 	  continue;
10877c478bd9Sstevel@tonic-gate 	}
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate       /* if we have a real file (and we're not just printing possibilities),
10907c478bd9Sstevel@tonic-gate 	 then this is where we want to exit */
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate       if (! *dirname || isspace (*dirname))
10937c478bd9Sstevel@tonic-gate 	{
10947c478bd9Sstevel@tonic-gate 	  if (! S_ISREG (mode))
10957c478bd9Sstevel@tonic-gate 	    {
10967c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_FILETYPE;
10977c478bd9Sstevel@tonic-gate 	      return 0;
10987c478bd9Sstevel@tonic-gate 	    }
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	  filepos = 0;
11017c478bd9Sstevel@tonic-gate 	  filemax = ((struct stat_data *) INFO->current_item)->sd_size;
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	  /* If this is a new stat data and size is > 4GB set filemax to
11047c478bd9Sstevel@tonic-gate 	   * maximum
11057c478bd9Sstevel@tonic-gate 	   */
11067c478bd9Sstevel@tonic-gate 	  if (INFO->current_ih->ih_version == ITEM_VERSION_2
11077c478bd9Sstevel@tonic-gate 	      && ((struct stat_data *) INFO->current_item)->sd_size_hi > 0)
11087c478bd9Sstevel@tonic-gate 	    filemax = 0xffffffff;
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	  INFO->fileinfo.k_dir_id = dir_id;
11117c478bd9Sstevel@tonic-gate 	  INFO->fileinfo.k_objectid = objectid;
11127c478bd9Sstevel@tonic-gate 	  return next_key ();
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate       /* continue with the file/directory name interpretation */
11167c478bd9Sstevel@tonic-gate       while (*dirname == '/')
11177c478bd9Sstevel@tonic-gate 	dirname++;
11187c478bd9Sstevel@tonic-gate       if (! S_ISDIR (mode))
11197c478bd9Sstevel@tonic-gate 	{
11207c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_FILETYPE;
11217c478bd9Sstevel@tonic-gate 	  return 0;
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate       for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++);
11247c478bd9Sstevel@tonic-gate       *rest = 0;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate # ifndef STAGE1_5
11277c478bd9Sstevel@tonic-gate       if (print_possibilities && ch != '/')
11287c478bd9Sstevel@tonic-gate 	do_possibilities = 1;
11297c478bd9Sstevel@tonic-gate # endif /* ! STAGE1_5 */
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate       while (1)
11327c478bd9Sstevel@tonic-gate 	{
11337c478bd9Sstevel@tonic-gate 	  char *name_end;
11347c478bd9Sstevel@tonic-gate 	  int num_entries;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	  if (! next_key ())
11377c478bd9Sstevel@tonic-gate 	    return 0;
11387c478bd9Sstevel@tonic-gate #ifdef REISERDEBUG
11397c478bd9Sstevel@tonic-gate 	  printf ("ih: key %d:%d:%d:%d version:%d\n",
11407c478bd9Sstevel@tonic-gate 		  INFO->current_ih->ih_key.k_dir_id,
11417c478bd9Sstevel@tonic-gate 		  INFO->current_ih->ih_key.k_objectid,
11427c478bd9Sstevel@tonic-gate 		  INFO->current_ih->ih_key.u.v1.k_offset,
11437c478bd9Sstevel@tonic-gate 		  INFO->current_ih->ih_key.u.v1.k_uniqueness,
11447c478bd9Sstevel@tonic-gate 		  INFO->current_ih->ih_version);
11457c478bd9Sstevel@tonic-gate #endif /* REISERDEBUG */
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	  if (INFO->current_ih->ih_key.k_objectid != objectid)
11487c478bd9Sstevel@tonic-gate 	    break;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	  name_end = INFO->current_item + INFO->current_ih->ih_item_len;
11517c478bd9Sstevel@tonic-gate 	  de_head = (struct reiserfs_de_head *) INFO->current_item;
11527c478bd9Sstevel@tonic-gate 	  num_entries = INFO->current_ih->u.ih_entry_count;
11537c478bd9Sstevel@tonic-gate 	  while (num_entries > 0)
11547c478bd9Sstevel@tonic-gate 	    {
11557c478bd9Sstevel@tonic-gate 	      char *filename = INFO->current_item + de_head->deh_location;
11567c478bd9Sstevel@tonic-gate 	      char  tmp = *name_end;
11577c478bd9Sstevel@tonic-gate 	      if ((de_head->deh_state & DEH_Visible))
11587c478bd9Sstevel@tonic-gate 		{
11597c478bd9Sstevel@tonic-gate 		  int cmp;
11607c478bd9Sstevel@tonic-gate 		  /* Directory names in ReiserFS are not null
11617c478bd9Sstevel@tonic-gate 		   * terminated.  We write a temporary 0 behind it.
11627c478bd9Sstevel@tonic-gate 		   * NOTE: that this may overwrite the first block in
11637c478bd9Sstevel@tonic-gate 		   * the tree cache.  That doesn't hurt as long as we
11647c478bd9Sstevel@tonic-gate 		   * don't call next_key () in between.
11657c478bd9Sstevel@tonic-gate 		   */
11667c478bd9Sstevel@tonic-gate 		  *name_end = 0;
11677c478bd9Sstevel@tonic-gate 		  cmp = substring (dirname, filename);
11687c478bd9Sstevel@tonic-gate 		  *name_end = tmp;
11697c478bd9Sstevel@tonic-gate # ifndef STAGE1_5
11707c478bd9Sstevel@tonic-gate 		  if (do_possibilities)
11717c478bd9Sstevel@tonic-gate 		    {
11727c478bd9Sstevel@tonic-gate 		      if (cmp <= 0)
11737c478bd9Sstevel@tonic-gate 			{
11747c478bd9Sstevel@tonic-gate 			  if (print_possibilities > 0)
11757c478bd9Sstevel@tonic-gate 			    print_possibilities = -print_possibilities;
11767c478bd9Sstevel@tonic-gate 			  *name_end = 0;
11777c478bd9Sstevel@tonic-gate 			  print_a_completion (filename);
11787c478bd9Sstevel@tonic-gate 			  *name_end = tmp;
11797c478bd9Sstevel@tonic-gate 			}
11807c478bd9Sstevel@tonic-gate 		    }
11817c478bd9Sstevel@tonic-gate 		  else
11827c478bd9Sstevel@tonic-gate # endif /* ! STAGE1_5 */
11837c478bd9Sstevel@tonic-gate 		    if (cmp == 0)
11847c478bd9Sstevel@tonic-gate 		      goto found;
11857c478bd9Sstevel@tonic-gate 		}
11867c478bd9Sstevel@tonic-gate 	      /* The beginning of this name marks the end of the next name.
11877c478bd9Sstevel@tonic-gate 	       */
11887c478bd9Sstevel@tonic-gate 	      name_end = filename;
11897c478bd9Sstevel@tonic-gate 	      de_head++;
11907c478bd9Sstevel@tonic-gate 	      num_entries--;
11917c478bd9Sstevel@tonic-gate 	    }
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate # ifndef STAGE1_5
11957c478bd9Sstevel@tonic-gate       if (print_possibilities < 0)
11967c478bd9Sstevel@tonic-gate 	return 1;
11977c478bd9Sstevel@tonic-gate # endif /* ! STAGE1_5 */
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate       errnum = ERR_FILE_NOT_FOUND;
12007c478bd9Sstevel@tonic-gate       *rest = ch;
12017c478bd9Sstevel@tonic-gate       return 0;
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate     found:
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate       *rest = ch;
12067c478bd9Sstevel@tonic-gate       dirname = rest;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate       parent_dir_id = dir_id;
12097c478bd9Sstevel@tonic-gate       parent_objectid = objectid;
12107c478bd9Sstevel@tonic-gate       dir_id = de_head->deh_dir_id;
12117c478bd9Sstevel@tonic-gate       objectid = de_head->deh_objectid;
12127c478bd9Sstevel@tonic-gate     }
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate int
reiserfs_embed(unsigned long long * start_sector,int needed_sectors)1216*2e1aefd1SJoshua M. Clulow reiserfs_embed (unsigned long long *start_sector, int needed_sectors)
12177c478bd9Sstevel@tonic-gate {
12187c478bd9Sstevel@tonic-gate   struct reiserfs_super_block super;
12197c478bd9Sstevel@tonic-gate   int num_sectors;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate   if (! devread (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS, 0,
12227c478bd9Sstevel@tonic-gate 		 sizeof (struct reiserfs_super_block), (char *) &super))
12237c478bd9Sstevel@tonic-gate     return 0;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate   *start_sector = 1; /* reserve first sector for stage1 */
12267c478bd9Sstevel@tonic-gate   if ((substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) <= 0
12277c478bd9Sstevel@tonic-gate        || substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) <= 0
12287c478bd9Sstevel@tonic-gate        || substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) <= 0)
12297c478bd9Sstevel@tonic-gate       && (/* check that this is not a super block copy inside
12307c478bd9Sstevel@tonic-gate 	   * the journal log */
12317c478bd9Sstevel@tonic-gate 	  super.s_journal_block * super.s_blocksize
12327c478bd9Sstevel@tonic-gate 	  > REISERFS_DISK_OFFSET_IN_BYTES))
12337c478bd9Sstevel@tonic-gate     num_sectors = (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
12347c478bd9Sstevel@tonic-gate   else
12357c478bd9Sstevel@tonic-gate     num_sectors = (REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate   return (needed_sectors <= num_sectors);
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate #endif /* FSYS_REISERFS */
1240