From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1Ih3xY-0007S9-Na for mharc-grub-devel@gnu.org; Sun, 14 Oct 2007 09:56:48 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Ih3xW-0007RM-Gd for grub-devel@gnu.org; Sun, 14 Oct 2007 09:56:46 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Ih3xU-0007QZ-Rw for grub-devel@gnu.org; Sun, 14 Oct 2007 09:56:46 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Ih3xU-0007QP-H2 for grub-devel@gnu.org; Sun, 14 Oct 2007 09:56:44 -0400 Received: from ug-out-1314.google.com ([66.249.92.175]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Ih3xR-0005nw-S2 for grub-devel@gnu.org; Sun, 14 Oct 2007 09:56:44 -0400 Received: by ug-out-1314.google.com with SMTP id a2so108775ugf for ; Sun, 14 Oct 2007 06:56:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:from:to:subject:date:user-agent:mime-version:content-type:content-transfer-encoding:message-id; bh=UbVz73/qJ4CqAM+fMzSkY9CRrRCZQ7fdITcQSXUOz3Y=; b=G9VygApbJ2QIJ4OnRKBJHfdfko+xvQQU9KDeIwlLxPPL82Y7cU9WTGfNGD9vBkxXYxiRvoIlBedjySsiYcFdzdPPzLZ2xw/km+XoEmhxeTfR+InIOuEAhcXS3G/zsu4KRQEb2NEooOM3dRNqgEAJTq96ZqeEkQaI7gOxt2mR9zI= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:from:to:subject:date:user-agent:mime-version:content-type:content-transfer-encoding:message-id; b=CNGxcDlO+dQnAE8i+uZvRp7cUiaS2GomwcvBhCjMI6aa/fC6aR4MkIb8I/67TAG38XDG8eDaG7aaXBbDikCgA5g1ULNA8AJR++bylkZf/tjXp2U2TPNzvBwVTr2TGLBoJfQChpghYu8wzyD32bc9HMeU5OCSZLWHVGpcOIaXfpg= Received: by 10.66.255.7 with SMTP id c7mr6748597ugi.1192370186138; Sun, 14 Oct 2007 06:56:26 -0700 (PDT) Received: from x2 ( [90.7.121.245]) by mx.google.com with ESMTPS id j1sm6647249ugf.2007.10.14.06.56.22 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 14 Oct 2007 06:56:23 -0700 (PDT) From: Vincent Pelletier To: grub-devel@gnu.org Date: Sun, 14 Oct 2007 15:56:18 +0200 User-Agent: KMail/1.9.7 MIME-Version: 1.0 Content-Type: multipart/signed; boundary="nextPart6593129.0vn136oNuu"; protocol="application/pgp-signature"; micalg=pgp-sha1 Content-Transfer-Encoding: 7bit Message-Id: <200710141556.22613.plr.vincent@gmail.com> X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 2) Subject: [non-finalised patch] reiserfs handling X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Oct 2007 13:56:46 -0000 --nextPart6593129.0vn136oNuu Content-Type: multipart/mixed; boundary="Boundary-01=_CAiEHB9bgGtZ/8n" Content-Transfer-Encoding: 7bit Content-Disposition: inline --Boundary-01=_CAiEHB9bgGtZ/8n Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Hi. Attached is my work on reiserfs handling. As I don't plan to work on it anytime soon, and as I was advised on IRC, I= =20 port it here, in case someone want to use it as a base. It does not follow the coding style, some part looks quite ugly (big hex=20 constants as bitmasks, grub_reiserfs_get_item and grub_reiserfe_iterate_dir= =20 functions), has old commented out code (grub_reiserfs_read) and some debug= =20 printfs commented out (grub_reiserfe_iterate_dir), conditionaly compiled=20 (GRUB_REISERFS_DEBUG), or always available. As such, it was good enough to read tens of megabyte big files on a reiserf= s=20 3.5 disk image on a PPC32 box. It handles symlinks as such, and showed no=20 read errors as far as I could tell. It was only tested in grub-emu, and nev= er=20 on a live system. To build grub2 with reiserfs module, add this file in the "fs" folder and a= dd=20 a reference to this file in conf/*.rmk files . Sorry for not finishing that work. =2D-=20 Vincent Pelletier --Boundary-01=_CAiEHB9bgGtZ/8n Content-Type: text/x-csrc; charset="us-ascii"; name="reiserfs.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="reiserfs.c" /* reiserfs.c - ReiserFS versions up to 3.6 */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* TODO: implement journal handling (ram replay) implement symlinks support support items bigger than roughly (blocksize / 4) * blocksize !! that goes for directories aswell, size in such case is metadata size. test tail packing & direct files validate partition label position */ #warning "TODO : journal, tail packing (?)" // #define GRUB_REISERFS_KEYV2_BITFIELD // #define GRUB_REISERFS_DEBUG // #define GRUB_REISERFS_JOURNALING // #define GRUB_HEXDUMP #include #include #include #include #include #include #include #include #define MIN(a, b) (((a)<(b))?(a):(b)) #define MAX(a, b) (((a)>(b))?(a):(b)) #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 #define REISERFS_MAGIC_LEN 12 #define REISERFS_MAGIC_STRING "ReIsEr2Fs\0\0\0" /* If the 3rd bit of an item state is set, then it's visible. */ #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t)0x04) #define REISERFS_MAX_LABEL_LENGTH 16 #define REISERFS_LABEL_OFFSET 0x64 #define S_IFLNK 0xA000 #ifndef GRUB_UTIL static grub_dl_t my_mod; #endif enum grub_reiserfs_item_type { GRUB_REISERFS_STAT, GRUB_REISERFS_DIRECTORY, GRUB_REISERFS_DIRECT, GRUB_REISERFS_INDIRECT, GRUB_REISERFS_ANY, /* Matches both _DIRECT and _INDIRECT when searching. = */ GRUB_REISERFS_UNKNOWN }; struct grub_reiserfs_superblock { grub_uint32_t block_count; grub_uint32_t block_free_count; grub_uint32_t root_block; grub_uint32_t journal_block; grub_uint32_t journal_device; grub_uint32_t journal_original_size; grub_uint32_t journal_max_transaction_size; grub_uint32_t journal_block_count; grub_uint32_t journal_max_batch; grub_uint32_t journal_max_commit_age; grub_uint32_t journal_max_transaction_age; grub_uint16_t block_size; grub_uint16_t oid_max_size; grub_uint16_t oid_current_size; grub_uint16_t state; grub_uint8_t magic_string[REISERFS_MAGIC_LEN]; grub_uint32_t function_hash_code; grub_uint16_t tree_height; grub_uint16_t bitmap_number; grub_uint16_t version; grub_uint16_t reserved; grub_uint32_t inode_generation; } __attribute__ ((packed)); #ifdef GRUB_REISERFS_JOURNALING #error "Journaling not yet supported." struct grub_reiserfs_journal_header { grub_uint32_t last_flush_uid; grub_uint32_t unflushed_offset; grub_uint32_t mount_id; } __attribute__ ((packed)); struct grub_reiserfs_transaction_header { grub_uint32_t id; grub_uint32_t len; grub_uint32_t mount_id; char *data; char checksum[12]; } __attribute__ ((packed)); #endif struct grub_reiserfs_stat_item_v1 { grub_uint16_t mode; grub_uint16_t hardlink_count; grub_uint16_t uid; grub_uint16_t gid; grub_uint32_t size; grub_uint32_t atime; grub_uint32_t mtime; grub_uint32_t ctime; grub_uint32_t rdev; grub_uint32_t first_direct_byte; } __attribute__ ((packed)); struct grub_reiserfs_stat_item_v2 { grub_uint16_t mode; grub_uint16_t reserved; grub_uint32_t hardlink_count; grub_uint64_t size; grub_uint32_t uid; grub_uint32_t gid; grub_uint32_t atime; grub_uint32_t mtime; grub_uint32_t ctime; grub_uint32_t blocks; grub_uint32_t first_direct_byte; } __attribute__ ((packed)); struct grub_reiserfs_key { grub_uint32_t directory_id; grub_uint32_t object_id; union { struct { grub_uint32_t offset; grub_uint32_t type; } v1 __attribute__ ((packed)); struct { #ifdef GRUB_REISERFS_KEYV2_BITFIELD grub_uint64_t offset:60; grub_uint64_t type:4; #else grub_uint64_t offset_type; #endif } v2 __attribute__ ((packed)); } u; } __attribute__ ((packed)); struct grub_reiserfs_item_header { struct grub_reiserfs_key key; union { grub_uint16_t free_space; grub_uint16_t entry_count; } u __attribute__ ((packed)); grub_uint16_t item_size; grub_uint16_t item_location; grub_uint16_t version; } __attribute__ ((packed)); struct grub_reiserfs_block_header { grub_uint16_t level; grub_uint16_t item_count; grub_uint16_t free_space; grub_uint16_t reserved; struct grub_reiserfs_key block_right_delimiting_key; } __attribute__ ((packed)); struct grub_reiserfs_disk_child { grub_uint32_t block_number; grub_uint16_t size; grub_uint16_t reserved; } __attribute__ ((packed)); struct grub_reiserfs_directory_header { grub_uint32_t offset; grub_uint32_t directory_id; grub_uint32_t object_id; grub_uint16_t location; grub_uint16_t state; } __attribute__ ((packed)); struct grub_reiserfs_node_body { union { struct { struct grub_reiserfs_key *key_list; struct grub_reiserfs_disk_child *child_list; } internal; struct { struct grub_reiserfs_item_header *item_header_list; } leaf; } u; }; struct grub_fshelp_node { struct grub_reiserfs_data *data; grub_uint32_t block_number; /* 0 if node is not found. */ grub_uint16_t block_position; enum grub_reiserfs_item_type type; /* To know how to read the header. */ struct grub_reiserfs_item_header header; }; /* Returned when opening a file. */ struct grub_reiserfs_data { struct grub_reiserfs_superblock superblock; grub_disk_t disk; }; /* Internal-only functions. Not to be used outside of this file. */ /* Return the type of given v2 key. */ static enum grub_reiserfs_item_type grub_reiserfs_get_key_v2_type (const struct grub_reiserfs_key *key) { #ifdef GRUB_REISERFS_KEYV2_BITFIELD switch (key->u.v2.type) #else switch (key->u.v2.offset_type & 0xF) #endif { case 0: return GRUB_REISERFS_STAT; case 15: return GRUB_REISERFS_ANY; case 3: return GRUB_REISERFS_DIRECTORY; case 2: return GRUB_REISERFS_DIRECT; case 1: return GRUB_REISERFS_INDIRECT; } return GRUB_REISERFS_UNKNOWN; } /* Return the type of given v1 key. */ static enum grub_reiserfs_item_type grub_reiserfs_get_key_v1_type (const struct grub_reiserfs_key *key) { switch (grub_le_to_cpu32 (key->u.v1.type)) { case 0: return GRUB_REISERFS_STAT; case 555: return GRUB_REISERFS_ANY; case 500: return GRUB_REISERFS_DIRECTORY; case 0x20000000: case 0xFFFFFFFF: return GRUB_REISERFS_DIRECT; case 0x10000000: case 0xFFFFFFFE: return GRUB_REISERFS_INDIRECT; } return GRUB_REISERFS_UNKNOWN; } /* Return 1 if the given key is version 1 key, 2 otherwise. */ static int grub_reiserfs_get_key_version (const struct grub_reiserfs_key *key) { return (grub_reiserfs_get_key_v1_type (key) =3D=3D GRUB_REISERFS_UNKNOWN)= ? 2 : 1; } #ifdef GRUB_HEXDUMP static void grub_hexdump (char *buffer, grub_size_t len) { unsigned int a; for (a =3D 0; a < len; a++) { if (!(a & 0x0F)) grub_printf ("\n%08x ", a); grub_printf ("%02x ", ((unsigned int) ((unsigned char *) buffer)[a]) = & 0xFF); } grub_printf ("\n"); } #endif #ifdef GRUB_REISERFS_DEBUG static grub_uint64_t grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key); static enum grub_reiserfs_item_type grub_reiserfs_get_key_type (const struct grub_reiserfs_key *key); static void grub_reiserfs_print_key (const struct grub_reiserfs_key *key) { unsigned int a; char *reiserfs_type_strings[6] =3D \ {"stat ", "directory", "direct ", "indirect ", "any ", "unknown "}; for (a =3D 0; a < sizeof(struct grub_reiserfs_key); a++) grub_printf ("%02x ", ((unsigned int) ((char *)key)[a]) & 0xFF); grub_printf("parent id =3D 0x%08x, self id =3D 0x%08x, type =3D %s, offse= t =3D ", grub_le_to_cpu32 (key->directory_id), grub_le_to_cpu32 (key->object_id), reiserfs_type_strings [grub_reiserfs_get_key_type(key)]); if (grub_reiserfs_get_key_version (key) =3D=3D 1) grub_printf("%08x", (unsigned int) grub_reiserfs_get_key_offset(key)); else grub_printf("0x%07x%08x", (unsigned int) (grub_reiserfs_get_key_offset(key) >> 32), (unsigned int) (grub_reiserfs_get_key_offset(key) & 0xFFFFF= =46FF)); grub_printf ("\n"); } #endif /* Return the offset of given key. */ static grub_uint64_t grub_reiserfs_get_key_offset (const struct grub_reiserfs_key *key) { if (grub_reiserfs_get_key_version (key) =3D=3D 1) return grub_le_to_cpu32 (key->u.v1.offset); else { #ifdef GRUB_REISERFS_KEYV2_BITFIELD return key->u.v2.offset; #else grub_uint64_t temp =3D grub_le_to_cpu64 (key->u.v2.offset_type & ~0xF= ); return ((temp & 0xF000000000000000LLU) >> 4) | (temp & 0x00FFFFFFFFFF= =46FFFLLU); #endif } } /* Set the offset of given key. */ static void grub_reiserfs_set_key_offset (struct grub_reiserfs_key *key, grub_uint64_t = value) { if (grub_reiserfs_get_key_version (key) =3D=3D 1) key->u.v1.offset =3D grub_cpu_to_le32 (value); else #ifdef GRUB_REISERFS_KEYV2_BITFIELD key->u.v2.offset =3D value; #else key->u.v2.offset_type =3D (key->u.v2.offset_type & 0xF) | grub_cpu_to_l= e64(((value & 0x0F00000000000000LLU) << 4) | (value & 0x00FFFFFFFFFFFFFFLLU= )); #endif } /* Return the type of given key. */ static enum grub_reiserfs_item_type grub_reiserfs_get_key_type (const struct grub_reiserfs_key *key) { if (grub_reiserfs_get_key_version (key) =3D=3D 1) return grub_reiserfs_get_key_v1_type (key); else return grub_reiserfs_get_key_v2_type (key); } /* Set the type of given key, with given version number. */ static void grub_reiserfs_set_key_type (struct grub_reiserfs_key *key, enum grub_reiserfs_item_type grub_type, int version) { grub_uint32_t type; switch (grub_type) { case GRUB_REISERFS_STAT: type =3D 0; break; case GRUB_REISERFS_ANY: type =3D (version =3D=3D 1) ? 555 : 15; break; case GRUB_REISERFS_DIRECTORY: type =3D (version =3D=3D 1) ? 500 : 3; break; case GRUB_REISERFS_DIRECT: type =3D (version =3D=3D 1) ? 0xFFFFFFFF : 2; break; case GRUB_REISERFS_INDIRECT: type =3D (version =3D=3D 1) ? 0xFFFFFFFE : 1; break; default: return; } if (version =3D=3D 1) key->u.v1.type =3D grub_cpu_to_le32 (type); else #ifdef GRUB_REISERFS_KEYV2_BITFIELD key->u.v2.type =3D type; #else key->u.v2.offset_type =3D (key->u.v2.offset_type & ~0xF) | (type & 0xF); #endif } /* -1 if key 1 if lower than key 2. 0 if key 1 is equal to key 2. 1 if key 1 is higher than key 2. */ static int grub_reiserfs_compare_keys (const struct grub_reiserfs_key *key1, const struct grub_reiserfs_key *key2) { grub_uint64_t offset1, offset2; enum grub_reiserfs_item_type type1, type2; grub_uint32_t id1, id2; if (!key1 || !key2) return -2; id1 =3D grub_le_to_cpu32 (key1->directory_id); id2 =3D grub_le_to_cpu32 (key2->directory_id); if (id1 < id2) return -1; if (id1 > id2) return 1; id1 =3D grub_le_to_cpu32 (key1->object_id); id2 =3D grub_le_to_cpu32 (key2->object_id); if (id1 < id2) return -1; if (id1 > id2) return 1; offset1 =3D grub_reiserfs_get_key_offset(key1); offset2 =3D grub_reiserfs_get_key_offset(key2); if (offset1 < offset2) return -1; if (offset1 > offset2) return 1; type1 =3D grub_reiserfs_get_key_type(key1); type2 =3D grub_reiserfs_get_key_type(key2); if ((type1 =3D=3D GRUB_REISERFS_ANY && (type2 =3D=3D GRUB_REISERFS_DIRECT= || type2 =3D=3D GRUB_REISERFS_INDIRECT)) || (type2 =3D=3D GRUB_REISERFS_ANY && (type1 =3D=3D GRUB_REISERFS_DIRECT= || type1 =3D=3D GRUB_REISERFS_INDIRECT))) return 0; if (type1 < type2) return -1; if (type1 > type2) return 1; return 0; } /* Find the item identified by KEY in mounted filesystem DATA, and fill ITEM accordingly to what was found. */ static grub_err_t grub_reiserfs_get_item (struct grub_reiserfs_data *data, const struct grub_reiserfs_key *key, struct grub_fshelp_node *item) { grub_uint32_t block_number; struct grub_reiserfs_node_body block_body; struct grub_reiserfs_block_header *block_header =3D 0; struct grub_reiserfs_key *block_key =3D 0; grub_uint16_t increment, block_size, item_count, current_level; grub_uint16_t previous_level =3D ~0; if (!data) { grub_error (GRUB_ERR_BAD_ARGUMENT, "data is NULL"); goto fail; } if (!key) { grub_error (GRUB_ERR_BAD_ARGUMENT, "key is NULL"); goto fail; } if (!item) { grub_error (GRUB_ERR_BAD_ARGUMENT, "item is NULL"); goto fail; } block_size =3D grub_le_to_cpu16 (data->superblock.block_size); block_number =3D grub_le_to_cpu32 (data->superblock.root_block); #ifdef GRUB_REISERFS_DEBUG grub_printf("Searching for "); grub_reiserfs_print_key (key); #endif block_header =3D grub_malloc (block_size); if (!block_header) goto fail; do { grub_disk_read (data->disk, (block_number * block_size) / GRUB_DISK_SECTOR_SIZE, (block_number * block_size) % GRUB_DISK_SECTOR_SIZE, block_size, (char *) block_header); if (grub_errno) goto fail; current_level =3D grub_le_to_cpu16 (block_header->level); grub_dprintf ("reiserfs_tree", " at level %d\n", current_level); if (current_level >=3D previous_level) { grub_dprintf ("reiserfs_tree", "level loop detected, aborting\n"); goto fail; } previous_level =3D current_level; item_count =3D grub_le_to_cpu16 (block_header->item_count); grub_dprintf ("reiserfs_tree", " number of contained items : %d\n", = item_count); if (current_level > 1) { /* Internal node. Navigate to the child that should contain the = searched key. */ block_body.u.internal.key_list =3D (struct grub_reiserfs_key *) (= block_header + 1); block_body.u.internal.child_list =3D (struct grub_reiserfs_disk_c= hild *) (block_body.u.internal.key_list + item_count); for (increment =3D 0; increment < item_count && grub_reiserfs_compare_keys (key, &= (block_body.u.internal.key_list[increment])) >=3D 0; increment++) { #ifdef GRUB_REISERFS_DEBUG grub_printf("i %03d/%03d ", increment + 1, item_count + 1); grub_reiserfs_print_key (&(block_body.u.internal.key_list[inc= rement])); #endif } block_number =3D grub_le_to_cpu32 (block_body.u.internal.child_li= st[increment].block_number); #ifdef GRUB_REISERFS_DEBUG if (increment =3D=3D item_count || grub_reiserfs_compare_keys (ke= y, &(block_body.u.internal.key_list[increment])) =3D=3D 0) grub_printf(">"); else grub_printf("<"); if (increment < item_count) { grub_printf (" %03d/%03d ", increment + 1, item_count + 1); grub_reiserfs_print_key (&(block_body.u.internal.key_list[inc= rement])); if (increment + 1 < item_count) { grub_printf ("+ %03d/%03d ", increment + 2, item_count); grub_reiserfs_print_key (&(block_body.u.internal.key_list[increm= ent + 1])); } } else grub_printf ("Accessing rightmost child at block %d.\n", block_= number); #endif } else { /* Leaf node. Check that the key is actually present. */ block_body.u.leaf.item_header_list =3D (struct grub_reiserfs_item= _header *) (block_header + 1); for (increment =3D 0; increment < item_count && grub_reiserfs_compare_keys (key, &= (block_body.u.leaf.item_header_list[increment].key)) !=3D 0; increment++) { #ifdef GRUB_REISERFS_DEBUG if (key->directory_id =3D=3D block_body.u.leaf.item_header_li= st[increment].key.directory_id && \ key->object_id =3D=3D block_body.u.leaf.item_header_list[= increment].key.object_id) grub_printf("C"); else grub_printf(" "); grub_printf(" %03d/%03d ", increment + 1, item_count); grub_reiserfs_print_key (&(block_body.u.leaf.item_header_list= [increment].key)); #endif } if (increment < item_count) block_key =3D &(block_body.u.leaf.item_header_list[increment].k= ey); } } while (current_level > 1); item->data =3D data; if (increment =3D=3D item_count || grub_reiserfs_compare_keys (key, block= _key)) { item->block_number =3D 0; item->block_position =3D 0; item->type =3D GRUB_REISERFS_UNKNOWN; #ifdef GRUB_REISERFS_DEBUG grub_printf("Not found.\n"); #endif } else { item->block_number =3D block_number; item->block_position =3D increment; item->type =3D grub_reiserfs_get_key_type (block_key); grub_memcpy (&(item->header), &(block_body.u.leaf.item_header_list[increment]), sizeof (struct grub_reiserfs_item_header)); #ifdef GRUB_REISERFS_DEBUG grub_printf("F %03d/%03d ", increment + 1, item_count); grub_reiserfs_print_key (block_key); #endif } grub_free(block_header); return GRUB_ERR_NONE; fail: grub_free (block_header); return grub_errno; } /* Return the path of the file which is pointed at by symlink NODE. */ static char * grub_reiserfs_read_symlink (grub_fshelp_node_t node) { char *symlink_buffer =3D 0; grub_uint16_t block_size; grub_size_t offset, len, block; struct grub_fshelp_node found; struct grub_reiserfs_key key; grub_memcpy (&key, &(node->header.key), sizeof(key)); grub_reiserfs_set_key_offset (&key, 1); grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECT, grub_reiserfs_get= _key_version(&key)); if (grub_reiserfs_get_item (node->data, &key, &found) !=3D GRUB_ERR_NONE) goto fail; if (found.block_number =3D=3D 0) goto fail; block_size =3D grub_le_to_cpu16 (node->data->superblock.block_size); len =3D grub_le_to_cpu16 (found.header.item_size); block =3D (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE; offset =3D grub_le_to_cpu16 (found.header.item_location); symlink_buffer =3D grub_malloc (len); if (!symlink_buffer) goto fail; grub_disk_read(node->data->disk, block, offset, len, symlink_buffer); if (grub_errno) goto fail; return symlink_buffer; fail: grub_free (symlink_buffer); return 0; } /* Fill the mounted filesystem structure and return it. */ static struct grub_reiserfs_data * grub_reiserfs_mount (grub_disk_t disk) { struct grub_reiserfs_data *data =3D 0; data =3D grub_malloc (sizeof (*data)); if (!data) goto fail; grub_disk_read (disk, REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE, 0, sizeof (data->superblock), (char *) &(data->superblock= )); if (grub_errno) goto fail; if (grub_memcmp (data->superblock.magic_string, REISERFS_MAGIC_STRING, REISERFS_MAGIC_LEN)) { grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem"); goto fail; } data->disk =3D disk; return data; fail: grub_free (data); return 0; } /* Call HOOK for each file in directory ITEM. */ static int grub_reiserfs_iterate_dir (grub_fshelp_node_t item, int NESTED_FUNC_ATTR (*hook) (const char *filename, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node)) { struct grub_reiserfs_data *data =3D item->data; struct grub_reiserfs_block_header *block_header =3D 0; grub_uint16_t block_size, block_position; grub_uint32_t block_number; if (item->type !=3D GRUB_REISERFS_DIRECTORY) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "grub_reiserfs_iterate_dir called on a non-directory item= "); goto fail; } block_size =3D grub_le_to_cpu16 (data->superblock.block_size); block_header =3D grub_malloc (block_size); if (!block_header) goto fail; block_number =3D item->block_number; block_position =3D item->block_position; grub_dprintf ("reiserfs", "Iterating directory...\n"); do { struct grub_reiserfs_directory_header *directory_header; struct grub_reiserfs_node_body block_body; struct grub_fshelp_node directory_item; grub_uint16_t entry_count, entry_number; grub_disk_read (data->disk, (block_number * block_size) / GRUB_DISK_SECTOR_SIZE, (block_number * block_size) % GRUB_DISK_SECTOR_SIZE, block_size, (char *) block_header); if (grub_errno) goto fail; // if (grub_le_to_cpu16 (block_header->level) !=3D 1) // { // grub_error (GRUB_ERR_TEST_FAILURE, // "reiserfs: block %d is not a leaf block", // block_number); // goto fail; // } block_body.u.leaf.item_header_list =3D (struct grub_reiserfs_item_hea= der *) (block_header + 1); directory_header =3D (struct grub_reiserfs_directory_header *) (((cha= r *) block_header) + grub_le_to_cpu16 (block_body.u.leaf.item_header_list[b= lock_position].item_location)); entry_count =3D grub_le_to_cpu16 (block_body.u.leaf.item_header_list[= block_position].u.entry_count); for (entry_number =3D 0; entry_number < entry_count; entry_number++) { grub_uint16_t entry_state; entry_state =3D grub_le_to_cpu16 (directory_header[entry_number].= state); if (entry_state & GRUB_REISERFS_VISIBLE_MASK) { struct grub_fshelp_node *entry_item =3D 0; struct grub_reiserfs_key entry_key; enum grub_reiserfs_item_type entry_type; char *entry_name; entry_item =3D grub_malloc (sizeof(*entry_item)); if (!entry_item) goto fail; entry_name =3D ((char *) directory_header) + grub_le_to_cpu16= (directory_header[entry_number].location); entry_key.directory_id =3D directory_header[entry_number].dir= ectory_id; entry_key.object_id =3D directory_header[entry_number].object= _id; #ifdef GRUB_REISERFS_KEYV2_BITFIELD entry_key.u.v2.offset =3D 0; entry_key.u.v2.type =3D 0; #else entry_key.u.v2.offset_type =3D 0; #endif grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_DIRECTO= RY, 2); grub_reiserfs_set_key_offset (&entry_key, 1); if (grub_reiserfs_get_item (data, &entry_key, entry_item) != =3D GRUB_ERR_NONE) goto fail; if (entry_item->type =3D=3D GRUB_REISERFS_DIRECTORY) entry_type =3D GRUB_FSHELP_DIR; else { grub_uint32_t entry_block_number; /* Order is very important here. First set the offset to 0 using current key version. Then change the key type, which influes on key version= detection. */ grub_reiserfs_set_key_offset (&entry_key, 0); grub_reiserfs_set_key_type (&entry_key, GRUB_REISERFS_STA= T, 2); if (grub_reiserfs_get_item (data, &entry_key, entry_item)= !=3D GRUB_ERR_NONE) goto fail; if (entry_item->block_number !=3D 0) { grub_uint16_t entry_version; entry_version =3D grub_le_to_cpu16 (entry_item->heade= r.version); entry_block_number =3D entry_item->block_number; //grub_dprintf("reiserfs", "version %04x block %08x (%08x) position= %08x\n", entry_version, entry_block_number, (entry_block_number * block_si= ze) / GRUB_DISK_SECTOR_SIZE, grub_le_to_cpu16 (entry_item->header.item_loca= tion)); if (entry_version =3D=3D 0) /* Version 1 stat item. */ { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, (entry_block_number * block_size)= / GRUB_DISK_SECTOR_SIZE, grub_le_to_cpu16 (entry_item->hea= der.item_location), sizeof(entry_v1_stat), (char *) &= entry_v1_stat); if (grub_errno) goto fail; //grub_dprintf("reiserfs", "%04x %04x %04x %04x %08x %08x | %08x %08x = %08x %08x\n", grub_le_to_cpu16 (entry_v1_stat.mode), grub_le_to_cpu16 (entr= y_v1_stat.hardlink_count), grub_le_to_cpu16 (entry_v1_stat.uid), grub_le_to= _cpu16 (entry_v1_stat.gid), grub_le_to_cpu32 (entry_v1_stat.size), grub_le_= to_cpu32 (entry_v1_stat.atime), grub_le_to_cpu32 (entry_v1_stat.mtime), gru= b_le_to_cpu32 (entry_v1_stat.ctime), grub_le_to_cpu32 (entry_v1_stat.rdev),= grub_le_to_cpu32 (entry_v1_stat.first_direct_byte)); //grub_dprintf("reiserfs", "%04x %04x %04x %04x %08x %08x | %08x %08x = %08x %08x\n", entry_v1_stat.mode, entry_v1_stat.hardlink_count, entry_v1_st= at.uid, entry_v1_stat.gid, entry_v1_stat.size, entry_v1_stat.atime, entry_v= 1_stat.mtime, entry_v1_stat.ctime, entry_v1_stat.rdev, entry_v1_stat.first_= direct_byte); if ((grub_le_to_cpu16 (entry_v1_stat.mode) & S_IF= LNK) =3D=3D S_IFLNK) entry_type =3D GRUB_FSHELP_SYMLINK; else entry_type =3D GRUB_FSHELP_REG; } else { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, (entry_block_number * block_size)= / GRUB_DISK_SECTOR_SIZE, grub_le_to_cpu16 (entry_item->hea= der.item_location), sizeof(entry_v2_stat), (char *) &= entry_v2_stat); if (grub_errno) goto fail; //grub_dprintf("reiserfs", "%04x %04x %08x %08x%08x | %08x %08x %08x %= 08x | %08x %08x %08x\n", grub_le_to_cpu16 (entry_v2_stat.mode), grub_le_to_= cpu16 (entry_v2_stat.reserved), grub_le_to_cpu32 (entry_v2_stat.hardlink_co= unt), (unsigned int) (grub_le_to_cpu64 (entry_v2_stat.size) >> 32), (unsign= ed int) (grub_le_to_cpu64 (entry_v2_stat.size) && 0xFFFFFFFF), grub_le_to_c= pu32 (entry_v2_stat.uid), grub_le_to_cpu32 (entry_v2_stat.gid), grub_le_to_= cpu32 (entry_v2_stat.atime), grub_le_to_cpu32 (entry_v2_stat.mtime), grub_l= e_to_cpu32 (entry_v2_stat.ctime), grub_le_to_cpu32 (entry_v2_stat.blocks), = grub_le_to_cpu32 (entry_v2_stat.first_direct_byte)); //grub_dprintf("reiserfs", "%04x %04x %08x %08x%08x | %08x %08x %08x %= 08x | %08x %08x %08x\n", entry_v2_stat.mode, entry_v2_stat.reserved, entry_= v2_stat.hardlink_count, (unsigned int) (entry_v2_stat.size >> 32), (unsigne= d int) (entry_v2_stat.size && 0xFFFFFFFF), entry_v2_stat.uid, entry_v2_stat= =2Egid, entry_v2_stat.atime, entry_v2_stat.mtime, entry_v2_stat.ctime, entr= y_v2_stat.blocks, entry_v2_stat.first_direct_byte); if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IF= LNK) =3D=3D S_IFLNK) entry_type =3D GRUB_FSHELP_SYMLINK; else entry_type =3D GRUB_FSHELP_REG; } } else { /* Pseudo file ".." never has stat block. */ if (grub_strcmp (entry_name, "..")) grub_dprintf ("reiserfs", "Warning : %s has no stat block !\n= ", entry_name); continue; } } if (hook (entry_name, entry_type, entry_item)) { grub_dprintf ("reiserfs", "Found : %s, type=3D%d\n", entr= y_name, entry_type); goto found; } //grub_free (entry_item); *entry_name =3D 0; /* Make sure next entry name (which is just before this one in disk order) stops befo= re the current one. */ } } grub_reiserfs_set_key_offset (&(block_body.u.leaf.item_header_list[bl= ock_position].key), grub_reiserfs_get_key_offset (&(block_body.u.leaf.item_= header_list[block_position].key)) + 1); if (grub_reiserfs_get_item (data, &(block_body.u.leaf.item_header_lis= t[block_position].key), &directory_item) !=3D GRUB_ERR_NONE) goto fail; block_number =3D directory_item.block_number; block_position =3D directory_item.block_position; } while (block_number); grub_free (block_header); return 0; found: fail: grub_free (block_header); return 1; } /**************************************************************************= **/ /* grub api functions */ /**************************************************************************= **/ /* Open a file named NAME and initialize FILE. */ static grub_err_t grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_data *data =3D 0; struct grub_fshelp_node root, *found =3D 0, info; struct grub_reiserfs_key key; grub_uint32_t block_number; grub_uint16_t entry_version, block_size, entry_location; #ifndef GRUB_UTIL grub_dl_ref (my_mod); #endif data =3D grub_reiserfs_mount (file->device->disk); if (!data) goto fail; block_size =3D grub_le_to_cpu16 (data->superblock.block_size); key.directory_id =3D grub_cpu_to_le32 (1); key.object_id =3D grub_cpu_to_le32 (2); #ifdef GRUB_REISERFS_KEYV2_BITFIELD key.u.v2.offset =3D 0; key.u.v2.type =3D 0; #else key.u.v2.offset_type =3D 0; #endif grub_reiserfs_set_key_type (&key, GRUB_REISERFS_DIRECTORY, 2); grub_reiserfs_set_key_offset (&key, 1); if (grub_reiserfs_get_item (data, &key, &root) !=3D GRUB_ERR_NONE) goto fail; if (root.block_number =3D=3D 0) goto fail; /* Should never happen since checked at mount. */ grub_fshelp_find_file (name, &root, &found, grub_reiserfs_iterate_dir, grub_reiserfs_read_symlink, GRUB_FSHELP_REG); if (grub_errno) goto fail; key.directory_id =3D found->header.key.directory_id; key.object_id =3D found->header.key.object_id; grub_reiserfs_set_key_type (&key, GRUB_REISERFS_STAT, 2); grub_reiserfs_set_key_offset (&key, 0); if (grub_reiserfs_get_item (data, &key, &info) !=3D GRUB_ERR_NONE) goto fail; if (info.block_number =3D=3D 0) goto fail; entry_version =3D grub_le_to_cpu16 (info.header.version); entry_location =3D grub_le_to_cpu16 (info.header.item_location); block_number =3D info.block_number; if (entry_version =3D=3D 0) /* Version 1 stat item. */ { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, (block_number * block_size) / GRUB_DISK_SECTOR_SIZE, entry_location + (block_number * block_size) % GRUB_D= ISK_SECTOR_SIZE, sizeof(entry_v1_stat), (char *) &entry_v1_stat); if (grub_errno) goto fail; file->size =3D (grub_off_t) grub_le_to_cpu64 (entry_v1_stat.size); } else { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, (block_number * block_size) / GRUB_DISK_SECTOR_SIZE, entry_location + (block_number * block_size) % GRUB_D= ISK_SECTOR_SIZE, sizeof(entry_v2_stat), (char *) &entry_v2_stat); if (grub_errno) goto fail; file->size =3D (grub_off_t) grub_le_to_cpu64 (entry_v2_stat.size); } grub_dprintf ("reiserfs", "file size : %d (%08x%08x)\n", (unsigned int) f= ile->size, (unsigned int) (file->size >> 32), (unsigned int) file->siz= e); file->offset =3D 0; file->data =3D found; return GRUB_ERR_NONE; fail: grub_free (found); grub_free (data); #ifndef GRUB_UTIL grub_dl_unref (my_mod); #endif return grub_errno; } static grub_ssize_t grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) { unsigned int indirect_block, indirect_block_count; struct grub_reiserfs_key key; struct grub_fshelp_node *node =3D file->data; struct grub_reiserfs_data *data =3D node->data; struct grub_fshelp_node found; //grub_size_t read, read_length =3D 0; grub_uint16_t block_size =3D grub_le_to_cpu16 (data->superblock.block_siz= e), item_size; grub_uint32_t *indirect_block_ptr =3D 0; grub_uint64_t current_key_offset =3D 1; grub_size_t initial_position, current_position, final_position, block, le= ngth, offset; if (file->offset >=3D file->size) return 0; key.directory_id =3D node->header.key.directory_id; key.object_id =3D node->header.key.object_id; #ifdef GRUB_REISERFS_KEYV2_BITFIELD key.u.v2.offset =3D 0; key.u.v2.type =3D 0; #else key.u.v2.offset_type =3D 0; #endif grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2); initial_position =3D file->offset; current_position =3D 0; final_position =3D MIN(len + initial_position, file->size); grub_dprintf ("reiserfs", "Reading from %d to %d (%d instead of requested= %d)\n", initial_position, final_position, final_position - initial_positio= n, len); while (current_position < final_position) { grub_reiserfs_set_key_offset (&key, current_key_offset); =20 if (grub_reiserfs_get_item (data, &key, &found) !=3D GRUB_ERR_NONE) goto fail; if (found.block_number =3D=3D 0) goto fail; item_size =3D grub_le_to_cpu16 (found.header.item_size); switch (found.type) { case GRUB_REISERFS_DIRECT: block =3D (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE; grub_dprintf ("reiserfs_blocktype", "D: %d\n", block); if (initial_position < current_position + item_size) { offset =3D MAX ((signed) (initial_position - current_positi= on), 0); length =3D MIN (item_size, final_position - current_positio= n) - offset; grub_dprintf ("reiserfs", "Reading direct block %d from %d to %d...\n", b= lock, offset, offset + length); found.data->disk->read_hook =3D file->read_hook; grub_disk_read (found.data->disk, block, offset + grub_le_t= o_cpu16 (found.header.item_location), length, buf); found.data->disk->read_hook =3D 0; if (grub_errno) goto fail; buf +=3D length; current_position +=3D offset + length; } else current_position +=3D item_size; break; case GRUB_REISERFS_INDIRECT: indirect_block_count =3D item_size / sizeof (*indirect_block_pt= r); indirect_block_ptr =3D grub_malloc (item_size); if (!indirect_block_ptr) goto fail; grub_disk_read (found.data->disk, (found.block_number * block_size) / GRUB_DISK_S= ECTOR_SIZE, grub_le_to_cpu16 (found.header.item_location), item_size, (char *) indirect_block_ptr); if (grub_errno) goto fail; found.data->disk->read_hook =3D file->read_hook; for (indirect_block =3D 0; indirect_block < indirect_block_count && current_position = < final_position; indirect_block++) { block =3D (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) *= block_size) / GRUB_DISK_SECTOR_SIZE; grub_dprintf ("reiserfs_blocktype", "I: %d\n", block); if (current_position + block_size >=3D initial_position) { offset =3D MAX ((signed) (initial_position - current_po= sition), 0); length =3D MIN (block_size, final_position - current_po= sition) - offset; grub_dprintf ("reiserfs", "Reading indirect block %d from %d to %d...= \n", block, offset, offset + length); //grub_dprintf ("reiserfs", "\nib=3D%04d/%04d, ip=3D%d,= cp=3D%d, fp=3D%d, off=3D%d, l=3D%d, tl=3D%d\n", indirect_block + 1, indire= ct_block_count, initial_position, current_position, final_position, offset,= length, len); grub_disk_read (found.data->disk, block, offset, length= , buf); if (grub_errno) goto fail; buf +=3D length; current_position +=3D offset + length; } else current_position +=3D block_size; } found.data->disk->read_hook =3D 0; grub_free (indirect_block_ptr); indirect_block_ptr =3D 0; break; default: goto fail; } current_key_offset =3D current_position + 1; } grub_dprintf("reiserfs", "Have successfully read %d bytes (%d requested)\= n", current_position - initial_position, len); return current_position - initial_position; /* switch (found.type) { case GRUB_REISERFS_DIRECT: read_length =3D MIN (len, item_size - file->offset); grub_disk_read (found.data->disk, (found.block_number * block_size) / GRUB_DISK_SECTO= R_SIZE, grub_le_to_cpu16 (found.header.item_location) + fil= e->offset, read_length, buf); if (grub_errno) goto fail; break; case GRUB_REISERFS_INDIRECT: indirect_block_count =3D item_size / sizeof (*indirect_block_ptr); indirect_block_ptr =3D grub_malloc (item_size); if (!indirect_block_ptr) goto fail; grub_disk_read (found.data->disk, (found.block_number * block_size) / GRUB_DISK_SECTO= R_SIZE, grub_le_to_cpu16 (found.header.item_location), item_size, (char *) indirect_block_ptr); if (grub_errno) goto fail; len =3D MIN (len, file->size - file->offset); for (indirect_block =3D file->offset / block_size; indirect_block < indirect_block_count && read_length < len; indirect_block++) { read =3D MIN (block_size, len - read_length); grub_disk_read (found.data->disk, (grub_le_to_cpu32 (indirect_block_ptr[indirect_= block]) * block_size) / GRUB_DISK_SECTOR_SIZE, file->offset % block_size, read, ((void *) buf) + read_length); if (grub_errno) goto fail; read_length +=3D read; } grub_free (indirect_block_ptr); break; default: goto fail; } return read_length;*/ fail: grub_free (indirect_block_ptr); return 0; } /* Close the file FILE. */ static grub_err_t grub_reiserfs_close (grub_file_t file) { struct grub_fshelp_node *node =3D file->data; struct grub_reiserfs_data *data =3D node->data; grub_free (data); grub_free (node); #ifndef GRUB_UTIL grub_dl_unref (my_mod); #endif return GRUB_ERR_NONE; } /* Call HOOK with each file under DIR. */ static grub_err_t grub_reiserfs_dir (grub_device_t device, const char *path, int (*hook) (const char *filename, int dir)) { struct grub_reiserfs_data *data =3D 0; struct grub_fshelp_node root, *found; struct grub_reiserfs_key root_key; auto int NESTED_FUNC_ATTR iterate (const char *filename, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node); int NESTED_FUNC_ATTR iterate (const char *filename, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node) { grub_free (node); if (filetype =3D=3D GRUB_FSHELP_DIR) return hook (filename, 1); else return hook (filename, 0); } #ifndef GRUB_UTIL grub_dl_ref (my_mod); #endif data =3D grub_reiserfs_mount (device->disk); if (!data) goto fail; root_key.directory_id =3D grub_cpu_to_le32 (1); root_key.object_id =3D grub_cpu_to_le32 (2); #ifdef GRUB_REISERFS_KEYV2_BITFIELD root_key.u.v2.offset =3D 0; root_key.u.v2.type =3D 0; #else root_key.u.v2.offset_type =3D 0; #endif grub_reiserfs_set_key_type (&root_key, GRUB_REISERFS_DIRECTORY, 2); grub_reiserfs_set_key_offset (&root_key, 1); if (grub_reiserfs_get_item (data, &root_key, &root) !=3D GRUB_ERR_NONE) goto fail; if (root.block_number =3D=3D 0) goto fail; grub_fshelp_find_file (path, &root, &found, grub_reiserfs_iterate_dir, grub_reiserfs_read_symlink, GRUB_FSHELP_DIR); if (grub_errno) goto fail; grub_reiserfs_iterate_dir (found, iterate); grub_free (data); #ifndef GRUB_UTIL grub_dl_unref (my_mod); #endif return GRUB_ERR_NONE; fail: grub_free (data); #ifndef GRUB_UTIL grub_dl_unref (my_mod); #endif return grub_errno; } /* Return the label of the device DEVICE in LABEL. The label is returned in a grub_malloc'ed buffer and should be freed by the caller. */ static grub_err_t grub_reiserfs_label (grub_device_t device, char **label) { *label =3D grub_malloc (REISERFS_MAX_LABEL_LENGTH); if (*label) { grub_disk_read (device->disk, REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE, REISERFS_LABEL_OFFSET, REISERFS_MAX_LABEL_LENGTH, *label); } return grub_errno; } static struct grub_fs grub_reiserfs_fs =3D { .name =3D "reiserfs", .dir =3D grub_reiserfs_dir, .open =3D grub_reiserfs_open, .read =3D grub_reiserfs_read, .close =3D grub_reiserfs_close, .label =3D grub_reiserfs_label, .next =3D 0 }; GRUB_MOD_INIT(reiserfs) { grub_fs_register (&grub_reiserfs_fs); #ifndef GRUB_UTIL my_mod =3D mod; #endif } GRUB_MOD_FINI(reiserfs) { grub_fs_unregister (&grub_reiserfs_fs); } --Boundary-01=_CAiEHB9bgGtZ/8n-- --nextPart6593129.0vn136oNuu Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQBHEiAGFEQoKRQyjtURAroWAJsEU3GVlXhn83ZAFqnxkEAloBsAigCdHT/p bdlyaQN8RWREKcyzFVwzt84= =hLoO -----END PGP SIGNATURE----- --nextPart6593129.0vn136oNuu--