1 /*
2
3 File: btrfs.c
4
5 Copyright (C) 2011 Christophe GRENIER <grenier@cgsecurity.org>
6
7 This software is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write the Free Software Foundation, Inc., 51
19 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #endif
33 #include "types.h"
34 #include "common.h"
35 #include "btrfs.h"
36 #include "fnctdsk.h"
37 #include "log.h"
38 #include "guid_cpy.h"
39
40 static int test_btrfs(const struct btrfs_super_block *sb);
41
set_btrfs_info(const struct btrfs_super_block * sb,partition_t * partition)42 static void set_btrfs_info(const struct btrfs_super_block *sb, partition_t *partition)
43 {
44 partition->upart_type=UP_BTRFS;
45 partition->blocksize=le32(sb->dev_item.sector_size);
46 set_part_name(partition, sb->label, sizeof(sb->label));
47 snprintf(partition->info, sizeof(partition->info), "btrfs blocksize=%u", partition->blocksize);
48 if(le64(sb->bytenr)!=partition->part_offset + BTRFS_SUPER_INFO_OFFSET)
49 {
50 strcat(partition->info," Backup superblock");
51 }
52 /* last mounted => date */
53 }
54
check_btrfs(disk_t * disk_car,partition_t * partition)55 int check_btrfs(disk_t *disk_car,partition_t *partition)
56 {
57 unsigned char *buffer=(unsigned char*)MALLOC(BTRFS_SUPER_INFO_SIZE);
58 if(disk_car->pread(disk_car, buffer, BTRFS_SUPER_INFO_SIZE, partition->part_offset + BTRFS_SUPER_INFO_OFFSET) != BTRFS_SUPER_INFO_SIZE)
59 {
60 free(buffer);
61 return 1;
62 }
63 if(test_btrfs((struct btrfs_super_block*)buffer)!=0)
64 {
65 free(buffer);
66 return 1;
67 }
68 set_btrfs_info((struct btrfs_super_block*)buffer, partition);
69 free(buffer);
70 return 0;
71 }
72
73 /*
74 Primary superblock is at 1024 (SUPERBLOCK_OFFSET)
75 Group 0 begin at s_first_data_block
76 */
recover_btrfs(disk_t * disk,const struct btrfs_super_block * sb,partition_t * partition,const int verbose,const int dump_ind)77 int recover_btrfs(disk_t *disk, const struct btrfs_super_block *sb, partition_t *partition, const int verbose, const int dump_ind)
78 {
79 if(test_btrfs(sb)!=0)
80 return 1;
81 if(dump_ind!=0)
82 {
83 if(partition!=NULL && disk!=NULL)
84 log_info("\nbtrfs magic value at %u/%u/%u\n",
85 offset2cylinder(disk,partition->part_offset),
86 offset2head(disk,partition->part_offset),
87 offset2sector(disk,partition->part_offset));
88 dump_log(sb, BTRFS_SUPER_INFO_SIZE);
89 }
90 if(partition==NULL)
91 return 0;
92 set_btrfs_info(sb, partition);
93 partition->part_type_i386=P_LINUX;
94 partition->part_type_mac=PMAC_LINUX;
95 partition->part_type_sun=PSUN_LINUX;
96 partition->part_type_gpt=GPT_ENT_TYPE_LINUX_DATA;
97 partition->part_size=(uint64_t)le64(sb->dev_item.total_bytes);
98 guid_cpy(&partition->part_uuid, (const efi_guid_t *)&sb->fsid);
99 if(verbose>0)
100 {
101 log_info("\n");
102 }
103 partition->sborg_offset=BTRFS_SUPER_INFO_OFFSET;
104 partition->sb_size=BTRFS_SUPER_INFO_SIZE;
105 if(verbose>0)
106 {
107 if(disk==NULL)
108 log_info("recover_btrfs: part_size %lu\n", (long unsigned)(partition->part_size / le32(sb->dev_item.sector_size)));
109 else
110 log_info("recover_btrfs: part_size %lu\n", (long unsigned)(partition->part_size / disk->sector_size));
111 }
112 return 0;
113 }
114
test_btrfs(const struct btrfs_super_block * sb)115 static int test_btrfs(const struct btrfs_super_block *sb)
116 {
117 if(memcmp(&sb->magic, BTRFS_MAGIC, 8)!=0)
118 return 1;
119 if(le32(sb->dev_item.sector_size)==0)
120 return 1;
121 return 0;
122 }
123