chiark / gitweb /
[PATCH] volume_id fix
[elogind.git] / extras / volume_id / volume_id.c
1 /*
2  * volume_id - reads filesystem label and uuid
3  *
4  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  *      The superblock structs are taken from the linux kernel sources
7  *      and the libblkid living inside the e2fsprogs. This is a simple
8  *      straightforward implementation for reading the label strings of the
9  *      most common filesystems.
10  *
11  *      This library is free software; you can redistribute it and/or
12  *      modify it under the terms of the GNU Lesser General Public
13  *      License as published by the Free Software Foundation; either
14  *      version 2.1 of the License, or (at your option) any later version.
15  *
16  *      This library is distributed in the hope that it will be useful,
17  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  *      Lesser General Public License for more details.
20  *
21  *      You should have received a copy of the GNU Lesser General Public
22  *      License along with this library; if not, write to the Free Software
23  *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  */
25
26 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE 1
28 #endif
29
30 #ifdef HAVE_CONFIG_H
31 #  include <config.h>
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #include <fcntl.h>
41 #include <sys/stat.h>
42 #include <asm/types.h>
43
44 #include "volume_id.h"
45 #include "volume_id_logging.h"
46
47 #define bswap16(x) (__u16)((((__u16)(x) & 0x00ffu) << 8) | \
48                            (((__u16)(x) & 0xff00u) >> 8))
49
50 #define bswap32(x) (__u32)((((__u32)(x) & 0xff000000u) >> 24) | \
51                            (((__u32)(x) & 0x00ff0000u) >>  8) | \
52                            (((__u32)(x) & 0x0000ff00u) <<  8) | \
53                            (((__u32)(x) & 0x000000ffu) << 24))
54
55 #define bswap64(x) (__u64)((((__u64)(x) & 0xff00000000000000ull) >> 56) | \
56                            (((__u64)(x) & 0x00ff000000000000ull) >> 40) | \
57                            (((__u64)(x) & 0x0000ff0000000000ull) >> 24) | \
58                            (((__u64)(x) & 0x000000ff00000000ull) >>  8) | \
59                            (((__u64)(x) & 0x00000000ff000000ull) <<  8) | \
60                            (((__u64)(x) & 0x0000000000ff0000ull) << 24) | \
61                            (((__u64)(x) & 0x000000000000ff00ull) << 40) | \
62                            (((__u64)(x) & 0x00000000000000ffull) << 56))
63
64 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
65 #define le16_to_cpu(x) (x)
66 #define le32_to_cpu(x) (x)
67 #define le64_to_cpu(x) (x)
68 #define be16_to_cpu(x) bswap16(x)
69 #define be32_to_cpu(x) bswap32(x)
70 #elif (__BYTE_ORDER == __BIG_ENDIAN)
71 #define le16_to_cpu(x) bswap16(x)
72 #define le32_to_cpu(x) bswap32(x)
73 #define le64_to_cpu(x) bswap64(x)
74 #define be16_to_cpu(x) (x)
75 #define be32_to_cpu(x) (x)
76 #endif
77
78 /* size of superblock buffer, reiserfs block is at 64k */
79 #define SB_BUFFER_SIZE                          0x11000
80 /* size of seek buffer 4k */
81 #define SEEK_BUFFER_SIZE                        0x1000
82
83
84 static void set_label_raw(struct volume_id *id,
85                           const __u8 *buf, unsigned int count)
86 {
87         memcpy(id->label_raw, buf, count);
88         id->label_raw_len = count;
89 }
90
91 static void set_label_string(struct volume_id *id,
92                              const __u8 *buf, unsigned int count)
93 {
94         unsigned int i;
95
96         memcpy(id->label, buf, count);
97
98         /* remove trailing whitespace */
99         i = strnlen(id->label, count);
100         while (i--) {
101                 if (! isspace(id->label[i]))
102                         break;
103         }
104         id->label[i+1] = '\0';
105 }
106
107 #define LE              0
108 #define BE              1
109 static void set_label_unicode16(struct volume_id *id,
110                                 const __u8 *buf,
111                                 unsigned int endianess,
112                                 unsigned int count)
113 {
114         unsigned int i, j;
115         __u16 c;
116
117         j = 0;
118         for (i = 0; i + 2 <= count; i += 2) {
119                 if (endianess == LE)
120                         c = (buf[i+1] << 8) | buf[i];
121                 else
122                         c = (buf[i] << 8) | buf[i+1];
123                 if (c == 0) {
124                         id->label[j] = '\0';
125                         break;
126                 } else if (c < 0x80) {
127                         id->label[j++] = (__u8) c;
128                 } else if (c < 0x800) {
129                         id->label[j++] = (__u8) (0xc0 | (c >> 6));
130                         id->label[j++] = (__u8) (0x80 | (c & 0x3f));
131                 } else {
132                         id->label[j++] = (__u8) (0xe0 | (c >> 12));
133                         id->label[j++] = (__u8) (0x80 | ((c >> 6) & 0x3f));
134                         id->label[j++] = (__u8) (0x80 | (c & 0x3f));
135                 }
136         }
137 }
138
139 enum uuid_format {
140         UUID_DCE,
141         UUID_DOS,
142         UUID_NTFS,
143         UUID_HFS,
144 };
145
146 static void set_uuid(struct volume_id *id, const __u8 *buf, enum uuid_format format)
147 {
148         unsigned int i;
149         unsigned int count = 0;
150
151         switch(format) {
152         case UUID_DOS:
153                 count = 4;
154                 break;
155         case UUID_NTFS:
156         case UUID_HFS:
157                 count = 8;
158                 break;
159         case UUID_DCE:
160                 count = 16;
161         }
162         memcpy(id->uuid_raw, buf, count);
163
164         /* if set, create string in the same format, the native platform uses */
165         for (i = 0; i < count; i++)
166                 if (buf[i] != 0)
167                         goto set;
168         return;
169
170 set:
171         switch(format) {
172         case UUID_DOS:
173                 sprintf(id->uuid, "%02X%02X-%02X%02X",
174                         buf[3], buf[2], buf[1], buf[0]);
175                 break;
176         case UUID_NTFS:
177                 sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X",
178                         buf[7], buf[6], buf[5], buf[4],
179                         buf[3], buf[2], buf[1], buf[0]);
180                 break;
181         case UUID_HFS:
182                 sprintf(id->uuid,"%02X%02X%02X%02X%02X%02X%02X%02X",
183                         buf[0], buf[1], buf[2], buf[3],
184                         buf[4], buf[5], buf[6], buf[7]);
185                 break;
186         case UUID_DCE:
187                 sprintf(id->uuid,
188                         "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
189                         buf[0], buf[1], buf[2], buf[3],
190                         buf[4], buf[5],
191                         buf[6], buf[7],
192                         buf[8], buf[9],
193                         buf[10], buf[11], buf[12], buf[13], buf[14],buf[15]);
194                 break;
195         }
196 }
197
198 static __u8 *get_buffer(struct volume_id *id, __u64 off, unsigned int len)
199 {
200         unsigned int buf_len;
201
202         dbg("get buffer off 0x%llx, len 0x%x", off, len);
203         /* check if requested area fits in superblock buffer */
204         if (off + len <= SB_BUFFER_SIZE) {
205                 if (id->sbbuf == NULL) {
206                         id->sbbuf = malloc(SB_BUFFER_SIZE);
207                         if (id->sbbuf == NULL)
208                                 return NULL;
209                 }
210
211                 /* check if we need to read */
212                 if ((off + len) > id->sbbuf_len) {
213                         dbg("read sbbuf len:0x%llx", off + len);
214                         lseek(id->fd, 0, SEEK_SET);
215                         buf_len = read(id->fd, id->sbbuf, off + len);
216                         dbg("got 0x%x (%i) bytes", buf_len, buf_len);
217                         id->sbbuf_len = buf_len;
218                         if (buf_len < off + len)
219                                 return NULL;
220                 }
221
222                 return &(id->sbbuf[off]);
223         } else {
224                 if (len > SEEK_BUFFER_SIZE)
225                         len = SEEK_BUFFER_SIZE;
226
227                 /* get seek buffer */
228                 if (id->seekbuf == NULL) {
229                         id->seekbuf = malloc(SEEK_BUFFER_SIZE);
230                         if (id->seekbuf == NULL)
231                                 return NULL;
232                 }
233
234                 /* check if we need to read */
235                 if ((off < id->seekbuf_off) ||
236                     ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
237                         dbg("read seekbuf off:0x%llx len:0x%x", off, len);
238                         if (lseek(id->fd, off, SEEK_SET) == -1)
239                                 return NULL;
240                         buf_len = read(id->fd, id->seekbuf, len);
241                         dbg("got 0x%x (%i) bytes", buf_len, buf_len);
242                         id->seekbuf_off = off;
243                         id->seekbuf_len = buf_len;
244                         if (buf_len < len)
245                                 return NULL;
246                 }
247
248                 return &(id->seekbuf[off - id->seekbuf_off]);
249         }
250 }
251
252 static void free_buffer(struct volume_id *id)
253 {
254         if (id->sbbuf != NULL) {
255                 free(id->sbbuf);
256                 id->sbbuf = NULL;
257                 id->sbbuf_len = 0;
258         }
259         if (id->seekbuf != NULL) {
260                 free(id->seekbuf);
261                 id->seekbuf = NULL;
262                 id->seekbuf_len = 0;
263         }
264 }
265
266 #define LVM1_SB_OFF                     0x400
267 #define LVM1_MAGIC                      "HM"
268 static int probe_lvm1(struct volume_id *id, __u64 off)
269 {
270         struct lvm2_super_block {
271                 __u8    id[2];
272         } __attribute__((packed)) *lvm;
273
274         const __u8 *buf;
275
276         buf = get_buffer(id, off + LVM1_SB_OFF, 0x800);
277         if (buf == NULL)
278                 return -1;
279
280         lvm = (struct lvm2_super_block *) buf;
281
282         if (strncmp(lvm->id, LVM1_MAGIC, 2) != 0)
283                 return -1;
284
285         id->usage_id = VOLUME_ID_RAID;
286         id->type_id = VOLUME_ID_LVM1;
287         id->type = "LVM1_member";
288
289         return 0;
290 }
291
292 #define LVM2_LABEL_ID                   "LABELONE"
293 #define LVM2LABEL_SCAN_SECTORS          4
294 static int probe_lvm2(struct volume_id *id, __u64 off)
295 {
296         struct lvm2_super_block {
297                 __u8    id[8];
298                 __u64   sector_xl;
299                 __u32   crc_xl;
300                 __u32   offset_xl;
301                 __u8    type[8];
302         } __attribute__((packed)) *lvm;
303
304         const __u8 *buf;
305         unsigned int soff;
306
307         buf = get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
308         if (buf == NULL)
309                 return -1;
310
311
312         for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
313                 lvm = (struct lvm2_super_block *) &buf[soff];
314
315                 if (strncmp(lvm->id, LVM2_LABEL_ID, 8) == 0)
316                         goto found;
317         }
318
319         return -1;
320
321 found:
322         strncpy(id->type_version, lvm->type, 8);
323         id->usage_id = VOLUME_ID_RAID;
324         id->type_id = VOLUME_ID_LVM2;
325         id->type = "LVM2_member";
326
327         return 0;
328 }
329
330 #define MD_RESERVED_BYTES               0x10000
331 #define MD_MAGIC                        0xa92b4efc
332 static int probe_linux_raid(struct volume_id *id, __u64 off, __u64 size)
333 {
334         struct mdp_super_block {
335                 __u32   md_magic;
336                 __u32   major_version;
337                 __u32   minor_version;
338                 __u32   patch_version;
339                 __u32   gvalid_words;
340                 __u32   set_uuid0;
341                 __u32   ctime;
342                 __u32   level;
343                 __u32   size;
344                 __u32   nr_disks;
345                 __u32   raid_disks;
346                 __u32   md_minor;
347                 __u32   not_persistent;
348                 __u32   set_uuid1;
349                 __u32   set_uuid2;
350                 __u32   set_uuid3;
351         } __attribute__((packed)) *mdp;
352
353         const __u8 *buf;
354         __u64 sboff;
355         __u8 uuid[16];
356
357         if (size < 0x10000)
358                 return -1;
359
360         sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
361         buf = get_buffer(id, off + sboff, 0x800);
362         if (buf == NULL)
363                 return -1;
364
365         mdp = (struct mdp_super_block *) buf;
366
367         if (le32_to_cpu(mdp->md_magic) != MD_MAGIC)
368                 return -1;
369
370         memcpy(uuid, &mdp->set_uuid0, 4);
371         memcpy(&uuid[4], &mdp->set_uuid1, 12);
372         set_uuid(id, uuid, UUID_DCE);
373
374         snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1, "%u.%u.%u",
375                  le32_to_cpu(mdp->major_version),
376                  le32_to_cpu(mdp->minor_version),
377                  le32_to_cpu(mdp->patch_version));
378
379         dbg("found raid signature");
380         id->usage_id = VOLUME_ID_RAID;
381         id->type = "linux_raid_member";
382
383         return 0;
384 }
385
386 #define MSDOS_MAGIC                     "\x55\xaa"
387 #define MSDOS_PARTTABLE_OFFSET          0x1be
388 #define MSDOS_SIG_OFF                   0x1fe
389 #define BSIZE                           0x200
390 #define DOS_EXTENDED_PARTITION          0x05
391 #define LINUX_EXTENDED_PARTITION        0x85
392 #define WIN98_EXTENDED_PARTITION        0x0f
393 #define LINUX_RAID_PARTITION            0xfd
394 #define is_extended(type) \
395         (type == DOS_EXTENDED_PARTITION ||      \
396          type == WIN98_EXTENDED_PARTITION ||    \
397          type == LINUX_EXTENDED_PARTITION)
398 #define is_raid(type) \
399         (type == LINUX_RAID_PARTITION)
400 static int probe_msdos_part_table(struct volume_id *id, __u64 off)
401 {
402         struct msdos_partition_entry {
403                 __u8    boot_ind;
404                 __u8    head;
405                 __u8    sector;
406                 __u8    cyl;
407                 __u8    sys_ind;
408                 __u8    end_head;
409                 __u8    end_sector;
410                 __u8    end_cyl;
411                 __u32   start_sect;
412                 __u32   nr_sects;
413         } __attribute__((packed)) *part;
414
415         const __u8 *buf;
416         int i;
417         __u64 poff;
418         __u64 plen;
419         __u64 extended = 0;
420         __u64 current;
421         __u64 next;
422         int limit;
423         int empty = 1;
424         struct volume_id_partition *p;
425
426         buf = get_buffer(id, off, 0x200);
427         if (buf == NULL)
428                 return -1;
429
430         if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
431                 return -1;
432
433         /* check flags on all entries for a valid partition table */
434         part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
435         for (i = 0; i < 4; i++) {
436                 if (part[i].boot_ind != 0 &&
437                     part[i].boot_ind != 0x80)
438                         return -1;
439
440                 if (le32_to_cpu(part[i].nr_sects) != 0)
441                         empty = 0;
442         }
443         if (empty == 1)
444                 return -1;
445
446         if (id->partitions != NULL)
447                 free(id->partitions);
448         id->partitions = malloc(VOLUME_ID_PARTITIONS_MAX *
449                                 sizeof(struct volume_id_partition));
450         if (id->partitions == NULL)
451                 return -1;
452         memset(id->partitions, 0x00,
453                VOLUME_ID_PARTITIONS_MAX * sizeof(struct volume_id_partition));
454
455         for (i = 0; i < 4; i++) {
456                 poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
457                 plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
458
459                 if (plen == 0)
460                         continue;
461
462                 p = &id->partitions[i];
463
464                 p->partition_type_raw = part[i].sys_ind;
465
466                 if (is_extended(part[i].sys_ind)) {
467                         dbg("found extended partition at 0x%llx", poff);
468                         p->usage_id = VOLUME_ID_PARTITIONTABLE;
469                         p->type_id = VOLUME_ID_MSDOSEXTENDED;
470                         p->type = "msdos_extended_partition";
471                         if (extended == 0)
472                                 extended = off + poff;
473                 } else {
474                         dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
475                             part[i].sys_ind, poff, plen);
476
477                         if (is_raid(part[i].sys_ind))
478                                 p->usage_id = VOLUME_ID_RAID;
479                         else
480                                 p->usage_id = VOLUME_ID_UNPROBED;
481                 }
482
483                 p->off = off + poff;
484                 p->len = plen;
485                 id->partition_count = i+1;
486         }
487
488         next = extended;
489         current = extended;
490         limit = 50;
491
492         /* follow extended partition chain and add data partitions */
493         while (next != 0) {
494                 if (limit-- == 0) {
495                         dbg("extended chain limit reached");
496                         break;
497                 }
498
499                 buf = get_buffer(id, current, 0x200);
500                 if (buf == NULL)
501                         break;
502
503                 part = (struct msdos_partition_entry*) &buf[MSDOS_PARTTABLE_OFFSET];
504
505                 if (strncmp(&buf[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0)
506                         break;
507
508                 next = 0;
509
510                 for (i = 0; i < 4; i++) {
511                         poff = (__u64) le32_to_cpu(part[i].start_sect) * BSIZE;
512                         plen = (__u64) le32_to_cpu(part[i].nr_sects) * BSIZE;
513
514                         if (plen == 0)
515                                 continue;
516
517                         if (is_extended(part[i].sys_ind)) {
518                                 dbg("found extended partition at 0x%llx", poff);
519                                 if (next == 0)
520                                         next = extended + poff;
521                         } else {
522                                 dbg("found 0x%x data partition at 0x%llx, len 0x%llx",
523                                         part[i].sys_ind, poff, plen);
524
525                                 /* we always start at the 5th entry */
526                                 while (id->partition_count < 4)
527                                         id->partitions[id->partition_count++].usage_id =
528                                                 VOLUME_ID_UNUSED;
529
530                                 p = &id->partitions[id->partition_count];
531
532                                 if (is_raid(part[i].sys_ind))
533                                         p->usage_id = VOLUME_ID_RAID;
534                                 else
535                                         p->usage_id = VOLUME_ID_UNPROBED;
536
537                                 p->off = current + poff;
538                                 p->len = plen;
539                                 id->partition_count++;
540
541                                 p->partition_type_raw = part[i].sys_ind;
542
543                                 if (id->partition_count >= VOLUME_ID_PARTITIONS_MAX) {
544                                         dbg("to many partitions");
545                                         next = 0;
546                                 }
547                         }
548                 }
549
550                 current = next;
551         }
552
553         id->usage_id = VOLUME_ID_PARTITIONTABLE;
554         id->type_id = VOLUME_ID_MSDOSPARTTABLE;
555         id->type = "msdos_partition_table";
556
557         return 0;
558 }
559
560 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL         0x00000004
561 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV       0x00000008
562 #define EXT_SUPERBLOCK_OFFSET                   0x400
563 static int probe_ext(struct volume_id *id, __u64 off)
564 {
565         struct ext2_super_block {
566                 __u32   inodes_count;
567                 __u32   blocks_count;
568                 __u32   r_blocks_count;
569                 __u32   free_blocks_count;
570                 __u32   free_inodes_count;
571                 __u32   first_data_block;
572                 __u32   log_block_size;
573                 __u32   dummy3[7];
574                 __u8    magic[2];
575                 __u16   state;
576                 __u32   dummy5[8];
577                 __u32   feature_compat;
578                 __u32   feature_incompat;
579                 __u32   feature_ro_compat;
580                 __u8    uuid[16];
581                 __u8    volume_name[16];
582         } __attribute__((__packed__)) *es;
583
584         es = (struct ext2_super_block *)
585              get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
586         if (es == NULL)
587                 return -1;
588
589         if (es->magic[0] != 0123 ||
590             es->magic[1] != 0357)
591                 return -1;
592
593         set_label_raw(id, es->volume_name, 16);
594         set_label_string(id, es->volume_name, 16);
595         set_uuid(id, es->uuid, UUID_DCE);
596
597         if ((le32_to_cpu(es->feature_compat) &
598              EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
599                 id->usage_id = VOLUME_ID_FILESYSTEM;
600                 id->type_id = VOLUME_ID_EXT3;
601                 id->type = "ext3";
602         } else {
603                 id->usage_id = VOLUME_ID_FILESYSTEM;
604                 id->type_id = VOLUME_ID_EXT2;
605                 id->type = "ext2";
606         }
607
608         return 0;
609 }
610
611 #define REISERFS1_SUPERBLOCK_OFFSET             0x2000
612 #define REISERFS_SUPERBLOCK_OFFSET              0x10000
613 static int probe_reiserfs(struct volume_id *id, __u64 off)
614 {
615         struct reiserfs_super_block {
616                 __u32   blocks_count;
617                 __u32   free_blocks;
618                 __u32   root_block;
619                 __u32   journal_block;
620                 __u32   journal_dev;
621                 __u32   orig_journal_size;
622                 __u32   dummy2[5];
623                 __u16   blocksize;
624                 __u16   dummy3[3];
625                 __u8    magic[12];
626                 __u32   dummy4[5];
627                 __u8    uuid[16];
628                 __u8    label[16];
629         } __attribute__((__packed__)) *rs;
630
631         rs = (struct reiserfs_super_block *)
632              get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
633         if (rs == NULL)
634                 return -1;
635
636         if (strncmp(rs->magic, "ReIsEr2Fs", 9) == 0) {
637                 strcpy(id->type_version, "3.6");
638                 goto found;
639         }
640
641         if (strncmp(rs->magic, "ReIsEr3Fs", 9) == 0) {
642                 strcpy(id->type_version, "JR");
643                 goto found;
644         }
645
646         rs = (struct reiserfs_super_block *)
647              get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
648         if (rs == NULL)
649                 return -1;
650
651         if (strncmp(rs->magic, "ReIsErFs", 8) == 0) {
652                 strcpy(id->type_version, "3.5");
653                 goto found;
654         }
655
656         return -1;
657
658 found:
659         set_label_raw(id, rs->label, 16);
660         set_label_string(id, rs->label, 16);
661         set_uuid(id, rs->uuid, UUID_DCE);
662
663         id->usage_id = VOLUME_ID_FILESYSTEM;
664         id->type_id = VOLUME_ID_REISERFS;
665         id->type = "reiserfs";
666
667         return 0;
668 }
669
670 static int probe_xfs(struct volume_id *id, __u64 off)
671 {
672         struct xfs_super_block {
673                 __u8    magic[4];
674                 __u32   blocksize;
675                 __u64   dblocks;
676                 __u64   rblocks;
677                 __u32   dummy1[2];
678                 __u8    uuid[16];
679                 __u32   dummy2[15];
680                 __u8    fname[12];
681                 __u32   dummy3[2];
682                 __u64   icount;
683                 __u64   ifree;
684                 __u64   fdblocks;
685         } __attribute__((__packed__)) *xs;
686
687         xs = (struct xfs_super_block *) get_buffer(id, off, 0x200);
688         if (xs == NULL)
689                 return -1;
690
691         if (strncmp(xs->magic, "XFSB", 4) != 0)
692                 return -1;
693
694         set_label_raw(id, xs->fname, 12);
695         set_label_string(id, xs->fname, 12);
696         set_uuid(id, xs->uuid, UUID_DCE);
697
698         id->usage_id = VOLUME_ID_FILESYSTEM;
699         id->type_id = VOLUME_ID_XFS;
700         id->type = "xfs";
701
702         return 0;
703 }
704
705 #define JFS_SUPERBLOCK_OFFSET                   0x8000
706 static int probe_jfs(struct volume_id *id, __u64 off)
707 {
708         struct jfs_super_block {
709                 __u8    magic[4];
710                 __u32   version;
711                 __u64   size;
712                 __u32   bsize;
713                 __u32   dummy1;
714                 __u32   pbsize;
715                 __u32   dummy2[27];
716                 __u8    uuid[16];
717                 __u8    label[16];
718                 __u8    loguuid[16];
719         } __attribute__((__packed__)) *js;
720
721         js = (struct jfs_super_block *)
722              get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
723         if (js == NULL)
724                 return -1;
725
726         if (strncmp(js->magic, "JFS1", 4) != 0)
727                 return -1;
728
729         set_label_raw(id, js->label, 16);
730         set_label_string(id, js->label, 16);
731         set_uuid(id, js->uuid, UUID_DCE);
732
733         id->usage_id = VOLUME_ID_FILESYSTEM;
734         id->type_id = VOLUME_ID_JFS;
735         id->type = "jfs";
736
737         return 0;
738 }
739
740 #define FAT12_MAX                       0xff5
741 #define FAT16_MAX                       0xfff5
742 #define FAT_ATTR_VOLUME                 0x08
743 static int probe_vfat(struct volume_id *id, __u64 off)
744 {
745         struct vfat_super_block {
746                 __u8    boot_jump[3];
747                 __u8    sysid[8];
748                 __u16   sector_size;
749                 __u8    sectors_per_cluster;
750                 __u16   reserved;
751                 __u8    fats;
752                 __u16   dir_entries;
753                 __u16   sectors;
754                 __u8    media;
755                 __u16   fat_length;
756                 __u16   secs_track;
757                 __u16   heads;
758                 __u32   hidden;
759                 __u32   total_sect;
760                 union {
761                         struct fat_super_block {
762                                 __u8    unknown[3];
763                                 __u8    serno[4];
764                                 __u8    label[11];
765                                 __u8    magic[8];
766                                 __u8    dummy2[192];
767                                 __u8    pmagic[2];
768                         } __attribute__((__packed__)) fat;
769                         struct fat32_super_block {
770                                 __u32   fat32_length;
771                                 __u16   flags;
772                                 __u8    version[2];
773                                 __u32   root_cluster;
774                                 __u16   insfo_sector;
775                                 __u16   backup_boot;
776                                 __u16   reserved2[6];
777                                 __u8    unknown[3];
778                                 __u8    serno[4];
779                                 __u8    label[11];
780                                 __u8    magic[8];
781                                 __u8    dummy2[164];
782                                 __u8    pmagic[2];
783                         } __attribute__((__packed__)) fat32;
784                 } __attribute__((__packed__)) type;
785         } __attribute__((__packed__)) *vs;
786
787         struct vfat_dir_entry {
788                 __u8    name[11];
789                 __u8    attr;
790                 __u16   time_creat;
791                 __u16   date_creat;
792                 __u16   time_acc;
793                 __u16   date_acc;
794                 __u16   cluster_high;
795                 __u16   time_write;
796                 __u16   date_write;
797                 __u16   cluster_low;
798                 __u32   size;
799         } __attribute__((__packed__)) *dir;
800
801         __u16 sector_size;
802         __u16 dir_entries;
803         __u32 sect_count;
804         __u16 reserved;
805         __u16 fat_size;
806         __u32 root_cluster;
807         __u32 dir_size;
808         __u32 cluster_count;
809         __u32 fat_length;
810         __u64 root_start;
811         __u32 start_data_sect;
812         __u16 root_dir_entries;
813         __u8 *buf;
814         __u32 buf_size;
815         __u8 *label = NULL;
816         __u32 next;
817         int maxloop;
818         int i;
819
820         vs = (struct vfat_super_block *) get_buffer(id, off, 0x200);
821         if (vs == NULL)
822                 return -1;
823
824         /* believe only that's fat, don't trust the version
825          * the cluster_count will tell us
826          */
827         if (strncmp(vs->type.fat32.magic, "MSWIN", 5) == 0)
828                 goto valid;
829
830         if (strncmp(vs->type.fat32.magic, "FAT32   ", 8) == 0)
831                 goto valid;
832
833         if (strncmp(vs->type.fat.magic, "FAT16   ", 8) == 0)
834                 goto valid;
835
836         if (strncmp(vs->type.fat.magic, "MSDOS", 5) == 0)
837                 goto valid;
838
839         if (strncmp(vs->type.fat.magic, "FAT12   ", 8) == 0)
840                 goto valid;
841
842         /*
843          * There are old floppies out there without a magic, so we check
844          * for well known values and guess if it's a fat volume
845          */
846
847         /* boot jump address check */
848         if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
849              vs->boot_jump[0] != 0xe9)
850                 return -1;
851
852         /* heads check */
853         if (vs->heads == 0)
854                 return -1;
855
856         /* cluster size check*/ 
857         if (vs->sectors_per_cluster == 0 ||
858             (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
859                 return -1;
860
861         /* media check */
862         if (vs->media < 0xf8 && vs->media != 0xf0)
863                 return -1;
864
865         /* fat count*/
866         if (vs->fats != 2)
867                 return -1;
868
869 valid:
870         /* sector size check */
871         sector_size = le16_to_cpu(vs->sector_size);
872         if (sector_size != 0x200 && sector_size != 0x400 &&
873             sector_size != 0x800 && sector_size != 0x1000)
874                 return -1;
875
876         dbg("sector_size 0x%x", sector_size);
877         dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
878
879         dir_entries = le16_to_cpu(vs->dir_entries);
880         reserved = le16_to_cpu(vs->reserved);
881         dbg("reserved 0x%x", reserved);
882
883         sect_count = le16_to_cpu(vs->sectors);
884         if (sect_count == 0)
885                 sect_count = le32_to_cpu(vs->total_sect);
886         dbg("sect_count 0x%x", sect_count);
887
888         fat_length = le16_to_cpu(vs->fat_length);
889         if (fat_length == 0)
890                 fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
891         dbg("fat_length 0x%x", fat_length);
892
893         fat_size = fat_length * vs->fats;
894         dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
895                         (sector_size-1)) / sector_size;
896         dbg("dir_size 0x%x", dir_size);
897
898         cluster_count = sect_count - (reserved + fat_size + dir_size);
899         cluster_count /= vs->sectors_per_cluster;
900         dbg("cluster_count 0x%x", cluster_count);
901
902         if (cluster_count < FAT12_MAX) {
903                 strcpy(id->type_version, "FAT12");
904         } else if (cluster_count < FAT16_MAX) {
905                 strcpy(id->type_version, "FAT16");
906         } else {
907                 strcpy(id->type_version, "FAT32");
908                 goto fat32;
909         }
910
911         /* the label may be an attribute in the root directory */
912         root_start = (reserved + fat_size) * sector_size;
913         dbg("root dir start 0x%llx", root_start);
914         root_dir_entries = le16_to_cpu(vs->dir_entries);
915         dbg("expected entries 0x%x", root_dir_entries);
916
917         buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
918         buf = get_buffer(id, off + root_start, buf_size);
919         if (buf == NULL)
920                 goto found;
921
922         dir = (struct vfat_dir_entry*) buf;
923
924         for (i = 0; i <= root_dir_entries; i++) {
925                 /* end marker */
926                 if (dir[i].name[0] == 0x00) {
927                         dbg("end of dir");
928                         break;
929                 }
930
931                 /* empty entry */
932                 if (dir[i].name[0] == 0xe5)
933                         continue;
934
935                 if (dir[i].attr == FAT_ATTR_VOLUME) {
936                         dbg("found ATTR_VOLUME id in root dir");
937                         label = dir[i].name;
938                 }
939
940                 dbg("skip dir entry");
941         }
942
943         if (label != NULL && strncmp(label, "NO NAME    ", 11) != 0) {
944                 set_label_raw(id, label, 11);
945                 set_label_string(id, label, 11);
946         } else if (strncmp(vs->type.fat.label, "NO NAME    ", 11) != 0) {
947                 set_label_raw(id, vs->type.fat.label, 11);
948                 set_label_string(id, vs->type.fat.label, 11);
949         }
950         set_uuid(id, vs->type.fat.serno, UUID_DOS);
951         goto found;
952
953 fat32:
954         /* FAT32 root dir is a cluster chain like any other directory */
955         buf_size = vs->sectors_per_cluster * sector_size;
956         root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
957         dbg("root dir cluster %u", root_cluster);
958         start_data_sect = reserved + fat_size;
959
960         next = root_cluster;
961         maxloop = 100;
962         while (--maxloop) {
963                 __u32 next_sect_off;
964                 __u64 next_off;
965                 __u64 fat_entry_off;
966                 int count;
967
968                 dbg("next cluster %u", next);
969                 next_sect_off = (next - 2) * vs->sectors_per_cluster;
970                 next_off = (start_data_sect + next_sect_off) * sector_size;
971                 dbg("cluster offset 0x%llx", next_off);
972
973                 /* get cluster */
974                 buf = get_buffer(id, off + next_off, buf_size);
975                 if (buf == NULL)
976                         goto found;
977
978                 dir = (struct vfat_dir_entry*) buf;
979                 count = buf_size / sizeof(struct vfat_dir_entry);
980                 dbg("expected entries 0x%x", count);
981
982                 for (i = 0; i <= count; i++) {
983                         /* end marker */
984                         if (dir[i].name[0] == 0x00) {
985                                 dbg("end of dir");
986                                 goto fat32_label;
987                         }
988
989                         /* empty entry */
990                         if (dir[i].name[0] == 0xe5)
991                                 continue;
992
993                         if (dir[i].attr == FAT_ATTR_VOLUME) {
994                                 dbg("found ATTR_VOLUME id in root dir");
995                                 label = dir[i].name;
996                                 goto fat32_label;
997                         }
998
999                         dbg("skip dir entry");
1000                 }
1001
1002                 /* get FAT entry */
1003                 fat_entry_off = (reserved * sector_size) + (next * sizeof(__u32));
1004                 buf = get_buffer(id, off + fat_entry_off, buf_size);
1005                 if (buf == NULL)
1006                         goto found;
1007
1008                 /* set next cluster */
1009                 next = le32_to_cpu(*((__u32 *) buf) & 0x0fffffff);
1010                 if (next == 0)
1011                         break;
1012         }
1013         if (maxloop == 0)
1014                 dbg("reached maximum follow count of root cluster chain, give up");
1015
1016 fat32_label:
1017         if (label != NULL && strncmp(label, "NO NAME    ", 11) != 0) {
1018                 set_label_raw(id, label, 11);
1019                 set_label_string(id, label, 11);
1020         } else if (strncmp(vs->type.fat32.label, "NO NAME    ", 11) == 0) {
1021                 set_label_raw(id, vs->type.fat32.label, 11);
1022                 set_label_string(id, vs->type.fat32.label, 11);
1023         }
1024         set_uuid(id, vs->type.fat32.serno, UUID_DOS);
1025
1026 found:
1027         id->usage_id = VOLUME_ID_FILESYSTEM;
1028         id->type_id = VOLUME_ID_VFAT;
1029         id->type = "vfat";
1030
1031         return 0;
1032 }
1033
1034 #define UDF_VSD_OFFSET                  0x8000
1035 static int probe_udf(struct volume_id *id, __u64 off)
1036 {
1037         struct volume_descriptor {
1038                 struct descriptor_tag {
1039                         __u16   id;
1040                         __u16   version;
1041                         __u8    checksum;
1042                         __u8    reserved;
1043                         __u16   serial;
1044                         __u16   crc;
1045                         __u16   crc_len;
1046                         __u32   location;
1047                 } __attribute__((__packed__)) tag;
1048                 union {
1049                         struct anchor_descriptor {
1050                                 __u32   length;
1051                                 __u32   location;
1052                         } __attribute__((__packed__)) anchor;
1053                         struct primary_descriptor {
1054                                 __u32   seq_num;
1055                                 __u32   desc_num;
1056                                 struct dstring {
1057                                         __u8    clen;
1058                                         __u8    c[31];
1059                                 } __attribute__((__packed__)) ident;
1060                         } __attribute__((__packed__)) primary;
1061                 } __attribute__((__packed__)) type;
1062         } __attribute__((__packed__)) *vd;
1063
1064         struct volume_structure_descriptor {
1065                 __u8    type;
1066                 __u8    id[5];
1067                 __u8    version;
1068         } *vsd;
1069
1070         unsigned int bs;
1071         unsigned int b;
1072         unsigned int type;
1073         unsigned int count;
1074         unsigned int loc;
1075         unsigned int clen;
1076
1077         vsd = (struct volume_structure_descriptor *)
1078               get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
1079         if (vsd == NULL)
1080                 return -1;
1081
1082         if (strncmp(vsd->id, "NSR02", 5) == 0)
1083                 goto blocksize;
1084         if (strncmp(vsd->id, "NSR03", 5) == 0)
1085                 goto blocksize;
1086         if (strncmp(vsd->id, "BEA01", 5) == 0)
1087                 goto blocksize;
1088         if (strncmp(vsd->id, "BOOT2", 5) == 0)
1089                 goto blocksize;
1090         if (strncmp(vsd->id, "CD001", 5) == 0)
1091                 goto blocksize;
1092         if (strncmp(vsd->id, "CDW02", 5) == 0)
1093                 goto blocksize;
1094         if (strncmp(vsd->id, "TEA03", 5) == 0)
1095                 goto blocksize;
1096         return -1;
1097
1098 blocksize:
1099         /* search the next VSD to get the logical block size of the volume */
1100         for (bs = 0x800; bs < 0x8000; bs += 0x800) {
1101                 vsd = (struct volume_structure_descriptor *)
1102                       get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
1103                 if (vsd == NULL)
1104                         return -1;
1105                 dbg("test for blocksize: 0x%x", bs);
1106                 if (vsd->id[0] != '\0')
1107                         goto nsr;
1108         }
1109         return -1;
1110
1111 nsr:
1112         /* search the list of VSDs for a NSR descriptor */
1113         for (b = 0; b < 64; b++) {
1114                 vsd = (struct volume_structure_descriptor *)
1115                       get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
1116                 if (vsd == NULL)
1117                         return -1;
1118
1119                 dbg("vsd: %c%c%c%c%c",
1120                     vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
1121
1122                 if (vsd->id[0] == '\0')
1123                         return -1;
1124                 if (strncmp(vsd->id, "NSR02", 5) == 0)
1125                         goto anchor;
1126                 if (strncmp(vsd->id, "NSR03", 5) == 0)
1127                         goto anchor;
1128         }
1129         return -1;
1130
1131 anchor:
1132         /* read anchor volume descriptor */
1133         vd = (struct volume_descriptor *)
1134                 get_buffer(id, off + (256 * bs), 0x200);
1135         if (vd == NULL)
1136                 return -1;
1137
1138         type = le16_to_cpu(vd->tag.id);
1139         if (type != 2) /* TAG_ID_AVDP */
1140                 goto found;
1141
1142         /* get desriptor list address and block count */
1143         count = le32_to_cpu(vd->type.anchor.length) / bs;
1144         loc = le32_to_cpu(vd->type.anchor.location);
1145         dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
1146
1147         /* pick the primary descriptor from the list */
1148         for (b = 0; b < count; b++) {
1149                 vd = (struct volume_descriptor *)
1150                      get_buffer(id, off + ((loc + b) * bs), 0x200);
1151                 if (vd == NULL)
1152                         return -1;
1153
1154                 type = le16_to_cpu(vd->tag.id);
1155                 dbg("descriptor type %i", type);
1156
1157                 /* check validity */
1158                 if (type == 0)
1159                         goto found;
1160                 if (le32_to_cpu(vd->tag.location) != loc + b)
1161                         goto found;
1162
1163                 if (type == 1) /* TAG_ID_PVD */
1164                         goto pvd;
1165         }
1166         goto found;
1167
1168 pvd:
1169         set_label_raw(id, &(vd->type.primary.ident.clen), 32);
1170
1171         clen = vd->type.primary.ident.clen;
1172         dbg("label string charsize=%i bit", clen);
1173         if (clen == 8)
1174                 set_label_string(id, vd->type.primary.ident.c, 31);
1175         else if (clen == 16)
1176                 set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
1177
1178 found:
1179         id->usage_id = VOLUME_ID_FILESYSTEM;
1180         id->type_id = VOLUME_ID_UDF;
1181         id->type = "udf";
1182
1183         return 0;
1184 }
1185
1186 #define ISO_SUPERBLOCK_OFFSET           0x8000
1187 static int probe_iso9660(struct volume_id *id, __u64 off)
1188 {
1189         union iso_super_block {
1190                 struct iso_header {
1191                         __u8    type;
1192                         __u8    id[5];
1193                         __u8    version;
1194                         __u8    unused1;
1195                         __u8            system_id[32];
1196                         __u8            volume_id[32];
1197                 } __attribute__((__packed__)) iso;
1198                 struct hs_header {
1199                         __u8    foo[8];
1200                         __u8    type;
1201                         __u8    id[4];
1202                         __u8    version;
1203                 } __attribute__((__packed__)) hs;
1204         } __attribute__((__packed__)) *is;
1205
1206         is = (union iso_super_block *)
1207              get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
1208         if (is == NULL)
1209                 return -1;
1210
1211         if (strncmp(is->iso.id, "CD001", 5) == 0) {
1212                 set_label_raw(id, is->iso.volume_id, 32);
1213                 set_label_string(id, is->iso.volume_id, 32);
1214                 goto found;
1215         }
1216         if (strncmp(is->hs.id, "CDROM", 5) == 0)
1217                 goto found;
1218         return -1;
1219
1220 found:
1221         id->usage_id = VOLUME_ID_FILESYSTEM;
1222         id->type_id = VOLUME_ID_ISO9660;
1223         id->type = "iso9660";
1224
1225         return 0;
1226 }
1227
1228 #define UFS_MAGIC                       0x00011954
1229 #define UFS2_MAGIC                      0x19540119
1230 #define UFS_MAGIC_FEA                   0x00195612
1231 #define UFS_MAGIC_LFN                   0x00095014
1232
1233
1234 static int probe_ufs(struct volume_id *id, __u64 off)
1235 {
1236         struct ufs_super_block {
1237                 __u32   fs_link;
1238                 __u32   fs_rlink;
1239                 __u32   fs_sblkno;
1240                 __u32   fs_cblkno;
1241                 __u32   fs_iblkno;
1242                 __u32   fs_dblkno;
1243                 __u32   fs_cgoffset;
1244                 __u32   fs_cgmask;
1245                 __u32   fs_time;
1246                 __u32   fs_size;
1247                 __u32   fs_dsize;
1248                 __u32   fs_ncg; 
1249                 __u32   fs_bsize;
1250                 __u32   fs_fsize;
1251                 __u32   fs_frag;
1252                 __u32   fs_minfree;
1253                 __u32   fs_rotdelay;
1254                 __u32   fs_rps; 
1255                 __u32   fs_bmask;
1256                 __u32   fs_fmask;
1257                 __u32   fs_bshift;
1258                 __u32   fs_fshift;
1259                 __u32   fs_maxcontig;
1260                 __u32   fs_maxbpg;
1261                 __u32   fs_fragshift;
1262                 __u32   fs_fsbtodb;
1263                 __u32   fs_sbsize;
1264                 __u32   fs_csmask;
1265                 __u32   fs_csshift;
1266                 __u32   fs_nindir;
1267                 __u32   fs_inopb;
1268                 __u32   fs_nspf;
1269                 __u32   fs_optim;
1270                 __u32   fs_npsect_state;
1271                 __u32   fs_interleave;
1272                 __u32   fs_trackskew;
1273                 __u32   fs_id[2];
1274                 __u32   fs_csaddr;
1275                 __u32   fs_cssize;
1276                 __u32   fs_cgsize;
1277                 __u32   fs_ntrak;
1278                 __u32   fs_nsect;
1279                 __u32   fs_spc; 
1280                 __u32   fs_ncyl;
1281                 __u32   fs_cpg;
1282                 __u32   fs_ipg;
1283                 __u32   fs_fpg;
1284                 struct ufs_csum {
1285                         __u32   cs_ndir;
1286                         __u32   cs_nbfree;
1287                         __u32   cs_nifree;
1288                         __u32   cs_nffree;
1289                 } __attribute__((__packed__)) fs_cstotal;
1290                 __s8    fs_fmod;
1291                 __s8    fs_clean;
1292                 __s8    fs_ronly;
1293                 __s8    fs_flags;
1294                 union {
1295                         struct {
1296                                 __s8    fs_fsmnt[512];
1297                                 __u32   fs_cgrotor;
1298                                 __u32   fs_csp[31];
1299                                 __u32   fs_maxcluster;
1300                                 __u32   fs_cpc;
1301                                 __u16   fs_opostbl[16][8];
1302                         } __attribute__((__packed__)) fs_u1;
1303                         struct {
1304                                 __s8  fs_fsmnt[468];
1305                                 __u8   fs_volname[32];
1306                                 __u64  fs_swuid;
1307                                 __s32  fs_pad;
1308                                 __u32   fs_cgrotor;
1309                                 __u32   fs_ocsp[28];
1310                                 __u32   fs_contigdirs;
1311                                 __u32   fs_csp; 
1312                                 __u32   fs_maxcluster;
1313                                 __u32   fs_active;
1314                                 __s32   fs_old_cpc;
1315                                 __s32   fs_maxbsize;
1316                                 __s64   fs_sparecon64[17];
1317                                 __s64   fs_sblockloc;
1318                                 struct  ufs2_csum_total {
1319                                         __u64   cs_ndir;
1320                                         __u64   cs_nbfree;
1321                                         __u64   cs_nifree;
1322                                         __u64   cs_nffree;
1323                                         __u64   cs_numclusters;
1324                                         __u64   cs_spare[3];
1325                                 } __attribute__((__packed__)) fs_cstotal;
1326                                 struct  ufs_timeval {
1327                                         __s32   tv_sec;
1328                                         __s32   tv_usec;
1329                                 } __attribute__((__packed__)) fs_time;
1330                                 __s64    fs_size;
1331                                 __s64    fs_dsize;
1332                                 __u64    fs_csaddr;
1333                                 __s64    fs_pendingblocks;
1334                                 __s32    fs_pendinginodes;
1335                         } __attribute__((__packed__)) fs_u2;
1336                 }  fs_u11;
1337                 union {
1338                         struct {
1339                                 __s32   fs_sparecon[53];
1340                                 __s32   fs_reclaim;
1341                                 __s32   fs_sparecon2[1];
1342                                 __s32   fs_state;
1343                                 __u32   fs_qbmask[2];
1344                                 __u32   fs_qfmask[2];
1345                         } __attribute__((__packed__)) fs_sun;
1346                         struct {
1347                                 __s32   fs_sparecon[53];
1348                                 __s32   fs_reclaim;
1349                                 __s32   fs_sparecon2[1];
1350                                 __u32   fs_npsect;
1351                                 __u32   fs_qbmask[2];
1352                                 __u32   fs_qfmask[2];
1353                         } __attribute__((__packed__)) fs_sunx86;
1354                         struct {
1355                                 __s32   fs_sparecon[50];
1356                                 __s32   fs_contigsumsize;
1357                                 __s32   fs_maxsymlinklen;
1358                                 __s32   fs_inodefmt;
1359                                 __u32   fs_maxfilesize[2];
1360                                 __u32   fs_qbmask[2];
1361                                 __u32   fs_qfmask[2];
1362                                 __s32   fs_state;
1363                         } __attribute__((__packed__)) fs_44;
1364                 } fs_u2;
1365                 __s32   fs_postblformat;
1366                 __s32   fs_nrpos;
1367                 __s32   fs_postbloff;
1368                 __s32   fs_rotbloff;
1369                 __u32   fs_magic;
1370                 __u8    fs_space[1];
1371         } __attribute__((__packed__)) *ufs;
1372
1373         __u32   magic;
1374         int     i;
1375         int     offsets[] = {0, 8, 64, 256, -1};
1376
1377         for (i = 0; offsets[i] >= 0; i++) {     
1378                 ufs = (struct ufs_super_block *)
1379                         get_buffer(id, off + (offsets[i] * 0x400), 0x800);
1380                 if (ufs == NULL)
1381                         return -1;
1382
1383                 dbg("offset 0x%x", offsets[i] * 0x400);
1384                 magic = be32_to_cpu(ufs->fs_magic);
1385                 if ((magic == UFS_MAGIC) ||
1386                     (magic == UFS2_MAGIC) ||
1387                     (magic == UFS_MAGIC_FEA) ||
1388                     (magic == UFS_MAGIC_LFN)) {
1389                         dbg("magic 0x%08x(be)", magic);
1390                         goto found;
1391                 }
1392                 magic = le32_to_cpu(ufs->fs_magic);
1393                 if ((magic == UFS_MAGIC) ||
1394                     (magic == UFS2_MAGIC) ||
1395                     (magic == UFS_MAGIC_FEA) ||
1396                     (magic == UFS_MAGIC_LFN)) {
1397                         dbg("magic 0x%08x(le)", magic);
1398                         goto found;
1399                 }
1400         }
1401         return -1;
1402
1403 found:
1404         id->usage_id = VOLUME_ID_FILESYSTEM;
1405         id->type_id = VOLUME_ID_UFS;
1406         id->type = "ufs";
1407
1408         return 0;
1409 }
1410
1411 static int probe_mac_partition_map(struct volume_id *id, __u64 off)
1412 {
1413         struct mac_driver_desc {
1414                 __u8    signature[2];
1415                 __u16   block_size;
1416                 __u32   block_count;
1417         } __attribute__((__packed__)) *driver;
1418
1419         struct mac_partition {
1420                 __u8    signature[2];
1421                 __u16   res1;
1422                 __u32   map_count;
1423                 __u32   start_block;
1424                 __u32   block_count;
1425                 __u8    name[32];
1426                 __u8    type[32];
1427         } __attribute__((__packed__)) *part;
1428
1429         const __u8 *buf;
1430
1431         buf = get_buffer(id, off, 0x200);
1432         if (buf == NULL)
1433                 return -1;
1434
1435         part = (struct mac_partition *) buf;
1436         if ((strncmp(part->signature, "PM", 2) == 0) &&
1437             (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
1438                 /* linux creates an own subdevice for the map
1439                  * just return the type if the drive header is missing */
1440                 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1441                 id->type_id = VOLUME_ID_MACPARTMAP;
1442                 id->type = "mac_partition_map";
1443                 return 0;
1444         }
1445
1446         driver = (struct mac_driver_desc *) buf;
1447         if (strncmp(driver->signature, "ER", 2) == 0) {
1448                 /* we are on a main device, like a CD
1449                  * just try to probe the first partition from the map */
1450                 unsigned int bsize = be16_to_cpu(driver->block_size);
1451                 int part_count;
1452                 int i;
1453
1454                 /* get first entry of partition table */
1455                 buf = get_buffer(id, off +  bsize, 0x200);
1456                 if (buf == NULL)
1457                         return -1;
1458
1459                 part = (struct mac_partition *) buf;
1460                 if (strncmp(part->signature, "PM", 2) != 0)
1461                         return -1;
1462
1463                 part_count = be32_to_cpu(part->map_count);
1464                 dbg("expecting %d partition entries", part_count);
1465
1466                 if (id->partitions != NULL)
1467                         free(id->partitions);
1468                 id->partitions =
1469                         malloc(part_count * sizeof(struct volume_id_partition));
1470                 if (id->partitions == NULL)
1471                         return -1;
1472                 memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
1473
1474                 id->partition_count = part_count;
1475
1476                 for (i = 0; i < part_count; i++) {
1477                         __u64 poff;
1478                         __u64 plen;
1479
1480                         buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
1481                         if (buf == NULL)
1482                                 return -1;
1483
1484                         part = (struct mac_partition *) buf;
1485                         if (strncmp(part->signature, "PM", 2) != 0)
1486                                 return -1;
1487
1488                         poff = be32_to_cpu(part->start_block) * bsize;
1489                         plen = be32_to_cpu(part->block_count) * bsize;
1490                         dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
1491                             part->type, poff, plen);
1492
1493                         id->partitions[i].off = poff;
1494                         id->partitions[i].len = plen;
1495
1496                         if (strncmp(part->type, "Apple_Free", 10) == 0) {
1497                                 id->partitions[i].usage_id = VOLUME_ID_UNUSED;
1498                         } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
1499                                 id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
1500                                 id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
1501                         } else {
1502                                 id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
1503                         }
1504                 }
1505                 id->usage_id = VOLUME_ID_PARTITIONTABLE;
1506                 id->type_id = VOLUME_ID_MACPARTMAP;
1507                 id->type = "mac_partition_map";
1508                 return 0;
1509         }
1510
1511         return -1;
1512 }
1513
1514 #define HFS_SUPERBLOCK_OFFSET           0x400
1515 #define HFS_NODE_LEAF                   0xff
1516 #define HFSPLUS_POR_CNID                1
1517 #define HFSPLUS_EXTENT_COUNT            8
1518 static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
1519 {
1520         struct hfs_finder_info{
1521                 __u32   boot_folder;
1522                 __u32   start_app;
1523                 __u32   open_folder;
1524                 __u32   os9_folder;
1525                 __u32   reserved;
1526                 __u32   osx_folder;
1527                 __u8    id[8];
1528         } __attribute__((__packed__));
1529
1530         struct hfs_mdb {
1531                 __u8    signature[2];
1532                 __u32   cr_date;
1533                 __u32   ls_Mod;
1534                 __u16   atrb;
1535                 __u16   nm_fls;
1536                 __u16   vbm_st;
1537                 __u16   alloc_ptr;
1538                 __u16   nm_al_blks;
1539                 __u32   al_blk_size;
1540                 __u32   clp_size;
1541                 __u16   al_bl_st;
1542                 __u32   nxt_cnid;
1543                 __u16   free_bks;
1544                 __u8    label_len;
1545                 __u8    label[27];
1546                 __u32   vol_bkup;
1547                 __u16   vol_seq_num;
1548                 __u32   wr_cnt;
1549                 __u32   xt_clump_size;
1550                 __u32   ct_clump_size;
1551                 __u16   num_root_dirs;
1552                 __u32   file_count;
1553                 __u32   dir_count;
1554                 struct hfs_finder_info finder_info;
1555                 __u8    embed_sig[2];
1556                 __u16   embed_startblock;
1557                 __u16   embed_blockcount;
1558         } __attribute__((__packed__)) *hfs;
1559
1560         struct hfsplus_bnode_descriptor {
1561                 __u32   next;
1562                 __u32   prev;
1563                 __u8    type;
1564                 __u8    height;
1565                 __u16   num_recs;
1566                 __u16   reserved;
1567         } __attribute__((__packed__));
1568
1569         struct hfsplus_bheader_record {
1570                 __u16   depth;
1571                 __u32   root;
1572                 __u32   leaf_count;
1573                 __u32   leaf_head;
1574                 __u32   leaf_tail;
1575                 __u16   node_size;
1576         } __attribute__((__packed__));
1577
1578         struct hfsplus_catalog_key {
1579                 __u16   key_len;
1580                 __u32   parent_id;
1581                 __u16   unicode_len;
1582                 __u8    unicode[255 * 2];
1583         } __attribute__((__packed__));
1584
1585         struct hfsplus_extent {
1586                 __u32 start_block;
1587                 __u32 block_count;
1588         } __attribute__((__packed__));
1589
1590         struct hfsplus_fork {
1591                 __u64 total_size;
1592                 __u32 clump_size;
1593                 __u32 total_blocks;
1594                 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1595         } __attribute__((__packed__));
1596
1597         struct hfsplus_vol_header {
1598                 __u8    signature[2];
1599                 __u16   version;
1600                 __u32   attributes;
1601                 __u32   last_mount_vers;
1602                 __u32   reserved;
1603                 __u32   create_date;
1604                 __u32   modify_date;
1605                 __u32   backup_date;
1606                 __u32   checked_date;
1607                 __u32   file_count;
1608                 __u32   folder_count;
1609                 __u32   blocksize;
1610                 __u32   total_blocks;
1611                 __u32   free_blocks;
1612                 __u32   next_alloc;
1613                 __u32   rsrc_clump_sz;
1614                 __u32   data_clump_sz;
1615                 __u32   next_cnid;
1616                 __u32   write_count;
1617                 __u64   encodings_bmp;
1618                 struct hfs_finder_info finder_info;
1619                 struct hfsplus_fork alloc_file;
1620                 struct hfsplus_fork ext_file;
1621                 struct hfsplus_fork cat_file;
1622                 struct hfsplus_fork attr_file;
1623                 struct hfsplus_fork start_file;
1624         } __attribute__((__packed__)) *hfsplus;
1625
1626         unsigned int blocksize;
1627         unsigned int cat_block;
1628         unsigned int ext_block_start;
1629         unsigned int ext_block_count;
1630         int ext;
1631         unsigned int leaf_node_head;
1632         unsigned int leaf_node_count;
1633         unsigned int leaf_node_size;
1634         unsigned int leaf_block;
1635         __u64 leaf_off;
1636         unsigned int alloc_block_size;
1637         unsigned int alloc_first_block;
1638         unsigned int embed_first_block;
1639         unsigned int record_count;
1640         struct hfsplus_bnode_descriptor *descr;
1641         struct hfsplus_bheader_record *bnode;
1642         struct hfsplus_catalog_key *key;
1643         unsigned int    label_len;
1644         struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
1645         const __u8 *buf;
1646
1647         buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1648         if (buf == NULL)
1649                 return -1;
1650
1651         hfs = (struct hfs_mdb *) buf;
1652         if (strncmp(hfs->signature, "BD", 2) != 0)
1653                 goto checkplus;
1654
1655         /* it may be just a hfs wrapper for hfs+ */
1656         if (strncmp(hfs->embed_sig, "H+", 2) == 0) {
1657                 alloc_block_size = be32_to_cpu(hfs->al_blk_size);
1658                 dbg("alloc_block_size 0x%x", alloc_block_size);
1659
1660                 alloc_first_block = be16_to_cpu(hfs->al_bl_st);
1661                 dbg("alloc_first_block 0x%x", alloc_first_block);
1662
1663                 embed_first_block = be16_to_cpu(hfs->embed_startblock);
1664                 dbg("embed_first_block 0x%x", embed_first_block);
1665
1666                 off += (alloc_first_block * 512) +
1667                        (embed_first_block * alloc_block_size);
1668                 dbg("hfs wrapped hfs+ found at offset 0x%llx", off);
1669
1670                 buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
1671                 if (buf == NULL)
1672                         return -1;
1673                 goto checkplus;
1674         }
1675
1676         if (hfs->label_len > 0 && hfs->label_len < 28) {
1677                 set_label_raw(id, hfs->label, hfs->label_len);
1678                 set_label_string(id, hfs->label, hfs->label_len) ;
1679         }
1680
1681         set_uuid(id, hfs->finder_info.id, UUID_HFS);
1682
1683         id->usage_id = VOLUME_ID_FILESYSTEM;
1684         id->type_id = VOLUME_ID_HFS;
1685         id->type = "hfs";
1686
1687         return 0;
1688
1689 checkplus:
1690         hfsplus = (struct hfsplus_vol_header *) buf;
1691         if (strncmp(hfsplus->signature, "H+", 2) == 0)
1692                 goto hfsplus;
1693         if (strncmp(hfsplus->signature, "HX", 2) == 0)
1694                 goto hfsplus;
1695         return -1;
1696
1697 hfsplus:
1698         set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
1699
1700         blocksize = be32_to_cpu(hfsplus->blocksize);
1701         dbg("blocksize %u", blocksize);
1702
1703         memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
1704         cat_block = be32_to_cpu(extents[0].start_block);
1705         dbg("catalog start block 0x%x", cat_block);
1706
1707         buf = get_buffer(id, off + (cat_block * blocksize), 0x2000);
1708         if (buf == NULL)
1709                 goto found;
1710
1711         bnode = (struct hfsplus_bheader_record *)
1712                 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1713
1714         leaf_node_head = be32_to_cpu(bnode->leaf_head);
1715         dbg("catalog leaf node 0x%x", leaf_node_head);
1716
1717         leaf_node_size = be16_to_cpu(bnode->node_size);
1718         dbg("leaf node size 0x%x", leaf_node_size);
1719
1720         leaf_node_count = be32_to_cpu(bnode->leaf_count);
1721         dbg("leaf node count 0x%x", leaf_node_count);
1722         if (leaf_node_count == 0)
1723                 goto found;
1724
1725         leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
1726
1727         /* get physical location */
1728         for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
1729                 ext_block_start = be32_to_cpu(extents[ext].start_block);
1730                 ext_block_count = be32_to_cpu(extents[ext].block_count);
1731                 dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
1732
1733                 if (ext_block_count == 0)
1734                         goto found;
1735
1736                 /* this is our extent */
1737                 if (leaf_block < ext_block_count)
1738                         break;
1739
1740                 leaf_block -= ext_block_count;
1741         }
1742         if (ext == HFSPLUS_EXTENT_COUNT)
1743                 goto found;
1744         dbg("found block in extent %i", ext);
1745
1746         leaf_off = (ext_block_start + leaf_block) * blocksize;
1747
1748         buf = get_buffer(id, off + leaf_off, leaf_node_size);
1749         if (buf == NULL)
1750                 goto found;
1751
1752         descr = (struct hfsplus_bnode_descriptor *) buf;
1753         dbg("descriptor type 0x%x", descr->type);
1754
1755         record_count = be16_to_cpu(descr->num_recs);
1756         dbg("number of records %u", record_count);
1757         if (record_count == 0)
1758                 goto found;
1759
1760         if (descr->type != HFS_NODE_LEAF)
1761                 goto found;
1762
1763         key = (struct hfsplus_catalog_key *)
1764                 &buf[sizeof(struct hfsplus_bnode_descriptor)];
1765
1766         dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
1767         if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
1768                 goto found;
1769
1770         label_len = be16_to_cpu(key->unicode_len) * 2;
1771         dbg("label unicode16 len %i", label_len);
1772         set_label_raw(id, key->unicode, label_len);
1773         set_label_unicode16(id, key->unicode, BE, label_len);
1774
1775 found:
1776         id->usage_id = VOLUME_ID_FILESYSTEM;
1777         id->type_id = VOLUME_ID_HFSPLUS;
1778         id->type = "hfsplus";
1779
1780         return 0;
1781 }
1782
1783 #define MFT_RECORD_VOLUME                       3
1784 #define MFT_RECORD_ATTR_VOLUME_NAME             0x60
1785 #define MFT_RECORD_ATTR_VOLUME_INFO             0x70
1786 #define MFT_RECORD_ATTR_OBJECT_ID               0x40
1787 #define MFT_RECORD_ATTR_END                     0xffffffffu
1788 static int probe_ntfs(struct volume_id *id, __u64 off)
1789 {
1790         struct ntfs_super_block {
1791                 __u8    jump[3];
1792                 __u8    oem_id[8];
1793                 __u16   bytes_per_sector;
1794                 __u8    sectors_per_cluster;
1795                 __u16   reserved_sectors;
1796                 __u8    fats;
1797                 __u16   root_entries;
1798                 __u16   sectors;
1799                 __u8    media_type;
1800                 __u16   sectors_per_fat;
1801                 __u16   sectors_per_track;
1802                 __u16   heads;
1803                 __u32   hidden_sectors;
1804                 __u32   large_sectors;
1805                 __u16   unused[2];
1806                 __u64   number_of_sectors;
1807                 __u64   mft_cluster_location;
1808                 __u64   mft_mirror_cluster_location;
1809                 __s8    cluster_per_mft_record;
1810                 __u8    reserved1[3];
1811                 __s8    cluster_per_index_record;
1812                 __u8    reserved2[3];
1813                 __u8    volume_serial[8];
1814                 __u16   checksum;
1815         } __attribute__((__packed__)) *ns;
1816
1817         struct master_file_table_record {
1818                 __u8    magic[4];
1819                 __u16   usa_ofs;
1820                 __u16   usa_count;
1821                 __u64   lsn;
1822                 __u16   sequence_number;
1823                 __u16   link_count;
1824                 __u16   attrs_offset;
1825                 __u16   flags;
1826                 __u32   bytes_in_use;
1827                 __u32   bytes_allocated;
1828         } __attribute__((__packed__)) *mftr;
1829
1830         struct file_attribute {
1831                 __u32   type;
1832                 __u32   len;
1833                 __u8    non_resident;
1834                 __u8    name_len;
1835                 __u16   name_offset;
1836                 __u16   flags;
1837                 __u16   instance;
1838                 __u32   value_len;
1839                 __u16   value_offset;
1840         } __attribute__((__packed__)) *attr;
1841
1842         struct volume_info {
1843                 __u64 reserved;
1844                 __u8 major_ver;
1845                 __u8 minor_ver;
1846         } __attribute__((__packed__)) *info;
1847
1848         unsigned int sector_size;
1849         unsigned int cluster_size;
1850         __u64 mft_cluster;
1851         __u64 mft_off;
1852         unsigned int mft_record_size;
1853         unsigned int attr_type;
1854         unsigned int attr_off;
1855         unsigned int attr_len;
1856         unsigned int val_off;
1857         unsigned int val_len;
1858         const __u8 *buf;
1859         const __u8 *val;
1860
1861         ns = (struct ntfs_super_block *) get_buffer(id, off, 0x200);
1862         if (ns == NULL)
1863                 return -1;
1864
1865         if (strncmp(ns->oem_id, "NTFS", 4) != 0)
1866                 return -1;
1867
1868         set_uuid(id, ns->volume_serial, UUID_NTFS);
1869
1870         sector_size = le16_to_cpu(ns->bytes_per_sector);
1871         cluster_size = ns->sectors_per_cluster * sector_size;
1872         mft_cluster = le64_to_cpu(ns->mft_cluster_location);
1873         mft_off = mft_cluster * cluster_size;
1874
1875         if (ns->cluster_per_mft_record < 0)
1876                 /* size = -log2(mft_record_size); normally 1024 Bytes */
1877                 mft_record_size = 1 << -ns->cluster_per_mft_record;
1878         else
1879                 mft_record_size = ns->cluster_per_mft_record * cluster_size;
1880
1881         dbg("sectorsize  0x%x", sector_size);
1882         dbg("clustersize 0x%x", cluster_size);
1883         dbg("mftcluster  %lli", mft_cluster);
1884         dbg("mftoffset  0x%llx", mft_off);
1885         dbg("cluster per mft_record  %i", ns->cluster_per_mft_record);
1886         dbg("mft record size  %i", mft_record_size);
1887
1888         buf = get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
1889                          mft_record_size);
1890         if (buf == NULL)
1891                 goto found;
1892
1893         mftr = (struct master_file_table_record*) buf;
1894
1895         dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
1896         if (strncmp(mftr->magic, "FILE", 4) != 0)
1897                 goto found;
1898
1899         attr_off = le16_to_cpu(mftr->attrs_offset);
1900         dbg("file $Volume's attributes are at offset %i", attr_off);
1901
1902         while (1) {
1903                 attr = (struct file_attribute*) &buf[attr_off];
1904                 attr_type = le32_to_cpu(attr->type);
1905                 attr_len = le16_to_cpu(attr->len);
1906                 val_off = le16_to_cpu(attr->value_offset);
1907                 val_len = le32_to_cpu(attr->value_len);
1908                 attr_off += attr_len;
1909
1910                 if (attr_len == 0)
1911                         break;
1912
1913                 if (attr_off >= mft_record_size)
1914                         break;
1915
1916                 if (attr_type == MFT_RECORD_ATTR_END)
1917                         break;
1918
1919                 dbg("found attribute type 0x%x, len %i, at offset %i",
1920                     attr_type, attr_len, attr_off);
1921
1922                 if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
1923                         dbg("found info, len %i", val_len);
1924                         info = (struct volume_info*) (((__u8 *) attr) + val_off);
1925                         snprintf(id->type_version, VOLUME_ID_FORMAT_SIZE-1,
1926                                  "%u.%u", info->major_ver, info->minor_ver);
1927                 }
1928
1929                 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
1930                         dbg("found label, len %i", val_len);
1931                         if (val_len > VOLUME_ID_LABEL_SIZE)
1932                                 val_len = VOLUME_ID_LABEL_SIZE;
1933
1934                         val = ((__u8 *) attr) + val_off;
1935                         set_label_raw(id, val, val_len);
1936                         set_label_unicode16(id, val, LE, val_len);
1937                 }
1938         }
1939
1940 found:
1941         id->usage_id = VOLUME_ID_FILESYSTEM;
1942         id->type_id = VOLUME_ID_NTFS;
1943         id->type = "ntfs";
1944
1945         return 0;
1946 }
1947
1948 #define LARGEST_PAGESIZE                        0x4000
1949 static int probe_swap(struct volume_id *id, __u64 off)
1950 {
1951         const __u8 *sig;
1952         unsigned int page;
1953
1954         /* huhh, the swap signature is on the end of the PAGE_SIZE */
1955         for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
1956                         sig = get_buffer(id, off + page-10, 10);
1957                         if (sig == NULL)
1958                                 return -1;
1959
1960                         if (strncmp(sig, "SWAP-SPACE", 10) == 0) {
1961                                 strcpy(id->type_version, "1");
1962                                 goto found;
1963                         }
1964                         if (strncmp(sig, "SWAPSPACE2", 10) == 0) {
1965                                 strcpy(id->type_version, "2");
1966                                 goto found;
1967                         }
1968         }
1969         return -1;
1970
1971 found:
1972         id->usage_id = VOLUME_ID_OTHER;
1973         id->type_id = VOLUME_ID_SWAP;
1974         id->type = "swap";
1975
1976         return 0;
1977 }
1978
1979 /* probe volume for filesystem type and try to read label+uuid */
1980 int volume_id_probe(struct volume_id *id,
1981                     enum volume_id_type type,
1982                     unsigned long long off,
1983                     unsigned long long size)
1984 {
1985         int rc;
1986
1987         if (id == NULL)
1988                 return -EINVAL;
1989
1990         switch (type) {
1991         case VOLUME_ID_MSDOSPARTTABLE:
1992                 rc = probe_msdos_part_table(id, off);
1993                 break;
1994         case VOLUME_ID_EXT3:
1995         case VOLUME_ID_EXT2:
1996                 rc = probe_ext(id, off);
1997                 break;
1998         case VOLUME_ID_REISERFS:
1999                 rc = probe_reiserfs(id, off);
2000                 break;
2001         case VOLUME_ID_XFS:
2002                 rc = probe_xfs(id, off);
2003                 break;
2004         case VOLUME_ID_JFS:
2005                 rc = probe_jfs(id, off);
2006                 break;
2007         case VOLUME_ID_VFAT:
2008                 rc = probe_vfat(id, off);
2009                 break;
2010         case VOLUME_ID_UDF:
2011                 rc = probe_udf(id, off);
2012                 break;
2013         case VOLUME_ID_ISO9660:
2014                 rc = probe_iso9660(id, off);
2015                 break;
2016         case VOLUME_ID_MACPARTMAP:
2017                 rc = probe_mac_partition_map(id, off);
2018                 break;
2019         case VOLUME_ID_HFS:
2020         case VOLUME_ID_HFSPLUS:
2021                 rc = probe_hfs_hfsplus(id, off);
2022                 break;
2023         case VOLUME_ID_UFS:
2024                 rc = probe_ufs(id, off);
2025                 break;
2026         case VOLUME_ID_NTFS:
2027                 rc = probe_ntfs(id, off);
2028                 break;
2029         case VOLUME_ID_SWAP:
2030                 rc = probe_swap(id, off);
2031                 break;
2032         case VOLUME_ID_LINUX_RAID:
2033                 rc = probe_linux_raid(id, off, size);
2034                 break;
2035         case VOLUME_ID_LVM1:
2036                 rc = probe_lvm1(id, off);
2037                 break;
2038         case VOLUME_ID_LVM2:
2039                 rc = probe_lvm2(id, off);
2040                 break;
2041         case VOLUME_ID_ALL:
2042         default:
2043                 /* probe for raid first, cause fs probes may be successful on raid members */
2044                 rc = probe_linux_raid(id, off, size);
2045                 if (rc == 0)
2046                         break;
2047                 rc = probe_lvm1(id, off);
2048                 if (rc == 0)
2049                         break;
2050                 rc = probe_lvm2(id, off);
2051                 if (rc == 0)
2052                         break;
2053
2054                 /* signature in the first block, only small buffer needed */
2055                 rc = probe_msdos_part_table(id, off);
2056                 if (rc == 0)
2057                         break;
2058                 rc = probe_ntfs(id, off);
2059                 if (rc == 0)
2060                         break;
2061                 rc = probe_vfat(id, off);
2062                 if (rc == 0)
2063                         break;
2064                 rc = probe_mac_partition_map(id, off);
2065                 if (rc == 0)
2066                         break;
2067                 rc = probe_xfs(id, off);
2068                 if (rc == 0)
2069                         break;
2070
2071                 /* fill buffer with maximum */
2072                 get_buffer(id, 0, SB_BUFFER_SIZE);
2073
2074                 rc = probe_swap(id, off);
2075                 if (rc == 0)
2076                         break;
2077                 rc = probe_ext(id, off);
2078                 if (rc == 0)
2079                         break;
2080                 rc = probe_reiserfs(id, off);
2081                 if (rc == 0)
2082                         break;
2083                 rc = probe_jfs(id, off);
2084                 if (rc == 0)
2085                         break;
2086                 rc = probe_udf(id, off);
2087                 if (rc == 0)
2088                         break;
2089                 rc = probe_iso9660(id, off);
2090                 if (rc == 0)
2091                         break;
2092                 rc = probe_hfs_hfsplus(id, off);
2093                 if (rc == 0)
2094                         break;
2095                 rc = probe_ufs(id, off);
2096                 if (rc == 0)
2097                         break;
2098
2099                 rc = -1;
2100         }
2101
2102         /* If the filestystem in recognized, we free the allocated buffers,
2103            otherwise they will stay in place for the possible next probe call */
2104         if (rc == 0)
2105                 free_buffer(id);
2106
2107         return rc;
2108 }
2109
2110 /* open volume by already open file descriptor */
2111 struct volume_id *volume_id_open_fd(int fd)
2112 {
2113         struct volume_id *id;
2114
2115         id = malloc(sizeof(struct volume_id));
2116         if (id == NULL)
2117                 return NULL;
2118         memset(id, 0x00, sizeof(struct volume_id));
2119
2120         id->fd = fd;
2121
2122         return id;
2123 }
2124
2125 /* open volume by device node */
2126 struct volume_id *volume_id_open_node(const char *path)
2127 {
2128         struct volume_id *id;
2129         int fd;
2130
2131         fd = open(path, O_RDONLY);
2132         if (fd < 0) {
2133                 dbg("unable to open '%s'", path);
2134                 return NULL;
2135         }
2136
2137         id = volume_id_open_fd(fd);
2138         if (id == NULL)
2139                 return NULL;
2140
2141         /* close fd on device close */
2142         id->fd_close = 1;
2143
2144         return id;
2145 }
2146
2147 /* open volume by major/minor */
2148 struct volume_id *volume_id_open_dev_t(dev_t devt)
2149 {
2150         struct volume_id *id;
2151         __u8 tmp_node[VOLUME_ID_PATH_MAX];
2152
2153         snprintf(tmp_node, VOLUME_ID_PATH_MAX,
2154                  "/tmp/volume-%u-%u-%u", getpid(), major(devt), minor(devt));
2155         tmp_node[VOLUME_ID_PATH_MAX] = '\0';
2156
2157         /* create tempory node to open the block device */
2158         unlink(tmp_node);
2159         if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0)
2160                 return NULL;
2161
2162         id = volume_id_open_node(tmp_node);
2163
2164         unlink(tmp_node);
2165
2166         return id;
2167 }
2168
2169 /* free allocated volume info */
2170 void volume_id_close(struct volume_id *id)
2171 {
2172         if (id == NULL)
2173                 return;
2174
2175         if (id->fd_close != 0)
2176                 close(id->fd);
2177
2178         free_buffer(id);
2179
2180         if (id->partitions != NULL)
2181                 free(id->partitions);
2182
2183         free(id);
2184 }