~ubuntu-branches/ubuntu/quantal/util-linux/quantal

« back to all changes in this revision

Viewing changes to shlibs/blkid/src/superblocks/befs.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-06-20 22:31:50 UTC
  • mfrom: (1.6.3 upstream) (4.5.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110620223150-lz8wrv0946ihcz3z
Tags: 2.19.1-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Build for multiarch.
  - Add pre-depends on multiarch-support.
  - configure.ac: don't try to be clever about extracting a path name from
    $libdir to append to /usr in a way that's not overridable; instead,
    reuse the built-in configurable libexecdir.
  - Fix up the .pc.in files to know about libexecdir, so our substitutions
    don't leave us with unusable pkg-config files.
  - Install custom blkid.conf to use /dev/.blkid.tab since we don't
    expect device names to survive a reboot
  - Mention mountall(8) in fstab(5) manpages, along with its special
    options.
  - Since upstart is required in Ubuntu, the hwclock.sh init script is not
    called on startup and the hwclockfirst.sh init script is removed.
  - Drop depends on initscripts for the above.
  - Replace hwclock udev rule with an Upstart job.
  - For the case where mount is called with a directory to mount, look
    that directory up in mountall's /lib/init/fstab if we couldn't find
    it mentioned anywhere else.  This means "mount /proc", "mount /sys",
    etc. work.
  - mount.8 points to the cifs-utils package, not the obsolete smbfs one. 
* Dropped changes:
  - mount.preinst: lsb_release has been fixed in lucid and above to be
    usable without configuration, so we don't have to diverge from Debian
    here anymore.
* Changes merged upstream:
  - sfdisk support for '+' with '-N'
  - mount/umount.c: fix a segfault on umount with empty mtab entry
  - Fix arbitrary unmount with fuse security issue

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 Jeroen Oortwijn <oortwijn@gmail.com>
 
3
 *
 
4
 * Partly based on the Haiku BFS driver by
 
5
 *     Axel Dörfler <axeld@pinc-software.de>
 
6
 *
 
7
 * Also inspired by the Linux BeFS driver by
 
8
 *     Will Dyson <will_dyson@pobox.com>, et al.
 
9
 *
 
10
 * This file may be redistributed under the terms of the
 
11
 * GNU Lesser General Public License.
 
12
 */
 
13
#include <stdio.h>
 
14
#include <stdlib.h>
 
15
#include <unistd.h>
 
16
#include <string.h>
 
17
#include <inttypes.h>
 
18
 
 
19
#include "superblocks.h"
 
20
 
 
21
#define B_OS_NAME_LENGTH        0x20
 
22
#define SUPER_BLOCK_MAGIC1      0x42465331      /* BFS1 */
 
23
#define SUPER_BLOCK_MAGIC2      0xdd121031
 
24
#define SUPER_BLOCK_MAGIC3      0x15b6830e
 
25
#define SUPER_BLOCK_FS_ENDIAN   0x42494745      /* BIGE */
 
26
#define INODE_MAGIC1            0x3bbe0ad9
 
27
#define BPLUSTREE_MAGIC         0x69f6c2e8
 
28
#define BPLUSTREE_NULL          -1LL
 
29
#define NUM_DIRECT_BLOCKS       12
 
30
#define B_UINT64_TYPE           0x554c4c47      /* ULLG */
 
31
#define KEY_NAME                "be:volume_id"
 
32
#define KEY_SIZE                8
 
33
 
 
34
#define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \
 
35
                                                        : be16_to_cpu(value))
 
36
#define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \
 
37
                                                        : be32_to_cpu(value))
 
38
#define FS64_TO_CPU(value, fs_is_le) (fs_is_le ? le64_to_cpu(value) \
 
39
                                                        : be64_to_cpu(value))
 
40
 
 
41
typedef struct block_run {
 
42
        int32_t         allocation_group;
 
43
        uint16_t        start;
 
44
        uint16_t        len;
 
45
} __attribute__((packed)) block_run, inode_addr;
 
46
 
 
47
struct befs_super_block {
 
48
        char            name[B_OS_NAME_LENGTH];
 
49
        int32_t         magic1;
 
50
        int32_t         fs_byte_order;
 
51
        uint32_t        block_size;
 
52
        uint32_t        block_shift;
 
53
        int64_t         num_blocks;
 
54
        int64_t         used_blocks;
 
55
        int32_t         inode_size;
 
56
        int32_t         magic2;
 
57
        int32_t         blocks_per_ag;
 
58
        int32_t         ag_shift;
 
59
        int32_t         num_ags;
 
60
        int32_t         flags;
 
61
        block_run       log_blocks;
 
62
        int64_t         log_start;
 
63
        int64_t         log_end;
 
64
        int32_t         magic3;
 
65
        inode_addr      root_dir;
 
66
        inode_addr      indices;
 
67
        int32_t         pad[8];
 
68
} __attribute__((packed));
 
69
 
 
70
typedef struct data_stream {
 
71
        block_run       direct[NUM_DIRECT_BLOCKS];
 
72
        int64_t         max_direct_range;
 
73
        block_run       indirect;
 
74
        int64_t         max_indirect_range;
 
75
        block_run       double_indirect;
 
76
        int64_t         max_double_indirect_range;
 
77
        int64_t         size;
 
78
} __attribute__((packed)) data_stream;
 
79
 
 
80
struct befs_inode {
 
81
        int32_t         magic1;
 
82
        inode_addr      inode_num;
 
83
        int32_t         uid;
 
84
        int32_t         gid;
 
85
        int32_t         mode;
 
86
        int32_t         flags;
 
87
        int64_t         create_time;
 
88
        int64_t         last_modified_time;
 
89
        inode_addr      parent;
 
90
        inode_addr      attributes;
 
91
        uint32_t        type;
 
92
        int32_t         inode_size;
 
93
        uint32_t        etc;
 
94
        data_stream     data;
 
95
        int32_t         pad[4];
 
96
        int32_t         small_data[0];
 
97
} __attribute__((packed));
 
98
 
 
99
struct small_data {
 
100
        uint32_t        type;
 
101
        uint16_t        name_size;
 
102
        uint16_t        data_size;
 
103
        char            name[0];
 
104
} __attribute__((packed));
 
105
 
 
106
struct bplustree_header {
 
107
        uint32_t        magic;
 
108
        uint32_t        node_size;
 
109
        uint32_t        max_number_of_levels;
 
110
        uint32_t        data_type;
 
111
        int64_t         root_node_pointer;
 
112
        int64_t         free_node_pointer;
 
113
        int64_t         maximum_size;
 
114
} __attribute__((packed));
 
115
 
 
116
struct bplustree_node {
 
117
        int64_t         left_link;
 
118
        int64_t         right_link;
 
119
        int64_t         overflow_link;
 
120
        uint16_t        all_key_count;
 
121
        uint16_t        all_key_length;
 
122
        char            name[0];
 
123
} __attribute__((packed));
 
124
 
 
125
unsigned char *get_block_run(blkid_probe pr, const struct befs_super_block *bs,
 
126
                                        const struct block_run *br, int fs_le)
 
127
{
 
128
        return blkid_probe_get_buffer(pr,
 
129
                        ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le)
 
130
                                        << FS32_TO_CPU(bs->ag_shift, fs_le)
 
131
                                        << FS32_TO_CPU(bs->block_shift, fs_le))
 
132
                                + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le)
 
133
                                        << FS32_TO_CPU(bs->block_shift, fs_le)),
 
134
                        (blkid_loff_t) FS16_TO_CPU(br->len, fs_le)
 
135
                                        << FS32_TO_CPU(bs->block_shift, fs_le));
 
136
}
 
137
 
 
138
unsigned char *get_custom_block_run(blkid_probe pr,
 
139
                                const struct befs_super_block *bs,
 
140
                                const struct block_run *br,
 
141
                                int64_t offset, uint32_t length, int fs_le)
 
142
{
 
143
        if (offset + length > (int64_t) FS16_TO_CPU(br->len, fs_le)
 
144
                                        << FS32_TO_CPU(bs->block_shift, fs_le))
 
145
                return NULL;
 
146
 
 
147
        return blkid_probe_get_buffer(pr,
 
148
                        ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le)
 
149
                                        << FS32_TO_CPU(bs->ag_shift, fs_le)
 
150
                                        << FS32_TO_CPU(bs->block_shift, fs_le))
 
151
                                + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le)
 
152
                                        << FS32_TO_CPU(bs->block_shift, fs_le))
 
153
                                + offset,
 
154
                        length);
 
155
}
 
156
 
 
157
unsigned char *get_tree_node(blkid_probe pr, const struct befs_super_block *bs,
 
158
                                const struct data_stream *ds,
 
159
                                int64_t start, uint32_t length, int fs_le)
 
160
{
 
161
        if (start < FS64_TO_CPU(ds->max_direct_range, fs_le)) {
 
162
                int64_t br_len;
 
163
                int i;
 
164
 
 
165
                for (i = 0; i < NUM_DIRECT_BLOCKS; i++) {
 
166
                        br_len = (int64_t) FS16_TO_CPU(ds->direct[i].len, fs_le)
 
167
                                        << FS32_TO_CPU(bs->block_shift, fs_le);
 
168
                        if (start < br_len)
 
169
                                return get_custom_block_run(pr, bs,
 
170
                                                        &ds->direct[i],
 
171
                                                        start, length, fs_le);
 
172
                        else
 
173
                                start -= br_len;
 
174
                }
 
175
        } else if (start < FS64_TO_CPU(ds->max_indirect_range, fs_le)) {
 
176
                struct block_run *br;
 
177
                int64_t max_br, br_len, i;
 
178
 
 
179
                start -= FS64_TO_CPU(ds->max_direct_range, fs_le);
 
180
                max_br = ((int64_t) FS16_TO_CPU(ds->indirect.len, fs_le)
 
181
                                        << FS32_TO_CPU(bs->block_shift, fs_le))
 
182
                                / sizeof(struct block_run);
 
183
 
 
184
                br = (struct block_run *) get_block_run(pr, bs, &ds->indirect,
 
185
                                                                        fs_le);
 
186
                if (!br)
 
187
                        return NULL;
 
188
 
 
189
                for (i = 0; i < max_br; i++) {
 
190
                        br_len = (int64_t) FS16_TO_CPU(br[i].len, fs_le)
 
191
                                        << FS32_TO_CPU(bs->block_shift, fs_le);
 
192
                        if (start < br_len)
 
193
                                return get_custom_block_run(pr, bs, &br[i],
 
194
                                                        start, length, fs_le);
 
195
                        else
 
196
                                start -= br_len;
 
197
                }
 
198
        } else if (start < FS64_TO_CPU(ds->max_double_indirect_range, fs_le)) {
 
199
                struct block_run *br;
 
200
                int64_t di_br_size, br_per_di_br, di_index, i_index;
 
201
 
 
202
                start -= FS64_TO_CPU(ds->max_indirect_range, fs_le);
 
203
                di_br_size = (int64_t) FS16_TO_CPU(ds->double_indirect.len,
 
204
                                fs_le) << FS32_TO_CPU(bs->block_shift, fs_le);
 
205
                br_per_di_br = di_br_size / sizeof(struct block_run);
 
206
                di_index = start / (br_per_di_br * di_br_size);
 
207
                i_index = (start % (br_per_di_br * di_br_size)) / di_br_size;
 
208
                start = (start % (br_per_di_br * di_br_size)) % di_br_size;
 
209
 
 
210
                br = (struct block_run *) get_block_run(pr, bs,
 
211
                                                &ds->double_indirect, fs_le);
 
212
                if (!br)
 
213
                        return NULL;
 
214
 
 
215
                br = (struct block_run *) get_block_run(pr, bs, &br[di_index],
 
216
                                                                        fs_le);
 
217
                if (!br)
 
218
                        return NULL;
 
219
 
 
220
                return get_custom_block_run(pr, bs, &br[i_index], start, length,
 
221
                                                                        fs_le);
 
222
        }
 
223
        return NULL;
 
224
}
 
225
 
 
226
int32_t compare_keys(const char keys1[], uint16_t keylengths1[], int32_t index,
 
227
                        const char *key2, uint16_t keylength2, int fs_le)
 
228
{
 
229
        const char *key1;
 
230
        uint16_t keylength1;
 
231
        int32_t result;
 
232
 
 
233
        key1 = &keys1[index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1],
 
234
                                                                        fs_le)];
 
235
        keylength1 = FS16_TO_CPU(keylengths1[index], fs_le)
 
236
                        - (index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1],
 
237
                                                                        fs_le));
 
238
 
 
239
        result = strncmp(key1, key2, min(keylength1, keylength2));
 
240
 
 
241
        if (result == 0)
 
242
                return keylength1 - keylength2;
 
243
 
 
244
        return result;
 
245
}
 
246
 
 
247
int64_t get_key_value(blkid_probe pr, const struct befs_super_block *bs,
 
248
                        const struct befs_inode *bi, const char *key, int fs_le)
 
249
{
 
250
        struct bplustree_header *bh;
 
251
        struct bplustree_node *bn;
 
252
        uint16_t *keylengths;
 
253
        int64_t *values;
 
254
        int64_t node_pointer;
 
255
        int32_t first, last, mid, cmp;
 
256
 
 
257
        bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0,
 
258
                                        sizeof(struct bplustree_header), fs_le);
 
259
        if (!bh)
 
260
                return -1;
 
261
 
 
262
        if (FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC)
 
263
                return -1;
 
264
 
 
265
        node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le);
 
266
 
 
267
        do {
 
268
                bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data,
 
269
                        node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le);
 
270
                if (!bn)
 
271
                        return -1;
 
272
 
 
273
                keylengths = (uint16_t *) ((uint8_t *) bn
 
274
                                + ((sizeof(struct bplustree_node)
 
275
                                        + FS16_TO_CPU(bn->all_key_length, fs_le)
 
276
                                        + sizeof(int64_t) - 1)
 
277
                                                & ~(sizeof(int64_t) - 1)));
 
278
                values = (int64_t *) ((uint8_t *) keylengths
 
279
                                        + FS16_TO_CPU(bn->all_key_count, fs_le)
 
280
                                                * sizeof(uint16_t));
 
281
                first = 0;
 
282
                mid = 0;
 
283
                last = FS16_TO_CPU(bn->all_key_count, fs_le) - 1;
 
284
 
 
285
                cmp = compare_keys(bn->name, keylengths, last, key, strlen(key),
 
286
                                                                        fs_le);
 
287
                if (cmp == 0) {
 
288
                        if (FS64_TO_CPU(bn->overflow_link, fs_le)
 
289
                                                        == BPLUSTREE_NULL)
 
290
                                return FS64_TO_CPU(values[last], fs_le);
 
291
                        else
 
292
                                node_pointer = FS64_TO_CPU(values[last], fs_le);
 
293
                } else if (cmp < 0)
 
294
                        node_pointer = FS64_TO_CPU(bn->overflow_link, fs_le);
 
295
                else {
 
296
                        while (first <= last) {
 
297
                                mid = (first + last) / 2;
 
298
 
 
299
                                cmp = compare_keys(bn->name, keylengths, mid,
 
300
                                                key, strlen(key), fs_le);
 
301
                                if (cmp == 0) {
 
302
                                        if (FS64_TO_CPU(bn->overflow_link,
 
303
                                                fs_le) == BPLUSTREE_NULL)
 
304
                                                return FS64_TO_CPU(values[mid],
 
305
                                                                        fs_le);
 
306
                                        else
 
307
                                                break;
 
308
                                } else if (cmp < 0)
 
309
                                        first = mid + 1;
 
310
                                else
 
311
                                        last = mid - 1;
 
312
                        }
 
313
                        if (cmp < 0)
 
314
                                node_pointer = FS64_TO_CPU(values[mid + 1],
 
315
                                                                        fs_le);
 
316
                        else
 
317
                                node_pointer = FS64_TO_CPU(values[mid], fs_le);
 
318
                }
 
319
        } while (FS64_TO_CPU(bn->overflow_link, fs_le) != BPLUSTREE_NULL);
 
320
        return 0;
 
321
}
 
322
 
 
323
int get_uuid(blkid_probe pr, const struct befs_super_block *bs,
 
324
                                        uint64_t * const uuid, int fs_le)
 
325
{
 
326
        struct befs_inode *bi;
 
327
        struct small_data *sd;
 
328
 
 
329
        bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le);
 
330
        if (!bi)
 
331
                return -1;
 
332
 
 
333
        if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
 
334
                return -1;
 
335
 
 
336
        sd = (struct small_data *) bi->small_data;
 
337
 
 
338
        do {
 
339
                if (FS32_TO_CPU(sd->type, fs_le) == B_UINT64_TYPE
 
340
                        && FS16_TO_CPU(sd->name_size, fs_le) == strlen(KEY_NAME)
 
341
                        && FS16_TO_CPU(sd->data_size, fs_le) == KEY_SIZE
 
342
                        && strcmp(sd->name, KEY_NAME) == 0) {
 
343
                        *uuid = *(uint64_t *) ((uint8_t *) sd->name
 
344
                                        + FS16_TO_CPU(sd->name_size, fs_le)
 
345
                                        + 3);
 
346
                        break;
 
347
                } else if (FS32_TO_CPU(sd->type, fs_le) == 0
 
348
                                && FS16_TO_CPU(sd->name_size, fs_le) == 0
 
349
                                && FS16_TO_CPU(sd->data_size, fs_le) == 0)
 
350
                        break;
 
351
 
 
352
                sd = (struct small_data *) ((uint8_t *) sd
 
353
                                + sizeof(struct small_data)
 
354
                                + FS16_TO_CPU(sd->name_size, fs_le) + 3
 
355
                                + FS16_TO_CPU(sd->data_size, fs_le) + 1);
 
356
 
 
357
        } while ((intptr_t) sd < (intptr_t) bi
 
358
                                        + FS32_TO_CPU(bi->inode_size, fs_le)
 
359
                                        - sizeof(struct small_data));
 
360
        if (*uuid == 0
 
361
                && (FS32_TO_CPU(bi->attributes.allocation_group, fs_le) != 0
 
362
                        || FS16_TO_CPU(bi->attributes.start, fs_le) != 0
 
363
                        || FS16_TO_CPU(bi->attributes.len, fs_le) != 0)) {
 
364
                int64_t value;
 
365
 
 
366
                bi = (struct befs_inode *) get_block_run(pr, bs,
 
367
                                                        &bi->attributes, fs_le);
 
368
                if (!bi)
 
369
                        return -1;
 
370
 
 
371
                if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
 
372
                        return -1;
 
373
 
 
374
                value = get_key_value(pr, bs, bi, KEY_NAME, fs_le);
 
375
 
 
376
                if (value < 0)
 
377
                        return value;
 
378
                else if (value > 0) {
 
379
                        bi = (struct befs_inode *) blkid_probe_get_buffer(pr,
 
380
                                value << FS32_TO_CPU(bs->block_shift, fs_le),
 
381
                                FS32_TO_CPU(bs->block_size, fs_le));
 
382
                        if (!bi)
 
383
                                return -1;
 
384
 
 
385
                        if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
 
386
                                return -1;
 
387
 
 
388
                        if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE
 
389
                                && FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE
 
390
                                && FS16_TO_CPU(bi->data.direct[0].len, fs_le)
 
391
                                                                        == 1) {
 
392
                                uint64_t *attr_data;
 
393
 
 
394
                                attr_data = (uint64_t *) get_block_run(pr, bs,
 
395
                                                &bi->data.direct[0], fs_le);
 
396
                                if (!attr_data)
 
397
                                        return -1;
 
398
 
 
399
                                *uuid = *attr_data;
 
400
                        }
 
401
                }
 
402
        }
 
403
        return 0;
 
404
}
 
405
 
 
406
static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag)
 
407
{
 
408
        struct befs_super_block *bs;
 
409
        const char *version = NULL;
 
410
        uint64_t volume_id = 0;
 
411
        int fs_le, ret;
 
412
 
 
413
        bs = (struct befs_super_block *) blkid_probe_get_buffer(pr,
 
414
                                        mag->sboff - B_OS_NAME_LENGTH,
 
415
                                        sizeof(struct befs_super_block));
 
416
        if (!bs)
 
417
                return -1;
 
418
 
 
419
        if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1
 
420
                && le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2
 
421
                && le32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3
 
422
                && le32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) {
 
423
                fs_le = 1;
 
424
                version = "little-endian";
 
425
        } else if (be32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1
 
426
                && be32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2
 
427
                && be32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3
 
428
                && be32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) {
 
429
                fs_le = 0;
 
430
                version = "big-endian";
 
431
        } else
 
432
                return -1;
 
433
 
 
434
        ret = get_uuid(pr, bs, &volume_id, fs_le);
 
435
 
 
436
        if (ret < 0)
 
437
                return ret;
 
438
 
 
439
        /*
 
440
         * all checks pass, set LABEL, VERSION and UUID
 
441
         */
 
442
        if (strlen(bs->name))
 
443
                blkid_probe_set_label(pr, (unsigned char *) bs->name,
 
444
                                                        sizeof(bs->name));
 
445
        if (version)
 
446
                blkid_probe_set_version(pr, version);
 
447
 
 
448
        if (volume_id)
 
449
                blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id,
 
450
                                        sizeof(volume_id), "%016" PRIx64,
 
451
                                        FS64_TO_CPU(volume_id, fs_le));
 
452
        return 0;
 
453
}
 
454
 
 
455
const struct blkid_idinfo befs_idinfo =
 
456
{
 
457
        .name           = "befs",
 
458
        .usage          = BLKID_USAGE_FILESYSTEM,
 
459
        .probefunc      = probe_befs,
 
460
        .minsz          = 1024 * 1440,
 
461
        .magics         = {
 
462
                { .magic = "BFS1", .len = 4, .sboff = B_OS_NAME_LENGTH },
 
463
                { .magic = "1SFB", .len = 4, .sboff = B_OS_NAME_LENGTH },
 
464
                { .magic = "BFS1", .len = 4, .sboff = 0x200 +
 
465
                                                        B_OS_NAME_LENGTH },
 
466
                { .magic = "1SFB", .len = 4, .sboff = 0x200 +
 
467
                                                        B_OS_NAME_LENGTH },
 
468
                { NULL }
 
469
        }
 
470
};