/* File: rfs.c Copyright (C) 1998-2007 Christophe GRENIER This software 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 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "types.h" #include "common.h" #include "rfs.h" #include "fnctdsk.h" #include "log.h" static int set_rfs_info(const disk_t *disk_car, const struct reiserfs_super_block *sb,partition_t *partition, const int debug, const int dump_ind); static int test_rfs(const disk_t *disk_car, const struct reiserfs_super_block *sb,partition_t *partition,const int debug, const int dump_ind); static int test_rfs4(const disk_t *disk_car, const struct reiser4_master_sb*sb,partition_t *partition,const int debug, const int dump_ind); static int set_rfs4_info(const disk_t *disk_car, const struct reiser4_master_sb*sb,partition_t *partition, const int debug, const int dump_ind); int check_rfs(disk_t *disk_car,partition_t *partition,const int debug) { unsigned char *buffer=(unsigned char*)MALLOC(REISERFS_SUPER_BLOCK_SIZE); if(disk_car->read(disk_car,REISERFS_SUPER_BLOCK_SIZE, buffer, partition->part_offset+128*512)!=0) /* 64k offset */ { free(buffer); return 1; } if(test_rfs(disk_car,(struct reiserfs_super_block*)buffer,partition,debug,0)==0) { set_rfs_info(disk_car,(struct reiserfs_super_block*)buffer,partition,debug,0); free(buffer); return 0; } if(test_rfs4(disk_car,(struct reiser4_master_sb*)buffer,partition,debug,0)==0) { set_rfs4_info(disk_car,(struct reiser4_master_sb*)buffer,partition,debug,0); free(buffer); return 0; } free(buffer); return 1; } static int test_rfs(const disk_t *disk_car, const struct reiserfs_super_block *sb,partition_t *partition,const int debug, const int dump_ind) { if (memcmp(sb->s_magic,REISERFS_SUPER_MAGIC,sizeof(REISERFS_SUPER_MAGIC)) == 0) { partition->upart_type = UP_RFS; } else if(memcmp(sb->s_magic,REISERFS2_SUPER_MAGIC,sizeof(REISERFS2_SUPER_MAGIC)) == 0) { partition->upart_type = UP_RFS2; } else if(memcmp(sb->s_magic,REISERFS3_SUPER_MAGIC,sizeof(REISERFS3_SUPER_MAGIC)) == 0) { partition->upart_type = UP_RFS3; } else return 1; if(debug>0) log_info("\nReiserFS Marker at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset), offset2head(disk_car,partition->part_offset), offset2sector(disk_car,partition->part_offset)); /* * sanity checks. */ if (le32(sb->s_block_count) < le32(sb->s_free_blocks)) return (1); if (le32(sb->s_block_count) < REISERFS_MIN_BLOCK_AMOUNT) return (1); if ((le16(sb->s_state) != REISERFS_VALID_FS) && (le16(sb->s_state) != REISERFS_ERROR_FS)) return (1); if (le16(sb->s_oid_maxsize) % 2!=0) /* must be even */ return (1); if (le16(sb->s_oid_maxsize) < le16(sb->s_oid_cursize)) return (1); if ((le16(sb->s_blocksize) != 4096) && (le16(sb->s_blocksize) != 8192)) return (1); return 0; } static int test_rfs4(const disk_t *disk_car, const struct reiser4_master_sb *sb,partition_t *partition,const int debug, const int dump_ind) { if (memcmp(sb->magic,REISERFS4_SUPER_MAGIC,sizeof(REISERFS4_SUPER_MAGIC)) == 0) { partition->upart_type = UP_RFS4; } else return 1; if(debug>0) log_info("\nReiserFS Marker at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset)); /* * sanity checks. */ if (le16(sb->blocksize) != 4096) return (1); /* if a value > 4096 become legal, the code will break while reading the filesystem size (read out of bound) */ return 0; } int recover_rfs(disk_t *disk_car, const struct reiserfs_super_block *sb,partition_t *partition,const int debug, const int dump_ind) { const struct reiser4_master_sb *sb4=(const struct reiser4_master_sb *)sb; if(test_rfs(disk_car,sb,partition,debug,dump_ind)==0) { if(debug>0 || dump_ind!=0) { log_info("\nrecover_rfs\n"); log_info("block_count=%u\n",(unsigned int)le32(sb->s_block_count)); log_info("block_size=%u\n",le16(sb->s_blocksize)); if(dump_ind!=0) { dump_log(sb,DEFAULT_SECTOR_SIZE); } } partition->part_size = (uint64_t)le32(sb->s_block_count) * le16(sb->s_blocksize); partition->part_type_i386 = P_LINUX; partition->part_type_mac= PMAC_LINUX; partition->part_type_sun= PSUN_LINUX; set_rfs_info(disk_car,sb,partition,debug,dump_ind); return 0; } if(test_rfs4(disk_car,sb4,partition,debug,dump_ind)==0) { const struct format40_super *fmt40_super=(const struct format40_super *)((const char*)sb4+le16(sb4->blocksize)); if(debug>0 || dump_ind!=0) { log_info("\nrecover_rfs\n"); log_info("block_count=%lu\n",(unsigned long int)le64(fmt40_super->sb_block_count)); log_info("block_size=%u\n",le16(sb4->blocksize)); if(dump_ind!=0) { dump_log(sb,DEFAULT_SECTOR_SIZE); } } partition->part_size = (uint64_t)le64(fmt40_super->sb_block_count) * le16(sb4->blocksize); partition->part_type_i386 = P_LINUX; partition->part_type_mac= PMAC_LINUX; partition->part_type_sun= PSUN_LINUX; set_rfs4_info(disk_car,sb4,partition,debug,dump_ind); return 0; } return 1; } static int set_rfs_info(const disk_t *disk_car,const struct reiserfs_super_block *sb,partition_t *partition, const int debug, const int dump_ind) { partition->name[0]='\0'; partition->info[0]='\0'; switch(partition->upart_type) { case UP_RFS: strncpy(partition->info,"ReiserFS 3.5 with standard journal",sizeof(partition->info)); break; case UP_RFS2: strncpy(partition->info,"ReiserFS 3.6 with standard journal",sizeof(partition->info)); set_part_name(partition,(const char*)sb->s_label,16); break; case UP_RFS3: if(le16(sb->sb_version)==1) strncpy(partition->info,"ReiserFS 3.5 with non standard journal",sizeof(partition->info)); else if(le16(sb->sb_version)==2) strncpy(partition->info,"ReiserFS 3.6 with non standard journal",sizeof(partition->info)); else strncpy(partition->info,"ReiserFS ? with non standard journal",sizeof(partition->info)); set_part_name(partition,(const char*)sb->s_label,16); break; default: return 1; } if (le16(sb->s_state) == REISERFS_ERROR_FS) { strcat(partition->info,", need recovery"); } return 0; } static int set_rfs4_info(const disk_t *disk_car,const struct reiser4_master_sb *sb,partition_t *partition, const int debug, const int dump_ind) { partition->name[0]='\0'; partition->info[0]='\0'; switch(partition->upart_type) { case UP_RFS4: strncpy(partition->info,"ReiserFS 4",sizeof(partition->info)); break; default: return 1; } return 0; }