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