1 /*
2 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
3 *
4 * Inspired by libvolume_id by
5 * Kay Sievers <kay.sievers@vrfy.org>
6 *
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
9 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <stdint.h>
15
16 #include "bitops.h" /* swab16() */
17 #include "superblocks.h"
18
19 struct sqsh_super_block {
20 uint32_t magic;
21 uint32_t inode_count;
22 uint32_t mod_time;
23 uint32_t block_size;
24 uint32_t frag_count;
25 uint16_t compressor;
26 uint16_t block_log;
27 uint16_t flags;
28 uint16_t id_count;
29 uint16_t version_major;
30 uint16_t version_minor;
31 uint64_t root_inode;
32 uint64_t bytes_used;
33 uint64_t id_table;
34 uint64_t xattr_table;
35 uint64_t inode_table;
36 uint64_t dir_table;
37 uint64_t frag_table;
38 uint64_t export_table;
39 } __attribute__((packed));
40
41 static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag)
42 {
43 struct sqsh_super_block *sq;
44 uint16_t vermaj;
45 uint16_t vermin;
46
47 sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
48 if (!sq)
49 return errno ? -errno : 1;
50
51 vermaj = le16_to_cpu(sq->version_major);
52 vermin = le16_to_cpu(sq->version_minor);
53 if (vermaj < 4)
54 return 1;
55
56 blkid_probe_sprintf_version(pr, "%u.%u", vermaj, vermin);
57 blkid_probe_set_fsblocksize(pr, le32_to_cpu(sq->block_size));
58 blkid_probe_set_block_size(pr, le32_to_cpu(sq->block_size));
59 blkid_probe_set_fssize(pr, le64_to_cpu(sq->bytes_used));
60
61 return 0;
62 }
63
64 static int probe_squashfs3(blkid_probe pr, const struct blkid_idmag *mag)
65 {
66 struct sqsh_super_block *sq;
67 uint16_t vermaj;
68 uint16_t vermin;
69 enum BLKID_ENDIANNESS endianness;
70
71 sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
72 if (!sq)
73 return errno ? -errno : 1;
74
75 if (strcmp(mag->magic, "sqsh") == 0) {
76 vermaj = be16_to_cpu(sq->version_major);
77 vermin = be16_to_cpu(sq->version_minor);
78 endianness = BLKID_ENDIANNESS_BIG;
79 } else {
80 vermaj = le16_to_cpu(sq->version_major);
81 vermin = le16_to_cpu(sq->version_minor);
82 endianness = BLKID_ENDIANNESS_LITTLE;
83 }
84
85 if (vermaj > 3)
86 return 1;
87
88 blkid_probe_sprintf_version(pr, "%u.%u", vermaj, vermin);
89
90 blkid_probe_set_fsblocksize(pr, 1024);
91 blkid_probe_set_block_size(pr, 1024);
92 blkid_probe_set_fsendianness(pr, endianness);
93
94 return 0;
95 }
96
97 const struct blkid_idinfo squashfs_idinfo =
98 {
99 .name = "squashfs",
100 .usage = BLKID_USAGE_FILESYSTEM,
101 .probefunc = probe_squashfs,
102 .magics =
103 {
104 { .magic = "hsqs", .len = 4 },
105 { NULL }
106 }
107 };
108
109 const struct blkid_idinfo squashfs3_idinfo =
110 {
111 .name = "squashfs3",
112 .usage = BLKID_USAGE_FILESYSTEM,
113 .probefunc = probe_squashfs3,
114 .magics =
115 {
116 { .magic = "sqsh", .len = 4 }, /* big endian */
117 { .magic = "hsqs", .len = 4 }, /* little endian */
118 { NULL }
119 }
120 };
121