disktype-9/0000775000076500007650000000000010440762150013675 5ustar chrispchrisp00000000000000disktype-9/amiga.c0000664000076500007650000001736710362000212015120 0ustar chrispchrisp00000000000000/* * amiga.c * Detection of Amiga partition maps and file systems * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * Amiga partition type codes * * Based on the dostypes list of the Ambient file manager * as of Apr 02, 2005. */ struct dostype { char *typecode; int isfs; /* true = native Amiga filesystem (affects printout when */ /* found at the start of the boot sector) */ char *name; }; struct dostype amiga_dostypes[] = { { "DOS\x00", 1, "Amiga OFS file system (non-intl.)" }, { "DOS\x01", 1, "Amiga FFS file system (non-intl.)" }, { "DOS\x02", 1, "Amiga OFS file system (intl., no dir cache)" }, { "DOS\x03", 1, "Amiga FFS file system (intl., no dir cache)" }, { "DOS\x04", 1, "Amiga OFS file system (intl., dir cache)" }, { "DOS\x05", 1, "Amiga FFS file system (intl., dir cache)" }, { "DOS\x06", 1, "Amiga OFS file system (LNFS)" }, { "DOS\x07", 1, "Amiga FFS file system (LNFS)" }, { "muFS", 1, "Amiga muFS FFS file system (intl., no dir cache)" }, { "muF\x00", 1, "Amiga muFS OFS file system (non-intl.)" }, { "muF\x01", 1, "Amiga muFS FFS file system (non-intl.)" }, { "muF\x02", 1, "Amiga muFS OFS file system (intl., no dir cache)" }, { "muF\x03", 1, "Amiga muFS FFS file system (intl., no dir cache)" }, { "muF\x04", 1, "Amiga muFS OFS file system (intl., dir cache)" }, { "muF\x05", 1, "Amiga muFS FFS file system (intl., dir cache)" }, { "SFS\x00", 1, "Amiga Smart File System" }, { "PFS\x00", 1, "Amiga PFS file system 0" }, { "PFS\x01", 1, "Amiga PFS file system 1" }, { "PFS\x02", 1, "Amiga PFS file system 2" }, { "PFS\x03", 1, "Amiga PFS file system 3" }, { "PDS\x02", 1, "Amiga PFS file system 2, SCSIdirect" }, { "PDS\x03", 1, "Amiga PFS file system 3, SCSIdirect" }, { "muPF", 1, "Amiga PFS file system, multiuser" }, { "AFS\x00", 1, "Amiga AFS file system" }, { "AFS\x01", 1, "Amiga AFS file system (experimental)" }, { "UNI\x00", 0, "Amiga Amix 0" }, { "UNI\x01", 0, "Amiga Amix 1" }, { "KICK", 1, "Amiga Kickstart disk" }, { "BOOU", 1, "Amiga generic boot disk" }, { "BAD\x00", 0, "Unreadable disk" }, { "NDOS", 0, "Not a DOS disk" }, { "resv", 0, "reserved" }, { "CD00", 0, "CD-ROM High Sierra format" }, { "CD01", 0, "CD-ROM ISO9660 format" }, { "CDDA", 0, "CD Audio" }, { "CDFS", 0, "CD-ROM - Amiga CDrive or AmiCDFS" }, { "\x66\x2d\xab\xac", 0, "CD-ROM - AsimCDFS" }, { "NBR\x07", 0, "NetBSD root" }, { "NBS\x01", 0, "NetBSD swap" }, { "NBU\x07", 0, "NetBSD other" }, { "LNX\x00", 0, "Linux native" }, { "EXT2", 0, "Linux ext2" }, { "SWAP", 0, "Linux swap" }, { "SWP\x00", 0, "Linux swap" }, { "MNX\x00", 0, "Linux minix" }, { "MAC\x00", 0, "Macintosh HFS" }, { "MSD\x00", 0, "MS-DOS disk" }, { "MSH\x00", 0, "MS-DOS PC-Task hardfile" }, { "BFFS", 0, "Berkeley Fast Filesystem" }, { NULL, 0, NULL }, }; static char * get_name_for_dostype(const unsigned char *dostype) { int i; for (i = 0; amiga_dostypes[i].name; i++) if (memcmp(dostype, amiga_dostypes[i].typecode, 4) == 0) return amiga_dostypes[i].name; return "Unknown"; } static void format_dostype(char *buf, const unsigned char *dostype) { int i; unsigned char c; char *p; p = buf; for (i = 0; i < 4; i++) { c = dostype[i]; if (c < 10) { *p++ = '\\'; *p++ = '0' + c; } else if (c < 32) { sprintf(p, "0x%02x", (int)c); p = strchr(p, 0); } else { *p++ = (char)c; } } *p = 0; } /* * Amiga "Rigid Disk" partition map */ void detect_amiga_partmap(SECTION *section, int level) { int i, off, found; unsigned char *buf; char s[256], append[64]; u4 blocksize, part_ptr; u8 cylsize, start, size; for (off = 0, found = 0; off < 16; off++) { if (get_buffer(section, off * 512, 512, (void **)&buf) < 512) break; if (memcmp(buf, "RDSK", 4) == 0) { found = 1; break; } } if (!found) return; if (off == 0) print_line(level, "Amiga Rigid Disk partition map"); else print_line(level, "Amiga Rigid Disk partition map at sector %d", off); /* get device block size (?) */ blocksize = get_be_long(buf + 16); if (blocksize < 256 || (blocksize & (blocksize-1))) { print_line(level+1, "Illegal block size %lu", blocksize); return; } else if (blocksize != 512) { print_line(level+1, "Unusual block size %lu, not sure this will work...", blocksize); } /* TODO: get geometry data for later use */ /* walk the partition list */ part_ptr = get_be_long(buf + 28); for (i = 1; part_ptr != 0xffffffffUL; i++) { if (get_buffer(section, (u8)part_ptr * 512, 256, (void **)&buf) < 256) { print_line(level, "Partition %d: Can't read partition info block"); break; } /* check signature */ if (memcmp(buf, "PART", 4) != 0) { print_line(level, "Partition %d: Invalid signature"); break; } /* get "next" pointer for next iteration */ part_ptr = get_be_long(buf + 16); /* get sizes */ cylsize = (u8)get_be_long(buf + 140) * (u8)get_be_long(buf + 148); start = get_be_long(buf + 164) * cylsize; size = (get_be_long(buf + 168) + 1 - get_be_long(buf + 164)) * cylsize; snprintf(append, 63, " from %llu", start); format_blocky_size(s, size, 512, "sectors", append); print_line(level, "Partition %d: %s", i, s); /* get name */ get_pstring(buf + 36, s); if (s[0]) print_line(level + 1, "Drive name \"%s\"", s); /* show dos type */ format_dostype(s, buf + 192); print_line(level + 1, "Type \"%s\" (%s)", s, get_name_for_dostype(buf + 192)); /* detect contents */ if (size > 0 && start > 0) { analyze_recursive(section, level + 1, start * 512, size * 512, 0); } } } /* * Amiga file system */ void detect_amiga_fs(SECTION *section, int level) { unsigned char *buf; int i, isfs; char s[256], *typename; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; /* look for one of the signatures */ isfs = 0; typename = NULL; for (i = 0; amiga_dostypes[i].name; i++) if (memcmp(buf, amiga_dostypes[i].typecode, 4) == 0) { isfs = amiga_dostypes[i].isfs; typename = amiga_dostypes[i].name; break; } if (typename == NULL) return; if (isfs) { print_line(level, "%s", typename); format_dostype(s, buf); print_line(level + 1, "Type \"%s\"", s); if (section->size == 512*11*2*80) { print_line(level+1, "Size matches DD floppy"); } else if (section->size == 512*22*2*80) { print_line(level+1, "Size matches HD floppy"); } } else { format_dostype(s, buf); print_line(level, "Amiga type code \"%s\" (%s)", s, typename); } } /* EOF */ disktype-9/apple.c0000664000076500007650000001515610440611132015143 0ustar chrispchrisp00000000000000/* * apple.c * Detection of Apple partition maps and file systems * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * Apple partition map detection */ void detect_apple_partmap(SECTION *section, int level) { int i, magic, count; char s[256], append[64]; unsigned char *buf; u8 start, size; /* partition maps only occur at the start of a device */ /* disabled to allow for APM maps in El Torito entries if (section->pos != 0) return; */ /* if (buf[off] == 0x45 && buf[off+1] == 0x52) { print_line(level, "HFS driver description map at sector %d", i); } */ if (get_buffer(section, 512, 512, (void **)&buf) < 512) return; magic = get_be_short(buf); if (magic == 0x5453) { print_line(level, "Old-style Apple partition map"); return; } if (magic != 0x504D) return; /* get partition count and print info */ count = get_be_long(buf + 4); print_line(level, "Apple partition map, %d entries", count); for (i = 1; i <= count; i++) { /* read the right sector */ /* NOTE: the previous run through the loop might have called * get_buffer indirectly, invalidating our old pointer */ if (i > 1 && get_buffer(section, i * 512, 512, (void **)&buf) < 512) return; /* check signature */ if (get_be_short(buf) != 0x504D) { print_line(level, "Partition %d: invalid signature, skipping", i); continue; } /* get position and size */ start = get_be_long(buf + 8); size = get_be_long(buf + 12); sprintf(append, " from %llu", start); format_blocky_size(s, size, 512, "sectors", append); print_line(level, "Partition %d: %s", i, s); /* get type */ get_string(buf + 48, 32, s); print_line(level+1, "Type \"%s\"", s); /* recurse for content detection */ if (start > count && size > 0) { /* avoid recursion on self */ analyze_recursive(section, level + 1, start * 512, size * 512, 0); } } } /* * Apple volume formats: MFS, HFS, HFS Plus */ void detect_apple_volume(SECTION *section, int level) { char s[256], t[514]; unsigned char *buf; u2 magic, version, volnamelen; u4 blocksize, blockstart; u8 blockcount, offset; u8 catalogstart, cataloglength; u4 firstleafnode, nodesize; if (get_buffer(section, 1024, 512, (void **)&buf) < 512) return; magic = get_be_short(buf); version = get_be_short(buf + 2); if (magic == 0xD2D7) { print_line(level, "MFS file system"); } else if (magic == 0x4244) { print_line(level, "HFS file system"); blockcount = get_be_short(buf + 18); blocksize = get_be_long(buf + 20); blockstart = get_be_short(buf + 28); get_pstring(buf + 36, s); format_ascii(s, t); print_line(level + 1, "Volume name \"%s\"", t); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); if (get_be_short(buf + 0x7c) == 0x482B) { print_line(level, "HFS wrapper for HFS Plus"); offset = (u8)get_be_short(buf + 0x7e) * blocksize + (u8)blockstart * 512; /* TODO: size */ analyze_recursive(section, level + 1, offset, 0, 0); } } else if (magic == 0x482B) { print_line(level, "HFS Plus file system"); blocksize = get_be_long(buf + 40); blockcount = get_be_long(buf + 44); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); /* To read the volume name, we have to parse some structures... This code makes many assumptions which are usually true, but don't have to be. */ /* get catalog file location on disk */ /* ASSUMPTION: This reads the location of the first extent of the catalog file. If the catalog file is fragmented, we'll be working with only the first fragment, which may not include the node we're looking for. */ catalogstart = get_be_long(buf + 288) * blocksize; cataloglength = get_be_long(buf + 292) * blocksize; /* limit to actual length (byte count instead of block count) */ if (cataloglength > get_be_quad(buf + 272)) cataloglength = get_be_quad(buf + 272); /* read header node of B-tree (4096 is the minimum node size) */ if (get_buffer(section, catalogstart, 4096, (void **)&buf) < 4096) return; firstleafnode = get_be_long(buf + 24); nodesize = get_be_short(buf + 32); if (nodesize < 4096) return; /* illegal value */ /* read first lead node */ if ((firstleafnode + 1) * nodesize > cataloglength) return; /* the location is beyond the end of the catalog */ if (get_buffer(section, catalogstart + firstleafnode * nodesize, nodesize, (void **)&buf) < nodesize) return; /* the first record in this leaf node should be for parent id 1 */ if (buf[8] != 0xff) return; /* not a leaf node */ if (get_be_short(buf + 14) <= 6) return; /* key of first record is too short to contain a name */ if (get_be_long(buf + 16) != 1) return; /* parent folder id is not "root parent" */ volnamelen = get_be_short(buf + 20); format_utf16_be(buf + 22, volnamelen * 2, t); print_line(level + 1, "Volume name \"%s\"", t); } } /* * Apple UDIF disk images */ void detect_udif(SECTION *section, int level) { u8 pos; unsigned char *buf; if (section->size < 1024 || section->source->sequential) return; pos = section->size - 512; if (get_buffer(section, pos, 512, (void **)&buf) < 512) return; if (memcmp(buf, "koly", 4) == 0) { print_line(level, "Apple UDIF disk image, content detection may or may not work..."); } } /* EOF */ disktype-9/archives.c0000664000076500007650000000647510440761021015655 0ustar chrispchrisp00000000000000/* * archives.c * Detection of (Unix) archive formats * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * detection of various archive headers * * Most of this is based on the tapetype program by Doug Merritt, * posted to the net in 1992. Some parts are augmented with stuff from * /etc/magic. */ void detect_archive(SECTION *section, int level) { int fill, i, stored_sum, sum, en; u4 magic; unsigned char *buf; fill = get_buffer(section, 0, 512, (void **)&buf); if (fill < 512) return; /* tar archives */ sum = 0; for (i = 0; i < 148; i++) sum += (char)buf[i]; for (; i < 156; i++) sum += ' '; for (; i < 512; i++) sum += (char)buf[i]; stored_sum = 0; for (i = 148; i < 156; i++) { if (buf[i] == 0) break; else if (buf[i] >= '0' && buf[i] <= '7') stored_sum = (stored_sum * 8) + (buf[i] - '0'); else if (buf[i] != ' ') { stored_sum = -1; /* make it mismatch, since this is an error */ break; } } if (sum == stored_sum) { if (memcmp((char *)buf + 257, "ustar \0", 8) == 0) { print_line(level, "GNU tar archive"); } else if (memcmp((char *)buf + 257, "ustar\0", 6) == 0) { print_line(level, "POSIX tar archive"); } else { print_line(level, "Pre-POSIX tar archive"); } } /* cpio */ if (get_le_short(buf) == 070707) { print_line(level, "cpio archive, little-endian binary"); } else if (get_be_short(buf) == 070707) { print_line(level, "cpio archive, big-endian binary"); } else if (memcmp(buf, "07070", 5) == 0) { print_line(level, "cpio archive, ascii"); } /* bar */ if (memcmp(buf + 65, "\x56\0", 2) == 0) { print_line(level, "bar archive"); } /* dump */ for (en = 0; en < 2; en++) { magic = get_ve_long(en, buf + 24); if (magic == 60011) { print_line(level, "dump: 4.1BSD (or older) or Sun OFS, %s", get_ve_name(en)); } else if (magic == 60012) { print_line(level, "dump: 4.2BSD (or newer) without IDC or Sun NFS, %s", get_ve_name(en)); } else if (magic == 60013) { print_line(level, "dump: 4.2BSD (or newer) with IDC, %s", get_ve_name(en)); } else if (magic == 60014) { print_line(level, "dump: Convex Storage Manager, %s", get_ve_name(en)); } } } /* EOF */ disktype-9/atari.c0000664000076500007650000001130607666132264015157 0ustar chrispchrisp00000000000000/* * atari.c * Detection of ATARI ST partition map * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * ATARI ST partition map */ static char * get_name_for_type(char *type) { if (memcmp(type, "GEM", 3) == 0) return "Standard GEMDOS"; else if (memcmp(type, "BGM", 3) == 0) return "Big GEMDOS"; else if (memcmp(type, "XGM", 3) == 0) return "Extended"; return "Unknown"; } static void detect_atari_partmap_ext(SECTION *section, u8 extbase, int level); void detect_atari_partmap(SECTION *section, int level) { unsigned char *buf; int i, off, used, flag, flags[4]; u4 start, size, starts[4], sizes[4]; char types[4][4], *type; u2 atari_csum; char s[256], append[64]; /* partition maps only occur at the start of a device */ if (section->pos != 0) return; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; /* check checksum */ atari_csum = 0; for (i = 0; i < 512; i += 2) atari_csum += get_be_short(buf + i); if (atari_csum != 0x1234) return; /* get data and check if it's actually used */ used = 0; for (off = 0x1c6, i = 0; i < 4; i++, off += 12) { flags[i] = buf[off]; get_string(buf + off + 1, 3, types[i]); starts[i] = get_be_long(buf + off + 4); sizes[i] = get_be_long(buf + off + 8); if ((flags[i] & 1) && starts[i] != 0 && sizes[i] != 0) used = 1; } if (!used) return; /* print data and handle each partition */ print_line(level, "ATARI ST partition map"); for (i = 0; i < 4; i++) { start = starts[i]; size = sizes[i]; flag = flags[i]; type = types[i]; if ((flag & 1) == 0) continue; sprintf(append, " from %lu", start); if (flag & 0x80) strcat(append, ", bootable"); format_blocky_size(s, size, 512, "sectors", append); print_line(level, "Partition %d: %s", i+1, s); print_line(level + 1, "Type \"%s\" (%s)", type, get_name_for_type(type)); if (memcmp(type, "XGM", 3) == 0) { /* extended partition */ detect_atari_partmap_ext(section, start, level + 1); } else { /* recurse for content detection */ analyze_recursive(section, level + 1, (u8)start * 512, (u8)size * 512, 0); } } } static void detect_atari_partmap_ext(SECTION *section, u8 extbase, int level) { unsigned char *buf; int extpartnum = 5; u8 tablebase, nexttablebase; int i, off, flags[4]; u4 start, size, starts[4], sizes[4]; char types[4][4], *type; char s[256], append[64]; for (tablebase = extbase; tablebase; tablebase = nexttablebase) { /* read sector from linked list */ if (get_buffer(section, tablebase << 9, 512, (void **)&buf) < 512) return; /* get data */ for (off = 0x1c6, i = 0; i < 4; i++, off += 12) { flags[i] = buf[off]; get_string(buf + off + 1, 3, types[i]); starts[i] = get_be_long(buf + off + 4); sizes[i] = get_be_long(buf + off + 8); } /* print data and handle each partition */ nexttablebase = 0; for (i = 0; i < 4; i++) { start = starts[i]; size = sizes[i]; type = types[i]; if ((flags[i] & 1) == 0) continue; if (memcmp(type, "XGM", 3) == 0) { /* link to next table */ nexttablebase = extbase + start; } else { /* real partition */ sprintf(append, " from %lu", start); format_blocky_size(s, size, 512, "sectors", append); print_line(level, "Partition %d: %s", extpartnum, s); extpartnum++; print_line(level + 1, "Type \"%s\" (%s)", type, get_name_for_type(type)); /* recurse for content detection */ analyze_recursive(section, level + 1, (tablebase + start) * 512, (u8)size * 512, 0); } } } } /* EOF */ disktype-9/beos.c0000664000076500007650000000600510440636362014777 0ustar chrispchrisp00000000000000/* * beos.c * Detection of BeOS file systems * * Copyright (c) 2003-2006 Christoph Pfisterer * Based on a contribution by Shadowcaster * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * BeOS BFS (BeFS) file system */ void detect_bfs(SECTION *section, int level) { unsigned char *buf; char s[256]; int off, en; u4 blocksize; u8 blockcount; for (off = 0; off <= 512; off += 512) { if (get_buffer(section, off, 512, (void **)&buf) < 512) continue; for (en = 0; en < 2; en++) { if (get_ve_long(en, buf + 32) == 0x42465331 && /* magic 1 */ get_ve_long(en, buf + 36) == 0x42494745 && /* endianness */ get_ve_long(en, buf + 68) == 0xdd121031 && /* magic 2 */ get_ve_long(en, buf + 112) == 0x15b6830e) { /* magic 3 */ print_line(level, "BeOS BFS (BeFS) file system, %s placement, %s", (off == 0) ? "Apple" : "Intel", get_ve_name(en)); /* get label */ get_string(buf, 32, s); if (s[0]) print_line(level + 1, "Volume name \"%s\"", s); /* get size */ blocksize = get_ve_long(en, buf + 40); blockcount = get_ve_quad(en, buf + 48); /* possible further consistency checks: blocksize must be in ( 512, 1024, 2048, 4096 ) long @ 44 is shift number for the block size, i.e. blocksize == 1 << get_ve_long(en, buf + 44) */ format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); return; } } } } /* * BeOS boot loader */ void detect_beos_loader(SECTION *section, int level) { unsigned char *buf; if (section->flags & FLAG_IN_DISKLABEL) return; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; if (find_memory(buf, 512, "Be Boot Loader", 14) >= 0) print_line(level, "BeOS boot loader"); if (find_memory(buf, 512, "yT Boot Loader", 14) >= 0) print_line(level, "ZETA/yellowTab boot loader"); if (find_memory(buf, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0) print_line(level, "Haiku boot loader"); } /* EOF */ disktype-9/blank.c0000664000076500007650000000503407664072357015153 0ustar chrispchrisp00000000000000/* * blank.c * Detection of Blank Disk (Formatted) * * Written By Aaron Geyer of StorageQuest, Inc. * * Copyright (c) 2003 Aaron Geyer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include "global.h" /* The principle used to determine whether or not a disk is blank is to search the disk for a byte code that does not change over the disk. This module only scans the first 2MB of the disk. This module will need more work. */ #define BLOCK_SIZE (512) #define MAX_BLOCKS (2048*2) #define MIN_BLOCKS (64*2) void detect_blank(SECTION *section, int level) { unsigned char *buffer; int i, j; int block_size = BLOCK_SIZE; int max_blocks = MAX_BLOCKS; int blank_blocks = 0; unsigned char code; char s[256]; if (get_buffer(section, 0, 1, (void **)&buffer) < 1) return; code = buffer[0]; /* Limit to actual size of partition / disk */ if (section->size && section->size < max_blocks * block_size) { max_blocks = section->size / block_size; } /* Determine number of blank blocks */ for (i = 0; i < max_blocks; i++) { if (get_buffer(section, i * block_size, block_size, (void **)&buffer) < block_size) break; for (j = 0; j < block_size; j++) { if (buffer[j] != code) break; } if (j < block_size) break; blank_blocks = i + 1; } if (blank_blocks >= max_blocks) { print_line(level, "Blank disk/medium"); } else if (blank_blocks > MIN_BLOCKS) { format_size(s, blank_blocks * block_size); print_line(level, "First %s are blank", s); } } disktype-9/buffer.c0000664000076500007650000002577107651536147015345 0ustar chrispchrisp00000000000000/* * buffer.c * Manages data reading and caching. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" #define PROFILE 0 /* * constants */ /* this defines 4K chunks, should only be changed upwards */ #define CHUNKBITS (12) #define CHUNKSIZE (1<>CHUNKBITS) % HASHSIZE) /* convenience */ #define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) #define MAXIMUM(a,b) (((a) > (b)) ? (a) : (b)) /* * types */ typedef struct chunk { /* file positions start never changes and is CHUNKSIZE-aligned, it identifies the chunk len is between 0 and CHUNKSIZE end is kept synchronized to (start + len) */ u8 start, end, len; void *buf; /* links within a hash bucket, organized as a ring list */ struct chunk *next, *prev; } CHUNK; typedef struct cache { /* chunks stored as a hash table of ring lists */ CHUNK *hashtab[HASHSIZE]; /* temporary buffer for requests involving several chunks */ void *tempbuf; } CACHE; /* * helper functions */ static CHUNK * ensure_chunk(SOURCE *s, CACHE *cache, u8 start); static CHUNK * get_chunk_alloc(CACHE *cache, u8 start); /* * retrieve a piece of the source, entry point for detection */ u8 get_buffer(SECTION *section, u8 pos, u8 len, void **buf) { SOURCE *s; /* get source info */ s = section->source; pos += section->pos; return get_buffer_real(s, pos, len, NULL, buf); } /* * actual retrieval, entry point for layering */ u8 get_buffer_real(SOURCE *s, u8 pos, u8 len, void *inbuf, void **outbuf) { CACHE *cache; CHUNK *c; u8 end, first_chunk, last_chunk, curr_chunk, got, tocopy; void *mybuf; /* sanity check */ if (len == 0 || (inbuf == NULL && outbuf == NULL)) return 0; /* get source info */ if (s->size_known && pos >= s->size) { /* error("Request for data beyond end of file (pos %llu)", pos); */ return 0; } end = pos + len; if (s->size_known && end > s->size) { /* truncate to known end of file */ end = s->size; len = end - pos; } /* get cache head */ cache = (CACHE *)s->cache_head; if (cache == NULL) { /* allocate and initialize new cache head */ cache = (CACHE *)malloc(sizeof(CACHE)); if (cache == NULL) bailout("Out of memory"); memset(cache, 0, sizeof(CACHE)); s->cache_head = (void *)cache; } /* free old temp buffer if present */ if (cache->tempbuf != NULL) { free(cache->tempbuf); cache->tempbuf = NULL; } /* calculate involved chunks */ first_chunk = pos & ~CHUNKMASK; last_chunk = (end - 1) & ~CHUNKMASK; if (last_chunk == first_chunk) { /* just get the matching chunk */ c = ensure_chunk(s, cache, first_chunk); /* NOTE: first_chunk == c->start */ if (pos >= c->end) /* chunk is incomplete and doesn't have our data */ return 0; /* calculate return data */ len = MINIMUM(len, c->end - pos); /* guaranteed to be > 0 */ mybuf = c->buf + (pos - c->start); if (inbuf) memcpy(inbuf, mybuf, len); if (outbuf) *outbuf = mybuf; return len; } else { /* prepare a buffer for concatenation */ if (inbuf) { mybuf = inbuf; } else { #if PROFILE printf("Temporary buffer for request %llu:%llu\n", pos, len); #endif /* allocate one temporarily, will be free()'d at the next call */ cache->tempbuf = malloc(len); if (cache->tempbuf == NULL) { error("Out of memory, still going"); return 0; } mybuf = cache->tempbuf; } /* draw data from all covered chunks */ got = 0; for (curr_chunk = first_chunk; curr_chunk <= last_chunk; curr_chunk += CHUNKSIZE) { /* get that chunk */ c = ensure_chunk(s, cache, curr_chunk); /* NOTE: curr_chunk == c->start */ if (pos > curr_chunk) { /* copy from middle of chunk */ /* NOTE: - we're in the first chunk, i.e. pos < curr_chunk + CHUNKSIZE - pos >= curr_chunk - got == 0 - we must read to the end (else it would be the one-chunk case), i.e. pos + len > curr_chunk + CHUNKSIZE BUT: the chunk may be only partially filled */ if (c->end > pos) { tocopy = c->end - pos; memcpy(mybuf, c->buf + (pos & CHUNKMASK), tocopy); } else tocopy = 0; } else { /* copy from start of chunk */ tocopy = MINIMUM(c->len, len - got); /* c->len can be zero */ if (tocopy) memcpy(mybuf + got, c->buf, tocopy); } got += tocopy; /* stop after an incomplete chunk (possibly-okay for the last one, not-so-nice for earlier ones, but treated all the same) */ if (c->len < CHUNKSIZE) break; } /* calculate return data */ len = MINIMUM(len, got); /* may be zero */ if (outbuf) *outbuf = mybuf; return len; } } static CHUNK * ensure_chunk(SOURCE *s, CACHE *cache, u8 start) { CHUNK *c; u8 pos, rel_start, rel_end; u8 toread, result, curr_chunk; c = get_chunk_alloc(cache, start); if (c->len >= CHUNKSIZE || (s->size_known && c->end >= s->size)) { /* chunk is complete or complete until EOF */ return c; } if (s->sequential) { /* sequential source: ensure all data before this chunk was read */ if (s->seq_pos < start) { /* try to read data between seq_pos and start */ curr_chunk = s->seq_pos & ~CHUNKMASK; while (curr_chunk < start) { /* runs at least once, due to the if() and the formula of curr_chunk */ ensure_chunk(s, cache, curr_chunk); curr_chunk += CHUNKSIZE; if (s->seq_pos < curr_chunk) break; /* it didn't work out... */ } /* re-check precondition since s->size may have changed */ if (s->size_known && c->end >= s->size) return c; /* there is no more data to read */ } if (s->seq_pos != c->end) /* c->end is where we'll continue reading */ return c; /* we're not in a sane state, give up */ } /* try to read the missing piece */ if (s->read_block != NULL) { /* use block-oriented read_block() method */ if (s->blocksize < MINBLOCKSIZE || s->blocksize > CHUNKSIZE || ((s->blocksize & (s->blocksize - 1)) != 0)) { bailout("Internal error: Invalid block size %d", s->blocksize); } for (rel_start = 0; rel_start < CHUNKSIZE; rel_start = rel_end) { rel_end = rel_start + s->blocksize; if (c->len >= rel_end) continue; /* already read */ pos = c->start + rel_start; if (s->size_known && pos >= s->size) break; /* whole block is past end of file */ /* read it */ if (s->read_block(s, pos, c->buf + rel_start)) { /* success */ c->len = rel_end; c->end = c->start + c->len; } else { /* failure */ c->len = rel_start; /* this is safe as it can only mean a shrink */ c->end = c->start + c->len; /* note the new end of file if necessary */ if (!s->size_known || s->size > c->end) { s->size_known = 1; s->size = c->end; } break; } } } else { /* use byte-oriented read_bytes() method */ if (s->size_known && s->size < c->start + CHUNKSIZE) { /* do not try to read beyond known end of file */ toread = s->size - c->end; /* toread cannot be zero or negative due to the preconditions */ } else { toread = CHUNKSIZE - c->len; } result = s->read_bytes(s, c->start + c->len, toread, c->buf + c->len); if (result > 0) { /* adjust offsets */ c->len += result; c->end = c->start + c->len; if (s->sequential) s->seq_pos += result; } if (result < toread) { /* we fell short, so it must have been an error or end-of-file */ /* make sure we don't try again */ if (!s->size_known || s->size > c->end) { s->size_known = 1; s->size = c->end; } } } return c; } static CHUNK * get_chunk_alloc(CACHE *cache, u8 start) { int hpos; CHUNK *chain, *trav, *c; /* get hash bucket (chain) */ hpos = HASHFUNC(start); chain = cache->hashtab[hpos]; if (chain == NULL) { /* bucket is empty, allocate new chunk */ c = (CHUNK *)malloc(sizeof(CHUNK)); if (c == NULL) bailout("Out of memory"); c->buf = malloc(CHUNKSIZE); if (c->buf == NULL) bailout("Out of memory"); c->start = start; c->end = start; c->len = 0; /* create a new ring list */ c->prev = c->next = c; cache->hashtab[hpos] = c; return c; } /* travel the ring list, looking for the wanted chunk */ trav = chain; do { if (trav->start == start) /* found existing chunk */ return trav; trav = trav->next; } while (trav != chain); /* not found, allocate new chunk */ c = (CHUNK *)malloc(sizeof(CHUNK)); if (c == NULL) bailout("Out of memory"); c->buf = malloc(CHUNKSIZE); if (c->buf == NULL) bailout("Out of memory"); c->start = start; c->end = start; c->len = 0; /* add to ring list before chain, becomes new head */ c->prev = chain->prev; c->next = chain; c->prev->next = c; c->next->prev = c; cache->hashtab[hpos] = c; return c; } /* * dispose of a source */ void close_source(SOURCE *s) { CACHE *cache; int hpos; CHUNK *chain, *trav, *nexttrav; /* drop the cache */ cache = (CACHE *)s->cache_head; if (cache != NULL) { #if PROFILE printf("Cache profile:\n"); #endif if (cache->tempbuf != NULL) free(cache->tempbuf); for (hpos = 0; hpos < HASHSIZE; hpos++) { #if PROFILE printf(" hash position %d:", hpos); #endif chain = cache->hashtab[hpos]; if (chain != NULL) { trav = chain; do { #if PROFILE printf(" %lluK", trav->start >> 10); if (trav->len != CHUNKSIZE) printf(":%llu", trav->len); #endif nexttrav = trav->next; free(trav->buf); free(trav); trav = nexttrav; } while (trav != chain); #if PROFILE printf("\n"); #endif } #if PROFILE else printf(" empty\n"); #endif } } /* type-specific cleanup */ if (s->close != NULL) (*s->close)(s); /* release memory for the structure */ free(s); } /* EOF */ disktype-9/cdaccess.c0000664000076500007650000001106607666372573015643 0ustar chrispchrisp00000000000000/* * cdaccess.c * System-dependent code to access extended CD information * * Based on a contribution by Erik Andersen * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" #ifdef USE_IOCTL_LINUX #include #include #define DO_CDACCESS 1 #endif /* USE_IOCTL_LINUX */ #ifdef DO_CDACCESS /* * CDDB stuff */ static int cddb_sum(int n); #define LBA_TO_SECS(lba) (((lba) + 150) / 75) /* * CD structure: * Tries to get the CD TOC using out-of-band means (i.e. ioctl()), * prints the info, and analyzes just the data tracks. Quite * system-dependent, but layed out for porability. */ int analyze_cdaccess(int fd, SOURCE *s, int level) { int i; int first, last, ntracks; int cksum, totaltime, seconds; u4 diskid; u1 ctrl[100]; u4 lba[100], length; char human_readable_size[256]; #ifdef USE_IOCTL_LINUX struct cdrom_tochdr tochdr; struct cdrom_tocentry tocentry; #endif /* read TOC header */ #ifdef USE_IOCTL_LINUX if (ioctl(fd, CDROMREADTOCHDR, &tochdr) < 0) { return 0; } first = tochdr.cdth_trk0; last = tochdr.cdth_trk1; #endif ntracks = last + 1 - first; if (ntracks > 99) /* natural limit */ return 0; /* read per-track data from TOC */ for (i = 0; i <= ntracks; i++) { #ifdef USE_IOCTL_LINUX if (i == ntracks) tocentry.cdte_track = CDROM_LEADOUT; else tocentry.cdte_track = first + i; tocentry.cdte_format = CDROM_LBA; if (ioctl(fd, CDROMREADTOCENTRY, &tocentry) < 0) { //printf("CDROMREADTOCENTRY: %s: ", strerror(errno)); return 0; } ctrl[i] = tocentry.cdte_ctrl; lba[i] = tocentry.cdte_addr.lba; #endif } /* System-dependent code ends here. From now on, we use the data in first, last, ntracks, ctrl[], and lba[]. We also assume all systems treat actual data access the same way... */ /* calculate CDDB disk id */ cksum = 0; for (i = 0; i < ntracks; i++) { cksum += cddb_sum(LBA_TO_SECS(lba[i])); } totaltime = LBA_TO_SECS(lba[ntracks]) - LBA_TO_SECS(lba[0]); diskid = (u4)(cksum % 0xff) << 24 | (u4)totaltime << 8 | (u4)ntracks; /* print disk info */ print_line(level, "CD-ROM, %d track%s, CDDB disk ID %08lX", ntracks, (ntracks != 1) ? "s" : "", diskid); /* Loop over each track */ for (i = 0; i < ntracks; i++) { /* length of track in sectors */ length = lba[i+1] - lba[i]; if ((ctrl[i] & 0x4) == 0) { /* Audio track, one sector holds 2352 actual data bytes */ seconds = length / 75; format_size(human_readable_size, (u8)length * 2352); print_line(level, "Track %d: Audio track, %s, %3d min %02d sec", first + i, human_readable_size, seconds / 60, seconds % 60); } else { /* Data track, one sector holds 2048 actual data bytes */ format_size(human_readable_size, length * 2048); print_line(level, "Track %d: Data track, %s", first + i, human_readable_size); /* NOTE: we adjust the length to stay clear of padding or post-gap stuff */ analyze_source_special(s, level + 1, (u8)lba[i] * 2048, (u8)(length - 250) * 2048); } } return 1; } /* * helper function: calculate cddb disk id */ static int cddb_sum(int n) { /* a number like 2344 becomes 2+3+4+4 (13) */ int ret = 0; while (n > 0) { ret = ret + (n % 10); n = n / 10; } return ret; } #else /* DO_CDACCESS */ /* * the system is not supported, so use a dummy function */ int analyze_cdaccess(int fd, SOURCE *s, int level) { return 0; } #endif /* DO_CDACCESS */ /* EOF */ disktype-9/cdimage.c0000664000076500007650000000656007651536147015460 0ustar chrispchrisp00000000000000/* * cdimage.c * Layered data source for CD images in raw mode. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * types */ typedef struct cdimage_source { SOURCE c; u8 off; } CDIMAGE_SOURCE; /* * helper functions */ static SOURCE *init_cdimage_source(SOURCE *foundation, u8 offset); static int read_block_cdimage(SOURCE *s, u8 pos, void *buf); /* * cd image detection */ static unsigned char syncbytes[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 }; void detect_cdimage(SECTION *section, int level) { int mode, off; unsigned char *buf; SOURCE *s; if (get_buffer(section, 0, 2352, (void **)&buf) < 2352) return; /* check sync bytes as signature */ if (memcmp(buf, syncbytes, 12) != 0) return; /* get mode of the track -- this determines sector layout */ mode = buf[15]; if (mode == 1) { /* standard data track */ print_line(level, "Raw CD image, Mode 1"); off = 16; } else if (mode == 2) { /* free-form track, assume XA form 1 */ print_line(level, "Raw CD image, Mode 2, assuming Form 1"); off = 24; } else return; /* create and analyze wrapped source */ s = init_cdimage_source(section->source, section->pos + off); analyze_source(s, level); close_source(s); /* don't run other analyzers */ stop_detect(); } /* * initialize the cd image source */ static SOURCE *init_cdimage_source(SOURCE *foundation, u8 offset) { CDIMAGE_SOURCE *src; src = (CDIMAGE_SOURCE *)malloc(sizeof(CDIMAGE_SOURCE)); if (src == NULL) bailout("Out of memory"); memset(src, 0, sizeof(CDIMAGE_SOURCE)); if (foundation->size_known) { src->c.size_known = 1; src->c.size = ((foundation->size - offset + 304) / 2352) * 2048; /* TODO: pass the size in from the SECTION record and use it */ } src->c.blocksize = 2048; src->c.foundation = foundation; src->c.read_block = read_block_cdimage; src->c.close = NULL; src->off = offset; return (SOURCE *)src; } /* * raw read */ static int read_block_cdimage(SOURCE *s, u8 pos, void *buf) { SOURCE *fs = s->foundation; u8 filepos; /* translate position */ filepos = (pos / 2048) * 2352 + ((CDIMAGE_SOURCE *)s)->off; /* read from lower layer */ if (get_buffer_real(fs, filepos, 2048, buf, NULL) < 2048) return 0; return 1; } /* EOF */ disktype-9/cdrom.c0000664000076500007650000001747610440611132015155 0ustar chrispchrisp00000000000000/* * cdrom.c * Detection of file systems for CD-ROM and similar media * * Copyright (c) 2003-2006 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * sub-functions */ static void dump_boot_catalog(SECTION *section, u8 pos, int level); /* * ISO9660 file system */ void detect_iso(SECTION *section, int level) { char s[256], t[256]; int i, sector, type; u4 blocksize; u8 blocks, bcpos; unsigned char *buf; /* get the volume descriptor */ if (get_buffer(section, 32768, 2048, (void **)&buf) < 2048) return; /* check signature */ if (memcmp(buf, "\001CD001", 6) != 0) return; print_line(level, "ISO9660 file system"); /* read Volume ID and other info */ get_padded_string(buf + 40, 32, ' ', s); print_line(level+1, "Volume name \"%s\"", s); get_padded_string(buf + 318, 128, ' ', s); if (s[0]) print_line(level+1, "Publisher \"%s\"", s); get_padded_string(buf + 446, 128, ' ', s); if (s[0]) print_line(level+1, "Preparer \"%s\"", s); get_padded_string(buf + 574, 128, ' ', s); if (s[0]) print_line(level+1, "Application \"%s\"", s); /* some other interesting facts */ blocks = get_le_long(buf + 80); blocksize = get_le_short(buf + 128); format_blocky_size(s, blocks, blocksize, "blocks", NULL); print_line(level+1, "Data size %s", s); for (sector = 17; ; sector++) { /* get next descriptor */ if (get_buffer(section, sector * 2048, 2048, (void **)&buf) < 2048) return; /* check signature */ if (memcmp(buf + 1, "CD001", 5) != 0) { print_line(level+1, "Signature missing in sector %d", sector); return; } type = buf[0]; if (type == 255) break; switch (type) { case 0: /* El Torito */ /* check signature */ if (memcmp(buf+7, "EL TORITO SPECIFICATION", 23) != 0) { print_line(level+1, "Boot record of unknown format"); break; } bcpos = get_le_long(buf + 0x47); print_line(level+1, "El Torito boot record, catalog at %llu", bcpos); /* boot catalog */ dump_boot_catalog(section, bcpos * 2048, level + 2); break; case 1: /* Primary Volume Descriptor */ print_line(level+1, "Additional Primary Volume Descriptor"); break; case 2: /* Supplementary Volume Descriptor, Joliet */ /* read Volume ID */ format_utf16_be(buf + 40, 32, t); for (i = strlen(t)-1; i >= 0 && t[i] == ' '; i--) t[i] = 0; print_line(level+1, "Joliet extension, volume name \"%s\"", t); break; case 3: /* Volume Partition Descriptor */ print_line(level+1, "Volume Partition Descriptor"); break; default: print_line(level+1, "Descriptor type %d at sector %d", type, sector); break; } } } /* * El Torito boot catalog */ static char *media_types[16] = { "non-emulated", "1.2M floppy", "1.44M floppy", "2.88M floppy", "hard disk", "reserved type 5", "reserved type 6", "reserved type 7", "reserved type 8", "reserved type 9", "reserved type 10", "reserved type 11", "reserved type 12", "reserved type 13", "reserved type 14", "reserved type 15" }; static char * get_name_for_eltorito_platform(int id) { if (id == 0) return "x86"; if (id == 1) return "PowerPC"; if (id == 2) return "Macintosh"; if (id == 0xEF) return "EFI"; return "unknown"; } static void dump_boot_catalog(SECTION *section, u8 pos, int level) { unsigned char *buf; int bootable, media, platform, system_type; u4 start, preload; int entry, maxentry, off; char s[256]; /* get boot catalog */ if (get_buffer(section, pos, 2048, (void **)&buf) < 2048) return; /* check validation entry (must be first) */ if (buf[0] != 0x01 || buf[30] != 0x55 || buf[31] != 0xAA) { print_line(level, "Validation entry missing"); return; } /* TODO: check checksum of the validation entry */ platform = buf[1]; /* TODO: ID string at bytes 0x04 - 0x1B */ maxentry = 2; for (entry = 1; entry < maxentry + 1; entry++) { if ((entry & 63) == 0) { /* get the next CD sector */ if (get_buffer(section, pos + (entry / 64) * 2048, 2048, (void **)&buf) < 2048) return; } off = (entry * 32) % 2048; if (entry >= maxentry) { if (buf[off] == 0x88) /* more bootable entries without proper section headers */ maxentry++; else break; } if (entry == 1) { if (!(buf[off] == 0x88 || buf[off] == 0x00)) { print_line(level, "Initial/Default entry missing"); break; } if (buf[off + 32] == 0x90 || buf[off + 32] == 0x91) maxentry = 3; } if (buf[off] == 0x88 || buf[off] == 0x00) { /* boot entry */ bootable = (buf[off] == 0x88) ? 1 : 0; media = buf[off + 1] & 15; system_type = buf[off + 4]; start = get_le_long(buf + off + 8); preload = get_le_short(buf + off + 6); /* print and analyze further */ format_size(s, preload * 512); print_line(level, "%s %s image, starts at %lu, preloads %s", bootable ? "Bootable" : "Non-bootable", media_types[media], start, s); print_line(level + 1, "Platform 0x%02X (%s), System Type 0x%02X (%s)", platform, get_name_for_eltorito_platform(platform), system_type, get_name_for_mbrtype(system_type)); if (start > 0) { analyze_recursive(section, level + 1, (u8)start * 2048, 0, 0); /* TODO: calculate size in some way */ } } else if (buf[off] == 0x44) { /* entry extension */ maxentry++; /* doesn't count against the entry count from the last section header */ } else if (buf[off] == 0x90 || buf[off] == 0x91) { /* section header */ platform = buf[off + 1]; maxentry = entry + 1 + get_le_short(buf + off + 2) + ((buf[off] == 0x90) ? 1 : 0); /* TODO: ID string at bytes 0x04 - 0x1F */ } else { print_line(level, "Unknown entry type 0x%02X", buf[off]); break; } } } /* * Various CD file systems */ void detect_cdrom_misc(SECTION *section, int level) { unsigned char *buf; /* get first sector */ if (get_buffer(section, 0, 2048, (void **)&buf) < 2048) return; /* Sega Dreamcast signature */ if (memcmp(buf, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0) { print_line(level, "Sega Dreamcast signature"); } /* 3DO filesystem */ if (memcmp(buf, "\x01\x5a\x5a\x5a\x5a\x5a\x01\x00", 8) == 0 && memcmp(buf + 0x28, "CD-ROM", 6) == 0) { print_line(level, "3DO CD-ROM file system"); } /* get sector 32 */ if (get_buffer(section, 32*2048, 2048, (void **)&buf) < 2048) return; /* Xbox DVD file system */ if (memcmp(buf, "MICROSOFT*XBOX*MEDIA", 20) == 0 && memcmp(buf + 0x7ec, "MICROSOFT*XBOX*MEDIA", 20) == 0) { print_line(level, "Xbox DVD file system"); } } /* EOF */ disktype-9/cloop.c0000664000076500007650000000344710361514003015157 0ustar chrispchrisp00000000000000/* * cloop.c * Layered data source for Linux cloop images. * * Copyright (c) 2005 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * image file detection */ void detect_cloop(SECTION *section, int level) { unsigned char *buf; u4 blocksize, blockcount; char s[256]; const char *sig_20 = "#!/bin/sh\n#V2.0 Format\nmodprobe cloop"; /* check for signature */ if (get_buffer(section, 0, 256, (void **)&buf) < 256) return; if (memcmp(buf, sig_20, strlen(sig_20)) != 0) return; print_line(level, "Linux cloop 2.0 image"); blocksize = get_be_long(buf + 128); blockcount = get_be_long(buf + 132); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); } /* EOF */ disktype-9/compressed.c0000664000076500007650000002257610222027670016220 0ustar chrispchrisp00000000000000/* * compressed.c * Layered data source for compressed files. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" #include #include #define DEBUG 0 #if !defined(FD_ZERO) #define DECOMPRESS 0 #warning Transparent decompression disabled, select() macros not defined #elif defined(__amigaos__) && !defined(__ixemul__) #define DECOMPRESS 0 #warning Transparent decompression disabled, ixemul not available #else #define DECOMPRESS 1 #endif /* * types */ #if DECOMPRESS typedef struct compressed_source { SOURCE c; u8 offset, write_pos, write_max; int write_pipe, read_pipe, nfds; pid_t pid; } COMPRESSED_SOURCE; #endif /* * helper functions */ static void handle_compressed(SECTION *section, int level, int off, const char *program); #if DECOMPRESS static SOURCE *init_compressed_source(SOURCE *foundation, u8 offset, u8 size, const char *program); static u8 read_compressed(SOURCE *s, u8 pos, u8 len, void *buf); static void close_compressed(SOURCE *s); #endif /* * compressed file detection */ void detect_compressed(SECTION *section, int level) { int fill, off, sector; unsigned char *buf; fill = get_buffer(section, 0, 4096, (void **)&buf); /* look for signatures at sector beginnings */ for (off = 0; off + 512 <= fill; off += 512) { sector = off >> 9; /* compress */ if (buf[off] == 037 && buf[off+1] == 0235) { if (sector > 0) print_line(level, "compress-compressed data at sector %d", sector); else print_line(level, "compress-compressed data"); handle_compressed(section, level, off, "gzip"); break; } /* gzip */ if (buf[off] == 037 && (buf[off+1] == 0213 || buf[off+1] == 0236)) { if (sector > 0) print_line(level, "gzip-compressed data at sector %d", sector); else print_line(level, "gzip-compressed data"); handle_compressed(section, level, off, "gzip"); break; } /* bzip2 */ if (memcmp(buf + off, "BZh", 3) == 0) { if (sector > 0) print_line(level, "bzip2-compressed data at sector %d", sector); else print_line(level, "bzip2-compressed data"); handle_compressed(section, level, off, "bzip2"); break; } } } static void handle_compressed(SECTION *section, int level, int off, const char *program) { #if DECOMPRESS SOURCE *s; u8 size; /* create decompression data source */ size = section->size; if (size > 0) size -= off; s = init_compressed_source(section->source, section->pos + off, size, program); analyze_source(s, level + 1); close_source(s); #else print_line(level + 1, "Decompression disabled on this system"); #endif } /* * initialize the decompression */ #if DECOMPRESS static SOURCE *init_compressed_source(SOURCE *foundation, u8 offset, u8 size, const char *program) { COMPRESSED_SOURCE *cs; int write_pipe[2], read_pipe[2], flags; cs = (COMPRESSED_SOURCE *)malloc(sizeof(COMPRESSED_SOURCE)); if (cs == NULL) bailout("Out of memory"); memset(cs, 0, sizeof(COMPRESSED_SOURCE)); cs->c.sequential = 1; cs->c.seq_pos = 0; cs->c.foundation = foundation; cs->c.read_bytes = read_compressed; cs->c.close = close_compressed; /* size is not known in advance by definition */ cs->offset = offset; cs->write_pos = 0; cs->write_max = size; /* open "gzip -dc" in a dual pipe */ if (pipe(write_pipe) < 0) bailoute("pipe for decompression"); if (pipe(read_pipe) < 0) bailoute("pipe for decompression"); cs->write_pipe = write_pipe[1]; cs->read_pipe = read_pipe[0]; cs->pid = fork(); if (cs->pid < 0) { bailoute("fork"); } if (cs->pid == 0) { /* we're the child process */ /* set up pipe */ dup2(write_pipe[0], 0); if (write_pipe[0] > 2) close(write_pipe[0]); close(write_pipe[1]); close(read_pipe[0]); dup2(read_pipe[1], 1); if (read_pipe[1] > 2) close(read_pipe[1]); /* execute decompressor (gzip or bzip2) */ execlp(program, program, "-dc", NULL); exit(0); } /* we're the parent process */ close(write_pipe[0]); close(read_pipe[1]); /* set non-blocking I/O */ if ((flags = fcntl(cs->write_pipe, F_GETFL, 0)) >= 0) fcntl(cs->write_pipe, F_SETFL, flags | O_NONBLOCK); else bailoute("set pipe flags"); if ((flags = fcntl(cs->read_pipe, F_GETFL, 0)) >= 0) fcntl(cs->read_pipe, F_SETFL, flags | O_NONBLOCK); else bailoute("set pipe flags"); cs->nfds = ((cs->read_pipe > cs->write_pipe) ? cs->read_pipe : cs->write_pipe) + 1; return (SOURCE *)cs; } /* * raw read */ static u8 read_compressed(SOURCE *s, u8 pos, u8 len, void *buf) { COMPRESSED_SOURCE *cs = (COMPRESSED_SOURCE *)s; SOURCE *fs = s->foundation; char *p, *filebuf; u8 got, fill; int askfor, selresult; ssize_t result; fd_set read_set; fd_set write_set; #if DEBUG printf("rc got asked for pos %llu len %llu\n", pos, len); #endif p = (char *)buf; got = 0; if (cs->read_pipe < 0) /* closed for reading */ return got; while (got < len) { result = read(cs->read_pipe, p, len - got); #if DEBUG printf("rc read got %d\n", result); #endif if (result == 0) { /* end of file */ /* remember size for buffer layer */ s->size_known = 1; s->size = s->seq_pos + got; /* close pipe (stops future read attempts in the track) */ close(cs->read_pipe); cs->read_pipe = -1; /* we're done */ break; } else if (result > 0) { /* got data */ p += result; got += result; continue; } else { /* error return */ if (errno == EINTR) continue; if (errno != EAGAIN) { errore("read from pipe"); break; } } /* no data available for reading right now, so try to write some uncompressed data down the other pipe for a change */ /* calculate how much data to write */ askfor = 4096; if (cs->write_max && cs->write_pos + askfor > cs->write_max) askfor = cs->write_max - cs->write_pos; if (askfor <= 0 && cs->write_pipe >= 0) { /* there's no more data to write, close the pipe */ close(cs->write_pipe); cs->write_pipe = -1; } if (cs->write_pipe < 0) { /* no more data to write, just wait for input using select */ FD_ZERO(&read_set); FD_SET(cs->read_pipe, &read_set); #if DEBUG printf("rc starting select\n"); #endif selresult = select(cs->nfds, &read_set, NULL, NULL, NULL); #if DEBUG printf("rc select got %d\n", selresult); #endif if (selresult < 0 && errno != EINTR) { errore("select"); break; } continue; } /* get data from lower layer */ fill = get_buffer_real(fs, cs->offset + cs->write_pos, askfor, NULL, (void **)&filebuf); #if DEBUG printf("rc get_buffer asked for pos %llu len %d got %llu\n", cs->offset + cs->write_pos, askfor, fill); #endif if (fill < askfor) { /* we reached the end of compressed input, note that down */ cs->write_max = cs->write_pos + fill; } if (fill <= 0) { /* didn't get any data to write, so no need trying */ /* NOTE: in this case, the above if() also caught on and the next time through the loop, the write pipe will be closed. */ continue; } /* try a write right now */ result = write(cs->write_pipe, filebuf, fill); #if DEBUG printf("rc write got %d\n", result); #endif if (result >= 0) { cs->write_pos += result; continue; /* see if that made more data available for reading */ } else { if (errno == EINTR) continue; if (errno != EAGAIN) { errore("write to pipe"); break; } } /* both pipes are blocked right now. wait using select(). */ FD_ZERO(&read_set); FD_ZERO(&write_set); FD_SET(cs->read_pipe, &read_set); FD_SET(cs->write_pipe, &write_set); #if DEBUG printf("rc starting select\n"); #endif selresult = select(cs->nfds, &read_set, &write_set, NULL, NULL); #if DEBUG printf("rc select got %d\n", selresult); #endif if (selresult < 0 && errno != EINTR) { errore("select"); break; } } return got; } /* * close cleanup */ static void close_compressed(SOURCE *s) { COMPRESSED_SOURCE *cs = (COMPRESSED_SOURCE *)s; int status; if (cs->write_pipe >= 0) close(cs->write_pipe); if (cs->read_pipe >= 0) close(cs->read_pipe); kill(cs->pid, SIGHUP); waitpid(cs->pid, &status, 0); } #endif /* DECOMPRESS */ /* EOF */ disktype-9/detect.c0000664000076500007650000001461110440636362015321 0ustar chrispchrisp00000000000000/* * detect.c * Detection dispatching * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * external detection functions */ /* in amiga.c */ void detect_amiga_partmap(SECTION *section, int level); void detect_amiga_fs(SECTION *section, int level); /* in apple.c */ void detect_apple_partmap(SECTION *section, int level); void detect_apple_volume(SECTION *section, int level); void detect_udif(SECTION *section, int level); /* in atari.c */ void detect_atari_partmap(SECTION *section, int level); /* in dos.c */ void detect_dos_partmap(SECTION *section, int level); void detect_gpt_partmap(SECTION *section, int level); void detect_fat(SECTION *section, int level); void detect_ntfs(SECTION *section, int level); void detect_hpfs(SECTION *section, int level); void detect_dos_loader(SECTION *section, int level); /* in cdrom.c */ void detect_iso(SECTION *section, int level); void detect_cdrom_misc(SECTION *section, int level); /* in udf.c */ void detect_udf(SECTION *section, int level); /* in linux.c */ void detect_ext23(SECTION *section, int level); void detect_reiser(SECTION *section, int level); void detect_reiser4(SECTION *section, int level); void detect_linux_raid(SECTION *section, int level); void detect_linux_lvm(SECTION *section, int level); void detect_linux_lvm2(SECTION *section, int level); void detect_linux_swap(SECTION *section, int level); void detect_linux_misc(SECTION *section, int level); void detect_linux_loader(SECTION *section, int level); /* in unix.c */ void detect_jfs(SECTION *section, int level); void detect_xfs(SECTION *section, int level); void detect_ufs(SECTION *section, int level); void detect_sysv(SECTION *section, int level); void detect_bsd_disklabel(SECTION *section, int level); void detect_bsd_loader(SECTION *section, int level); void detect_solaris_disklabel(SECTION *section, int level); void detect_solaris_vtoc(SECTION *section, int level); void detect_qnx(SECTION *section, int level); void detect_vxfs(SECTION *section, int level); /* in beos.c */ void detect_bfs(SECTION *section, int level); void detect_beos_loader(SECTION *section, int level); /* in compressed.c */ void detect_compressed(SECTION *section, int level); /* in cdimage.c */ void detect_cdimage(SECTION *section, int level); /* in vpc.c */ void detect_vhd(SECTION *section, int level); /* in cloop.c */ void detect_cloop(SECTION *section, int level); /* in archives.c */ void detect_archive(SECTION *section, int level); /* in blank.c */ void detect_blank(SECTION *section, int level); /* * list of detectors */ DETECTOR detectors[] = { /* 1: disk image formats */ detect_vhd, /* may stop */ detect_cdimage, /* may stop */ detect_cloop, detect_udif, /* 2: boot code */ detect_linux_loader, detect_bsd_loader, detect_dos_loader, detect_beos_loader, /* 3: partition tables */ detect_bsd_disklabel, /* may stop, recurses with FLAG_IN_DISKLABEL */ detect_solaris_disklabel, /* may stop, recurses with FLAG_IN_DISKLABEL */ detect_solaris_vtoc, detect_amiga_partmap, detect_apple_partmap, detect_atari_partmap, detect_dos_partmap, detect_gpt_partmap, /* 4: file systems */ detect_amiga_fs, detect_apple_volume, detect_fat, detect_ntfs, detect_hpfs, detect_udf, detect_cdrom_misc, detect_iso, detect_ext23, detect_reiser, detect_reiser4, detect_linux_raid, detect_linux_lvm, detect_linux_lvm2, detect_linux_swap, detect_linux_misc, detect_jfs, detect_xfs, detect_ufs, detect_sysv, detect_qnx, detect_vxfs, detect_bfs, /* 5: file formats */ detect_archive, detect_compressed, /* this is here because of boot disks */ /* 6: blank formatted disk */ detect_blank, NULL }; /* * internal stuff */ static void detect(SECTION *section, int level); static int stop_flag = 0; /* * analyze a given source */ void analyze_source(SOURCE *s, int level) { SECTION section; /* Allow custom analyzing using special info available to the data source implementation. The analyze() function must either call through to analyze_source_special() or return zero. */ if (s->analyze != NULL) { if ((*s->analyze)(s, level)) return; } section.source = s; section.pos = 0; section.size = s->size_known ? s->size : 0; section.flags = 0; detect(§ion, level); } /* * analyze part of a given source */ void analyze_source_special(SOURCE *s, int level, u8 pos, u8 size) { SECTION section; section.source = s; section.pos = pos; section.size = size; section.flags = 0; detect(§ion, level); } /* * recursively analyze a portion of a SECTION */ void analyze_recursive(SECTION *section, int level, u8 rel_pos, u8 size, int flags) { SOURCE *s; SECTION rs; /* sanity */ if (rel_pos == 0 && (flags & FLAG_IN_DISKLABEL) == 0) return; s = section->source; if (s->size_known && (section->pos + rel_pos >= s->size)) return; rs.source = s; rs.pos = section->pos + rel_pos; rs.size = size; rs.flags = section->flags | flags; detect(&rs, level); } /* * detection dispatching */ static void detect(SECTION *section, int level) { int i; /* run the modularized detectors */ for (i = 0; detectors[i] && !stop_flag; i++) (*detectors[i])(section, level); stop_flag = 0; } /* * break the detection loop */ void stop_detect(void) { stop_flag = 1; } /* EOF */ disktype-9/disktype.10000664000076500007650000000466510206444212015622 0ustar chrispchrisp00000000000000.\" -*- nroff -*- .Dd Feb 21, 2005 .Dt DISKTYPE 1 .\" .Sh NAME .Nm disktype .Nd disk format detector .\" .Sh SYNOPSIS .Nm .\" .Op Ar options .Ar file... .\" .Sh DESCRIPTION The purpose of .Nm is to detect the content format of a disk or disk image. It knows about common file systems, partition tables, and boot codes. .\" .Sh USAGE .Nm can be run with any number of regular files or device special files as arguments. They will be analyzed in the order given, and the results printed to standard output. There are no switches in this version. Note that running disktype on device files like your hard disk will likely require root rights. .Pp See the online documentation at for some example command lines. .\" .Sh RECOGNIZED FORMATS The following formats are recognized by this version of .Nm Ns .No . .Bl -tag -width flag .It File systems: FAT12/FAT16/FAT32, NTFS, HPFS, MFS, HFS, HFS Plus, ISO9660, ext2/ext3, Minix, ReiserFS, Reiser4, Linux romfs, Linux cramfs, Linux squashfs, UFS (some variations), SysV FS (some variations), JFS, XFS, Amiga FS/FFS, BeOS BFS, QNX4 FS, UDF, 3DO CD-ROM file system, Veritas VxFS, Xbox DVD file system. .It Partitioning: DOS/PC style, Apple, Amiga "Rigid Disk", ATARI ST (AHDI3), BSD disklabel, Linux RAID physical disks, Linux LVM1 physical volumes, Linux LVM2 physical volumes, Solaris x86 disklabel (vtoc), Solaris SPARC disklabel. .It Other structures: Debian split floppy header, Linux swap. .It Disk images: Raw CD image (.bin), Virtual PC hard disk image, Apple UDIF disk image (limited). .It Boot codes: LILO, GRUB, SYSLINUX, ISOLINUX, Linux kernel, FreeBSD loader, Sega Dreamcast (?). .It Compression formats: gzip, compress, bzip2. .It Archive formats: tar, cpio, bar, dump/restore. .El .Pp Compressed files (gzip, compress, bzip2 formats) will also have their contents analyzed using transparent decompression. The appropriate compression program must be installed on the system, i.e. .Xr gzip 1 for the gzip and compress formats, .Xr bzip2 1 for the bzip2 format. .Pp Disk images in general will also have their contents analyzed using the proper mapping, with the exception of the Apple UDIF format. .Pp See the online documentation at for more details on the supported formats and their quirks. .\" .Sh HOMEPAGE http://disktype.sourceforge.net/ .\" .Sh AUTHOR Christoph Pfisterer .\" .Sh "SEE ALSO" .Xr file 1 , .Xr gpart 8 disktype-9/dos.c0000664000076500007650000004140310440636362014635 0ustar chrispchrisp00000000000000/* * dos.c * Detection of DOS parition maps and file systems * * Copyright (c) 2003-2006 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * DOS partition types * * Taken from fdisk/i386_sys_types.c and fdisk/common.h of * util-linux 2.11n (as packaged by Debian), Feb 08, 2003. */ struct systypes { unsigned char type; char *name; }; struct systypes i386_sys_types[] = { { 0x00, "Empty" }, { 0x01, "FAT12" }, { 0x02, "XENIX root" }, { 0x03, "XENIX usr" }, { 0x04, "FAT16 <32M" }, { 0x05, "Extended" }, { 0x06, "FAT16" }, { 0x07, "HPFS/NTFS" }, { 0x08, "AIX" }, { 0x09, "AIX bootable" }, { 0x0a, "OS/2 Boot Manager" }, { 0x0b, "Win95 FAT32" }, { 0x0c, "Win95 FAT32 (LBA)" }, { 0x0e, "Win95 FAT16 (LBA)" }, { 0x0f, "Win95 Ext'd (LBA)" }, { 0x10, "OPUS" }, { 0x11, "Hidden FAT12" }, { 0x12, "Compaq diagnostics" }, { 0x14, "Hidden FAT16 <32M" }, { 0x16, "Hidden FAT16" }, { 0x17, "Hidden HPFS/NTFS" }, { 0x18, "AST SmartSleep" }, { 0x1b, "Hidden Win95 FAT32" }, { 0x1c, "Hidden Win95 FAT32 (LBA)" }, { 0x1e, "Hidden Win95 FAT16 (LBA)" }, { 0x24, "NEC DOS" }, { 0x39, "Plan 9" }, { 0x3c, "PartitionMagic recovery" }, { 0x40, "Venix 80286" }, { 0x41, "PPC PReP Boot" }, { 0x42, "SFS / MS LDM" }, { 0x4d, "QNX4.x" }, { 0x4e, "QNX4.x 2nd part" }, { 0x4f, "QNX4.x 3rd part" }, { 0x50, "OnTrack DM" }, { 0x51, "OnTrack DM6 Aux1" }, { 0x52, "CP/M" }, { 0x53, "OnTrack DM6 Aux3" }, { 0x54, "OnTrackDM6" }, { 0x55, "EZ-Drive" }, { 0x56, "Golden Bow" }, { 0x5c, "Priam Edisk" }, { 0x61, "SpeedStor" }, { 0x63, "GNU HURD or SysV" }, { 0x64, "Novell Netware 286" }, { 0x65, "Novell Netware 386" }, { 0x70, "DiskSecure Multi-Boot" }, { 0x75, "PC/IX" }, { 0x78, "XOSL" }, { 0x80, "Old Minix" }, { 0x81, "Minix / old Linux" }, { 0x82, "Linux swap / Solaris" }, { 0x83, "Linux" }, { 0x84, "OS/2 hidden C: drive" }, { 0x85, "Linux extended" }, { 0x86, "NTFS volume set" }, { 0x87, "NTFS volume set" }, { 0x8e, "Linux LVM" }, { 0x93, "Amoeba" }, { 0x94, "Amoeba BBT" }, { 0x9f, "BSD/OS" }, { 0xa0, "IBM Thinkpad hibernation" }, { 0xa5, "FreeBSD" }, { 0xa6, "OpenBSD" }, { 0xa7, "NeXTSTEP" }, { 0xa9, "NetBSD" }, { 0xaf, "Mac OS X" }, { 0xb7, "BSDI fs" }, { 0xb8, "BSDI swap" }, { 0xbb, "Boot Wizard hidden" }, { 0xc1, "DRDOS/sec (FAT-12)" }, { 0xc4, "DRDOS/sec (FAT-16 < 32M)" }, { 0xc6, "DRDOS/sec (FAT-16)" }, { 0xc7, "Syrinx" }, { 0xda, "Non-FS data" }, { 0xdb, "CP/M / CTOS / ..." }, { 0xde, "Dell Utility" }, { 0xdf, "BootIt" }, { 0xe1, "DOS access" }, { 0xe3, "DOS R/O" }, { 0xe4, "SpeedStor" }, { 0xeb, "BeOS fs" }, { 0xee, "EFI GPT protective" }, { 0xef, "EFI System (FAT)" }, { 0xf0, "Linux/PA-RISC boot" }, { 0xf1, "SpeedStor" }, { 0xf4, "SpeedStor" }, { 0xf2, "DOS secondary" }, { 0xfd, "Linux raid autodetect" }, { 0xfe, "LANstep" }, { 0xff, "BBT" }, { 0, 0 } }; char * get_name_for_mbrtype(int type) { int i; for (i = 0; i386_sys_types[i].name; i++) if (i386_sys_types[i].type == type) return i386_sys_types[i].name; return "Unknown"; } /* * DOS-style partition map / MBR */ static void detect_dos_partmap_ext(SECTION *section, u8 extbase, int level, int *extpartnum); void detect_dos_partmap(SECTION *section, int level) { unsigned char *buf; int i, off, used, type, types[4], bootflags[4]; u4 start, size, starts[4], sizes[4]; int extpartnum = 5; char s[256], append[64]; /* partition maps only occur at the start of a device */ if (section->pos != 0) return; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; /* check signature */ if (buf[510] != 0x55 || buf[511] != 0xAA) return; /* get entries and check */ used = 0; for (off = 446, i = 0; i < 4; i++, off += 16) { /* get data */ bootflags[i] = buf[off]; types[i] = buf[off + 4]; starts[i] = get_le_long(buf + off + 8); sizes[i] = get_le_long(buf + off + 12); /* bootable flag: either on or off */ if (bootflags[i] != 0x00 && bootflags[i] != 0x80) return; /* size non-zero -> entry in use */ if (starts[i] && sizes[i]) used = 1; } if (!used) return; /* parse the data for real */ print_line(level, "DOS/MBR partition map"); for (i = 0; i < 4; i++) { start = starts[i]; size = sizes[i]; type = types[i]; if (start == 0 || size == 0) continue; sprintf(append, " from %lu", start); if (bootflags[i] == 0x80) strcat(append, ", bootable"); format_blocky_size(s, size, 512, "sectors", append); print_line(level, "Partition %d: %s", i+1, s); print_line(level + 1, "Type 0x%02X (%s)", type, get_name_for_mbrtype(type)); if (type == 0x05 || type == 0x0f || type == 0x85) { /* extended partition */ detect_dos_partmap_ext(section, start, level + 1, &extpartnum); } else if (type != 0xee) { /* recurse for content detection */ analyze_recursive(section, level + 1, (u8)start * 512, (u8)size * 512, 0); } } } static void detect_dos_partmap_ext(SECTION *section, u8 extbase, int level, int *extpartnum) { unsigned char *buf; u8 tablebase, nexttablebase; int i, off, type, types[4]; u4 start, size, starts[4], sizes[4]; char s[256], append[64]; for (tablebase = extbase; tablebase; tablebase = nexttablebase) { /* read sector from linked list */ if (get_buffer(section, tablebase << 9, 512, (void **)&buf) < 512) return; /* check signature */ if (buf[510] != 0x55 || buf[511] != 0xAA) { print_line(level, "Signature missing"); return; } /* get entries */ for (off = 446, i = 0; i < 4; i++, off += 16) { types[i] = buf[off + 4]; starts[i] = get_le_long(buf + off + 8); sizes[i] = get_le_long(buf + off + 12); } /* parse the data for real */ nexttablebase = 0; for (i = 0; i < 4; i++) { start = starts[i]; size = sizes[i]; type = types[i]; if (size == 0) continue; if (type == 0x05 || type == 0x85) { /* inner extended partition */ nexttablebase = extbase + start; } else { /* logical partition */ sprintf(append, " from %llu+%lu", tablebase, start); format_blocky_size(s, size, 512, "sectors", append); print_line(level, "Partition %d: %s", *extpartnum, s); (*extpartnum)++; print_line(level + 1, "Type 0x%02X (%s)", type, get_name_for_mbrtype(type)); /* recurse for content detection */ if (type != 0xee) { analyze_recursive(section, level + 1, (tablebase + start) * 512, (u8)size * 512, 0); } } } } } /* * EFI GPT partition map */ struct gpttypes { char *guid; char *name; }; struct gpttypes gpt_types[] = { { "\x28\x73\x2A\xC1\x1F\xF8\xD2\x11\xBA\x4B\x00\xA0\xC9\x3E\xC9\x3B", "EFI System (FAT)" }, { "\x41\xEE\x4D\x02\xE7\x33\xD3\x11\x9D\x69\x00\x08\xC7\x81\xF3\x9F", "MBR partition scheme" }, { "\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE", "MS Reserved" }, { "\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7", "Basic Data" }, { "\xAA\xC8\x08\x58\x8F\x7E\xE0\x42\x85\xD2\xE1\xE9\x04\x34\xCF\xB3", "MS LDM Metadata" }, { "\xA0\x60\x9B\xAF\x31\x14\x62\x4F\xBC\x68\x33\x11\x71\x4A\x69\xAD", "MS LDM Data" }, { "\x1E\x4C\x89\x75\xEB\x3A\xD3\x11\xB7\xC1\x7B\x03\xA0\x00\x00\x00", "HP/UX Data" }, { "\x28\xE7\xA1\xE2\xE3\x32\xD6\x11\xA6\x82\x7B\x03\xA0\x00\x00\x00", "HP/UX Service" }, { "\x0F\x88\x9D\xA1\xFC\x05\x3B\x4D\xA0\x06\x74\x3F\x0F\x84\x91\x1E", "Linux RAID" }, { "\x6D\xFD\x57\x06\xAB\xA4\xC4\x43\x84\xE5\x09\x33\xC8\x4B\x4F\x4F", "Linux Swap" }, { "\x79\xD3\xD6\xE6\x07\xF5\xC2\x44\xA2\x3C\x23\x8F\x2A\x3D\xF9\x28", "Linux LVM" }, { "\x39\x33\xA6\x8D\x07\x00\xC0\x60\xC4\x36\x08\x3A\xC8\x23\x09\x08", "Linux Reserved" }, { "\xB4\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", "FreeBSD Data" }, { "\xB5\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", "FreeBSD Swap" }, { "\xB6\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", "FreeBSD UFS" }, { "\xB8\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", "FreeBSD Vinum" }, { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", "Mac HFS+" }, { 0, 0 } }; static char * get_name_for_guid(void *guid) { int i; for (i = 0; gpt_types[i].name; i++) if (memcmp(gpt_types[i].guid, guid, 16) == 0) return gpt_types[i].name; return "Unknown"; } void detect_gpt_partmap(SECTION *section, int level) { unsigned char *buf; u8 diskblocks, partmap_start, start, end, size; u4 partmap_count, partmap_entry_size; u4 i; char s[256], append[64]; int last_unused; /* partition maps only occur at the start of a device */ if (section->pos != 0) return; /* get LBA 1: GPT header */ if (get_buffer(section, 512, 512, (void **)&buf) < 512) return; /* check signature */ if (memcmp(buf, "EFI PART", 8) != 0) return; /* get header information */ if (get_le_quad(buf + 0x18) != 1) return; diskblocks = get_le_quad(buf + 0x20) + 1; partmap_start = get_le_quad(buf + 0x48); partmap_count = get_le_long(buf + 0x50); partmap_entry_size = get_le_long(buf + 0x54); print_line(level, "GPT partition map, %d entries", (int)partmap_count); format_blocky_size(s, diskblocks, 512, "sectors", NULL); print_line(level+1, "Disk size %s", s); format_guid(buf + 0x38, s); print_line(level+1, "Disk GUID %s", s); /* get entries */ last_unused = 0; for (i = 0; i < partmap_count; i++) { if (get_buffer(section, (partmap_start * 512) + i * partmap_entry_size, partmap_entry_size, (void **)&buf) < partmap_entry_size) return; if (memcmp(buf, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) { if (last_unused == 0) print_line(level, "Partition %d: unused", i+1); last_unused = 1; continue; } last_unused = 0; /* size */ start = get_le_quad(buf + 0x20); end = get_le_quad(buf + 0x28); size = end + 1 - start; sprintf(append, " from %llu", start); format_blocky_size(s, size, 512, "sectors", append); print_line(level, "Partition %d: %s", i+1, s); /* type */ format_guid(buf, s); print_line(level+1, "Type %s (GUID %s)", get_name_for_guid(buf), s); /* partition name */ format_utf16_le(buf + 0x38, 72, s); print_line(level+1, "Partition Name \"%s\"", s); /* GUID */ format_guid(buf + 0x10, s); print_line(level+1, "Partition GUID %s", s); /* recurse for content detection */ if (start > 0 && size > 0) { /* avoid recursion on self */ analyze_recursive(section, level + 1, start * 512, size * 512, 0); } } } /* * FAT12/FAT16/FAT32 file systems */ static char *fatnames[] = { "FAT12", "FAT16", "FAT32" }; void detect_fat(SECTION *section, int level) { int i, score, fattype; u4 sectsize, clustersize, reserved, fatcount, dirsize, fatsize; u8 sectcount, clustercount; u2 atari_csum; unsigned char *buf; char s[256]; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; /* first, some hard tests */ /* sector size has four allowed values */ sectsize = get_le_short(buf + 11); if (sectsize != 512 && sectsize != 1024 && sectsize != 2048 && sectsize != 4096) return; /* sectors per cluster: must be a power of two */ clustersize = buf[13]; if (clustersize == 0 || (clustersize & (clustersize - 1))) return; /* since the above is also present on NTFS, make sure it's not NTFS... */ if (memcmp(buf + 3, "NTFS ", 8) == 0) return; /* next, some soft tests, taking score */ score = 0; /* boot jump */ if ((buf[0] == 0xEB && buf[2] == 0x90) || buf[0] == 0xE9) score++; /* boot signature */ if (buf[510] == 0x55 && buf[511] == 0xAA) score++; /* reserved sectors */ reserved = get_le_short(buf + 14); if (reserved == 1 || reserved == 32) score++; /* number of FATs */ fatcount = buf[16]; if (fatcount == 2) score++; /* number of root dir entries */ dirsize = get_le_short(buf + 17); /* sector count (16-bit and 32-bit versions) */ sectcount = get_le_short(buf + 19); if (sectcount == 0) sectcount = get_le_long(buf + 32); /* media byte */ if (buf[21] == 0xF0 || buf[21] >= 0xF8) score++; /* FAT size in sectors */ fatsize = get_le_short(buf + 22); if (fatsize == 0) fatsize = get_le_long(buf + 36); /* determine FAT type */ dirsize = ((dirsize * 32) + (sectsize - 1)) / sectsize; clustercount = sectcount - (reserved + (fatcount * fatsize) + dirsize); clustercount /= clustersize; if (clustercount < 4085) fattype = 0; else if (clustercount < 65525) fattype = 1; else fattype = 2; /* check for ATARI ST boot checksum */ atari_csum = 0; for (i = 0; i < 512; i += 2) atari_csum += get_be_short(buf + i); /* tell the user */ s[0] = 0; if (atari_csum == 0x1234) strcpy(s, ", ATARI ST bootable"); print_line(level, "%s file system (hints score %d of %d%s)", fatnames[fattype], score, 5, s); if (sectsize > 512) print_line(level + 1, "Unusual sector size %lu bytes", sectsize); format_blocky_size(s, clustercount, clustersize * sectsize, "clusters", NULL); print_line(level + 1, "Volume size %s", s); /* get the cached volume name if present */ if (fattype < 2) { if (buf[38] == 0x29) { memcpy(s, buf + 43, 11); s[11] = 0; for (i = 10; i >= 0 && s[i] == ' '; i--) s[i] = 0; if (strcmp(s, "NO NAME") != 0) print_line(level + 1, "Volume name \"%s\"", s); } } else { if (buf[66] == 0x29) { memcpy(s, buf + 71, 11); s[11] = 0; for (i = 10; i >= 0 && s[i] == ' '; i--) s[i] = 0; if (strcmp(s, "NO NAME") != 0) print_line(level + 1, "Volume name \"%s\"", s); } } } /* * NTFS file system */ void detect_ntfs(SECTION *section, int level) { u4 sectsize, clustersize; u8 sectcount; unsigned char *buf; char s[256]; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; /* check signatures */ if (memcmp(buf + 3, "NTFS ", 8) != 0) return; /* disabled for now, mkntfs(8) doesn't generate it if (memcmp(buf + 0x24, "\x80\x00\x80\x00", 4) != 0) return; */ /* sector size: must be a power of two */ sectsize = get_le_short(buf + 11); if (sectsize < 512 || (sectsize & (sectsize - 1))) return; /* sectors per cluster: must be a power of two */ clustersize = buf[13]; if (clustersize == 0 || (clustersize & (clustersize - 1))) return; /* get size in sectors */ sectcount = get_le_quad(buf + 0x28); /* tell the user */ print_line(level, "NTFS file system"); format_blocky_size(s, sectcount, sectsize, "sectors", NULL); print_line(level + 1, "Volume size %s", s); } /* * HPFS file system */ void detect_hpfs(SECTION *section, int level) { unsigned char *buf; char s[256]; u8 sectcount; if (get_buffer(section, 16*512, 512, (void **)&buf) < 512) return; if (memcmp(buf, "\xF9\x95\xE8\x49\xFA\x53\xE9\xC5", 8) != 0) return; print_line(level, "HPFS file system (version %d, functional version %d)", (int)buf[8], (int)buf[9]); sectcount = get_le_long(buf + 16); format_blocky_size(s, sectcount, 512, "sectors", NULL); print_line(level + 1, "Volume size %s", s); /* TODO: BPB in boot sector, volume label -- information? */ } /* * DOS/Windows boot loaders */ void detect_dos_loader(SECTION *section, int level) { int fill; unsigned char *buf; if (section->flags & FLAG_IN_DISKLABEL) return; fill = get_buffer(section, 0, 2048, (void **)&buf); if (fill < 512) return; if (find_memory(buf, fill, "NTLDR", 5) >= 0) print_line(level, "Windows NTLDR boot loader"); else if (find_memory(buf, 512, "WINBOOT SYS", 11) >= 0) print_line(level, "Windows 95/98/ME boot loader"); else if (find_memory(buf, 512, "MSDOS SYS", 11) >= 0) print_line(level, "Windows / MS-DOS boot loader"); } /* EOF */ disktype-9/file.c0000664000076500007650000001542307666372573015013 0ustar chrispchrisp00000000000000/* * file.c * Data source for files and block devices. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" #define USE_BINARY_SEARCH 0 #define DEBUG_SIZE 0 #ifdef USE_IOCTL_LINUX #include #include #endif #ifdef USE_IOCTL_FREEBSD #include #endif #ifdef USE_IOCTL_DARWIN #include #include #endif /* * types */ typedef struct file_source { SOURCE c; int fd; } FILE_SOURCE; /* * helper functions */ static int analyze_file(SOURCE *s, int level); static u8 read_file(SOURCE *s, u8 pos, u8 len, void *buf); static void close_file(SOURCE *s); #if USE_BINARY_SEARCH static int check_position(int fd, u8 pos); #endif /* * initialize the file source */ SOURCE *init_file_source(int fd, int filekind) { FILE_SOURCE *fs; off_t result; fs = (FILE_SOURCE *)malloc(sizeof(FILE_SOURCE)); if (fs == NULL) bailout("Out of memory"); memset(fs, 0, sizeof(FILE_SOURCE)); if (filekind != 0) /* special treatment hook for devices */ fs->c.analyze = analyze_file; fs->c.read_bytes = read_file; fs->c.close = close_file; fs->fd = fd; /* * Determine the size using various methods. The first method that * works is used. */ /* * lseek() to the end: * Works on files. On some systems (Linux), this also works on devices. */ if (!fs->c.size_known) { result = lseek(fd, 0, SEEK_END); #if DEBUG_SIZE printf("Size: lseek returned %lld\n", result); #endif if (result > 0) { fs->c.size_known = 1; fs->c.size = result; } } #ifdef USE_IOCTL_LINUX /* * ioctl, Linux style: * Works on certain devices. */ #ifdef BLKGETSIZE64 #define u64 __u64 /* workaround for broken header file */ if (!fs->c.size_known && filekind != 0) { u8 devsize; if (ioctl(fd, BLKGETSIZE64, (void *)&devsize) >= 0) { fs->c.size_known = 1; fs->c.size = devsize; #if DEBUG_SIZE printf("Size: Linux 64-bit ioctl reports %llu\n", fs->c.size); #endif } } #undef u64 #endif if (!fs->c.size_known && filekind != 0) { u4 blockcount; if (ioctl(fd, BLKGETSIZE, (void *)&blockcount) >= 0) { fs->c.size_known = 1; fs->c.size = (u8)blockcount * 512; #if DEBUG_SIZE printf("Size: Linux 32-bit ioctl reports %llu (%lu blocks)\n", fs->c.size, blockcount); #endif } } #endif #ifdef USE_IOCTL_FREEBSD /* * ioctl, FreeBSD style: * Works on partitioned hard disks or somthing like that. */ if (!fs->c.size_known && filekind != 0) { struct disklabel dl; if (ioctl(fd, DIOCGDINFO, &dl) >= 0) { fs->c.size_known = 1; fs->c.size = (u8) dl.d_ncylinders * dl.d_secpercyl * dl.d_secsize; /* TODO: check this, it's the whole disk size... */ #if DEBUG_SIZE printf("Size: FreeBSD ioctl reports %llu\n", fs->c.size); #endif } } #endif #ifdef USE_IOCTL_DARWIN /* * ioctl, Darwin style: * Works on certain devices. */ if (!fs->c.size_known && filekind != 0) { u4 blocksize; u8 blockcount; if (ioctl(fd, DKIOCGETBLOCKSIZE, (void *)&blocksize) >= 0) { if (ioctl(fd, DKIOCGETBLOCKCOUNT, (void *)&blockcount) >= 0) { fs->c.size_known = 1; fs->c.size = blockcount * blocksize; #if DEBUG_SIZE printf("Size: Darwin ioctl reports %llu (%llu blocks of %lu bytes)\n", fs->c.size, blockcount, blocksize); #endif } } } #endif #if USE_BINARY_SEARCH /* * binary search: * Works on anything that can seek, but is quite expensive. */ if (!fs->c.size_known) { u8 lower, upper, current; /* TODO: check that the target can seek at all */ #if DEBUG_SIZE printf("Size: Doing a binary search\n"); #endif /* first, find an upper bound starting from a reasonable guess */ lower = 0; upper = 1024 * 1024; /* start with 1MB */ while (check_position(fd, upper)) { lower = upper; upper <<= 2; } /* second, nail down the size between the lower and upper bounds */ while (upper > lower + 1) { current = (lower + upper) >> 1; if (check_position(fd, current)) lower = current; else upper = current; } fs->c.size_known = 1; fs->c.size = lower + 1; #if DEBUG_SIZE printf("Size: Binary search reports %llu\n", fs->c.size); #endif } #endif return (SOURCE *)fs; } /* * special handling hook: devices may have out-of-band structure */ static int analyze_file(SOURCE *s, int level) { if (analyze_cdaccess(((FILE_SOURCE *)s)->fd, s, level)) return 1; return 0; } /* * raw read */ static u8 read_file(SOURCE *s, u8 pos, u8 len, void *buf) { off_t result_seek; ssize_t result_read; char *p; u8 got; int fd = ((FILE_SOURCE *)s)->fd; /* seek to the requested position */ result_seek = lseek(fd, pos, SEEK_SET); if (result_seek != pos) { errore("Seek to %llu failed", pos); return 0; } /* read from there */ p = (char *)buf; got = 0; while (len > 0) { result_read = read(fd, p, len); if (result_read < 0) { if (errno == EINTR || errno == EAGAIN) continue; errore("Data read failed at position %llu", pos + got); break; } else if (result_read == 0) { /* simple EOF, no message */ break; } else { len -= result_read; got += result_read; p += result_read; } } return got; } /* * dispose of everything */ static void close_file(SOURCE *s) { int fd = ((FILE_SOURCE *)s)->fd; if (fd >= 0) close(fd); } /* * check if the given position is inside the file's size */ #if USE_BINARY_SEARCH static int check_position(int fd, u8 pos) { char buf[2]; #if DEBUG_SIZE printf(" Probing %llu\n", pos); #endif if (lseek(fd, pos, SEEK_SET) != pos) return 0; if (read(fd, buf, 1) != 1) return 0; return 1; } #endif /* EOF */ disktype-9/global.h0000664000076500007650000001046710440611132015307 0ustar chrispchrisp00000000000000/* * global.h * Common header file. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define PROGNAME "disktype" /* global includes */ #include #include #include #include #include #include #include #include #include /* constants */ #define FLAG_IN_DISKLABEL (0x0001) /* types */ typedef signed char s1; typedef unsigned char u1; typedef short int s2; typedef unsigned short int u2; typedef long int s4; typedef unsigned long int u4; typedef long long int s8; typedef unsigned long long int u8; typedef struct source { u8 size; int size_known; void *cache_head; int sequential; u8 seq_pos; int blocksize; struct source *foundation; int (*analyze)(struct source *s, int level); u8 (*read_bytes)(struct source *s, u8 pos, u8 len, void *buf); int (*read_block)(struct source *s, u8 pos, void *buf); void (*close)(struct source *s); /* private data may follow */ } SOURCE; typedef struct section { u8 pos, size; int flags; SOURCE *source; } SECTION; typedef void (*DETECTOR)(SECTION *section, int level); /* detection dispatching functions */ void analyze_source(SOURCE *s, int level); void analyze_source_special(SOURCE *s, int level, u8 pos, u8 size); void analyze_recursive(SECTION *section, int level, u8 rel_pos, u8 size, int flags); void stop_detect(void); /* file source functions */ SOURCE *init_file_source(int fd, int filekind); int analyze_cdaccess(int fd, SOURCE *s, int level); /* buffer functions */ u8 get_buffer(SECTION *section, u8 pos, u8 len, void **buf); u8 get_buffer_real(SOURCE *s, u8 pos, u8 len, void *inbuf, void **outbuf); void close_source(SOURCE *s); /* output functions */ void print_line(int level, const char *fmt, ...); void start_line(const char *fmt, ...); void continue_line(const char *fmt, ...); void finish_line(int level); /* formatting functions */ void format_blocky_size(char *buf, u8 count, u4 blocksize, const char *blockname, const char *append); void format_size(char *buf, u8 size); void format_size_verbose(char *buf, u8 size); void format_ascii(void *from, char *to); void format_utf16_be(void *from, u4 len, char *to); void format_utf16_le(void *from, u4 len, char *to); void format_uuid(void *from, char *to); void format_uuid_lvm(void *uuid, char *to); void format_guid(void *guid, char *to); /* endian-aware data access */ u2 get_be_short(void *from); u4 get_be_long(void *from); u8 get_be_quad(void *from); u2 get_le_short(void *from); u4 get_le_long(void *from); u8 get_le_quad(void *from); u2 get_ve_short(int endianness, void *from); u4 get_ve_long(int endianness, void *from); u8 get_ve_quad(int endianness, void *from); const char * get_ve_name(int endianness); /* more data access */ void get_string(void *from, int len, char *to); void get_pstring(void *from, char *to); void get_padded_string(void *from, int len, char pad, char *to); int find_memory(void *haystack, int haystack_len, void *needle, int needle_len); /* name table lookups */ char * get_name_for_mbrtype(int type); /* error functions */ void error(const char *msg, ...); void errore(const char *msg, ...); void bailout(const char *msg, ...); void bailoute(const char *msg, ...); /* EOF */ disktype-9/HISTORY0000664000076500007650000000707210440761777015005 0ustar chrispchrisp00000000000000$Id: HISTORY,v 1.32 2006/06/05 07:57:51 chrisp Exp $ -*- text -*- disktype History ================== Version 1 was released on Feb 11, 2003. It supported the following formats: File systems: FAT12/FAT16/FAT32, ext2/ext3, Minix, MFS, HFS, HFS Plus, ISO9660. Partition maps: DOS/PC style, Apple. Boot codes: LILO, GRUB, SYSLINUX, ISOLINUX, Linux kernel. Other structures: Debian split floppy header, gzip header, Linux swap. Version 2 was released on Feb 18, 2003. It brought improvements to the infrastructure, making it possible to analyze the .bin file of a .bin/.cue pair in place. In other news: Added file systems: ReiserFS, NTFS, HPFS, Linux romfs, Linux cramfs. Added other structures: Linux RAID physical disks, Linux LVM physical volumes. Improved file systems: ISO9660, Minix. Improved other structures: Linux swap. Version 3 was released on Mar 15, 2003. It features an extensive re-write of the buffering layer, in conjunction with transparent decompression of data compressed with gzip, compress, or bzip2. Raw CD image detection now works by actually looking at the data. In other news: Added file systems: UFS (some variations), JFS. Added other structures: tar archives, cpio archives, bar archives, dump/restore data. Improved file systems: ext2/ext3, ReiserFS. Improved other structures: Linux swap. UFS and the archive formats are based Doug Merritt's 'tapetype' program. He posted it to Usenet back in 1992 and asked me to include it in disktype so that the code would not be lost. Version 4 was released on Apr 15, 2003. It features the following improvements: Added file systems: Linux squashfs, XFS, Amiga FS/FFS. Added other structures: Amiga "Rigid Disk" partition map, ATARI ST (AHDI3) partition map. Improved file systems: FAT12/FAT16 (a.k.a. ATARI GEMDOS). Improved other structures: - Version 5 was released on May 3, 2003. It includes a range of portability fixes. Most importantly, character devices are no longer blocked out; some systems use them for disks. There is also a range of internal improvements. In other news: Added file systems: BeFS, QNX4, SysV (some variants). Added other structures: BSD disklabel, FreeBSD i386 boot code, Virtual PC hard disk image, Apple UDIF disk image (limited). Improved file systems: UFS, ext2/ext3. Improved other structures: DOS partition map, GRUB boot code. Version 6 was released on June 15, 2003. It now detects blank disks. Size printouts use the prefixes for binary multiples as defined by IEC. On Linux, the TOC of a CD can be read using ioctl's. In other news: Added file systems: UDF. Added other structures: Solaris x86 disklabel (vtoc), Solaris SPARC disklabel. Improved file systems: ISO9660. Improved other structures: - Version 7 was released on Apr 5, 2004. It features the following improvements: Added file systems: 3DO CD-ROM file system, Veritas VxFS. Added other structures: Sega Dreamcast signature. Improved file systems: HFS Plus. Improved other structures: - Version 8 was released on Feb 21, 2005. It features the following improvements: Added file systems: Reiser4, Xbox DVD file system. Added other structures: Linux LVM2 physical volumes. Improved file systems: - Improved other structures: Linux LVM1 physical volumes. Version 9 was released on Jun 5, 2006. It features the following improvements: Added file systems: Amiga SFS. Added other structures: Linux cloop (detection only), EFI GPT, Windows/MS-DOS boot loader, BeOS boot loader. Improved file systems: Amiga FS/FFS, Amiga PFS, Linux squashfs. Improved other structures: Amiga "Rigid Disk" partitioning, LILO, ISO9660 El Torito. EOF disktype-9/lib.c0000664000076500007650000002575210361772326014632 0ustar chrispchrisp00000000000000/* * lib.c * Global utility functions. * * Copyright (c) 2003-2006 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" #include /* * output functions */ #define LEVELS (8) static const char *insets[LEVELS] = { "", " ", " ", " ", " ", " ", " ", " ", }; static char line_akku[4096]; void print_line(int level, const char *fmt, ...) { va_list par; va_start(par, fmt); vsnprintf(line_akku, 4096, fmt, par); va_end(par); if (level >= LEVELS) bailout("Recursion loop caught"); printf("%s%s\n", insets[level], line_akku); } void start_line(const char *fmt, ...) { va_list par; va_start(par, fmt); vsnprintf(line_akku, 4096, fmt, par); va_end(par); } void continue_line(const char *fmt, ...) { va_list par; int len = strlen(line_akku); va_start(par, fmt); vsnprintf(line_akku + len, 4096 - len, fmt, par); va_end(par); } void finish_line(int level) { if (level >= LEVELS) bailout("Recursion loop caught"); printf("%s%s\n", insets[level], line_akku); } /* * formatting functions */ /* TODO: make all of this safe from buffer overruns... */ /* * format_raw_size() does the actual unit-suffix formatting. * * Returns an indicator for the format used: * 0 - rounded to some unit * 1 - whole multiple of some unit (return code limited to KiB) * 2 - plain bytes */ static int format_raw_size(char *buf, u8 size) { int unit_index, dd; u8 unit_size, card; const char *unit_names[] = { "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", NULL }; const int dd_mult[4] = { 1, 10, 100, 1000 }; /* just a few bytes */ if (size < 1024) { sprintf(buf, "%llu bytes", size); return 2; } /* find a suitable unit */ for (unit_index = 0, unit_size = 1024; unit_names[unit_index] != NULL; unit_index++, unit_size <<= 10) { /* size is at least one of the next unit -> use that */ if (size >= 1024 * unit_size) continue; /* check integral multiples */ if ((size % unit_size) == 0) { card = size / unit_size; sprintf(buf, "%d %s", (int)card, unit_names[unit_index]); return unit_index ? 0 : 1; } /* find suitable number of decimal digits */ for (dd = 3; dd >= 1; dd--) { card = (size * dd_mult[dd] + (unit_size >> 1)) / unit_size; if (card >= 10000) continue; /* more than four significant digits */ sprintf(buf, "%d.%0*d %s", (int)(card / dd_mult[dd]), dd, (int)(card % dd_mult[dd]), unit_names[unit_index]); return 0; } } /* fallback (something wrong with the numbers?) */ strcpy(buf, "off the scale"); return 0; } void format_blocky_size(char *buf, u8 count, u4 blocksize, const char *blockname, const char *append) { int used; u8 total_size; char *p; char blocksizebuf[32]; total_size = count * blocksize; used = format_raw_size(buf, total_size); p = strchr(buf, 0); *p++ = ' '; *p++ = '('; if (used != 2) { sprintf(p, "%llu bytes, ", total_size); p = strchr(buf, 0); } if (blocksize == 512 && strcmp(blockname, "sectors") == 0) { sprintf(p, "%llu %s", count, blockname); } else { if (blocksize < 64*1024 && (blocksize % 1024) != 0) sprintf(blocksizebuf, "%lu bytes", blocksize); else format_raw_size(blocksizebuf, blocksize); sprintf(p, "%llu %s of %s", count, blockname, blocksizebuf); } p = strchr(buf, 0); if (append != NULL) { strcpy(p, append); p = strchr(buf, 0); } *p++ = ')'; *p++ = 0; } void format_size(char *buf, u8 size) { int used; used = format_raw_size(buf, size); if (used > 0) return; sprintf(strchr(buf, 0), " (%llu bytes)", size); } void format_size_verbose(char *buf, u8 size) { int used; used = format_raw_size(buf, size); if (used == 2) return; sprintf(strchr(buf, 0), " (%llu bytes)", size); } void format_ascii(void *from, char *to) { u1 *p = (u1 *)from; u1 *q = (u1 *)to; int c; while ((c = *p++)) { if (c >= 127 || c < 32) { *q++ = '<'; *q++ = "0123456789ABCDEF"[c >> 4]; *q++ = "0123456789ABCDEF"[c & 15]; *q++ = '>'; } else { *q++ = c; } } *q = 0; } void format_utf16_be(void *from, u4 len, char *to) { u2 *p = (u2 *)from; u2 *p_end; u1 *q = (u1 *)to; u2 c; if (len) p_end = (u2 *)(((u1 *)from) + len); else p_end = NULL; while (p_end == NULL || p < p_end) { c = get_be_short(p); if (c == 0) break; p++; /* advance 2 bytes */ if (c >= 127 || c < 32) { *q++ = '<'; *q++ = "0123456789ABCDEF"[c >> 12]; *q++ = "0123456789ABCDEF"[(c >> 8) & 15]; *q++ = "0123456789ABCDEF"[(c >> 4) & 15]; *q++ = "0123456789ABCDEF"[c & 15]; *q++ = '>'; } else { *q++ = (u1)c; } } *q = 0; } void format_utf16_le(void *from, u4 len, char *to) { u2 *p = (u2 *)from; u2 *p_end; u1 *q = (u1 *)to; u2 c; if (len) p_end = (u2 *)(((u1 *)from) + len); else p_end = NULL; while (p_end == NULL || p < p_end) { c = get_le_short(p); if (c == 0) break; p++; /* advance 2 bytes */ if (c >= 127 || c < 32) { *q++ = '<'; *q++ = "0123456789ABCDEF"[c >> 12]; *q++ = "0123456789ABCDEF"[(c >> 8) & 15]; *q++ = "0123456789ABCDEF"[(c >> 4) & 15]; *q++ = "0123456789ABCDEF"[c & 15]; *q++ = '>'; } else { *q++ = (u1)c; } } *q = 0; } void format_uuid(void *uuid, char *to) { u1 *from = uuid; int i, c, variant, version; if (memcmp(uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) { strcpy(to, "nil"); return; } variant = from[8] >> 5; version = from[6] >> 4; for (i = 0; i < 16; i++) { c = *from++; *to++ = "0123456789ABCDEF"[c >> 4]; *to++ = "0123456789ABCDEF"[c & 15]; if (i == 3 || i == 5 || i == 7 || i == 9) *to++ = '-'; } if ((variant & 4) == 0) { /* 0 x x */ strcpy(to, " (NCS)"); } else if ((variant & 2) == 0) { /* 1 0 x */ sprintf(to, " (DCE, v%1.1d)", version); } else if ((variant & 1) == 0) { /* 1 1 0 */ strcpy(to, " (MS GUID)"); } else { /* 1 1 1 */ strcpy(to, " (Reserved)"); } } void format_uuid_lvm(void *uuid, char *to) { char *from = uuid; int i; for (i = 0; i < 32; i++) { *to++ = *from++; if ((i & 3) == 1 && i > 1 && i < 29) *to++ = '-'; } *to = 0; } void format_guid(void *guid, char *to) { u1 *from = guid; int i, c; if (memcmp(guid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) { strcpy(to, "nil"); return; } for (i = 0; i < 16; i++) { c = *from++; *to++ = "0123456789ABCDEF"[c >> 4]; *to++ = "0123456789ABCDEF"[c & 15]; if (i == 3 || i == 5 || i == 7 || i == 9) *to++ = '-'; } *to = 0; } /* * endian-aware data access */ u2 get_be_short(void *from) { u1 *p = from; return ((u2)(p[0]) << 8) + (u2)p[1]; } u4 get_be_long(void *from) { u1 *p = from; return ((u4)(p[0]) << 24) + ((u4)(p[1]) << 16) + ((u4)(p[2]) << 8) + (u4)p[3]; } u8 get_be_quad(void *from) { u1 *p = from; return ((u8)(p[0]) << 56) + ((u8)(p[1]) << 48) + ((u8)(p[2]) << 40) + ((u8)(p[3]) << 32) + ((u8)(p[4]) << 24) + ((u8)(p[5]) << 16) + ((u8)(p[6]) << 8) + (u8)p[7]; } u2 get_le_short(void *from) { u1 *p = from; return ((u2)(p[1]) << 8) + (u2)p[0]; } u4 get_le_long(void *from) { u1 *p = from; return ((u4)(p[3]) << 24) + ((u4)(p[2]) << 16) + ((u4)(p[1]) << 8) + (u4)p[0]; } u8 get_le_quad(void *from) { u1 *p = from; return ((u8)(p[7]) << 56) + ((u8)(p[6]) << 48) + ((u8)(p[5]) << 40) + ((u8)(p[4]) << 32) + ((u8)(p[3]) << 24) + ((u8)(p[2]) << 16) + ((u8)(p[1]) << 8) + (u8)p[0]; } u2 get_ve_short(int endianness, void *from) { if (endianness) return get_le_short(from); else return get_be_short(from); } u4 get_ve_long(int endianness, void *from) { if (endianness) return get_le_long(from); else return get_be_long(from); } u8 get_ve_quad(int endianness, void *from) { if (endianness) return get_le_quad(from); else return get_be_quad(from); } const char * get_ve_name(int endianness) { if (endianness) return "little-endian"; else return "big-endian"; } /* * more data access */ void get_string(void *from, int len, char *to) { if (len > 255) len = 255; memcpy(to, from, len); to[len] = 0; } void get_pstring(void *from, char *to) { int len = *(unsigned char *)from; memcpy(to, (char *)from + 1, len); to[len] = 0; } void get_padded_string(void *from, int len, char pad, char *to) { int pos; get_string(from, len, to); for (pos = strlen(to) - 1; pos >= 0 && to[pos] == pad; pos--) to[pos] = 0; } int find_memory(void *haystack, int haystack_len, void *needle, int needle_len) { int searchlen = haystack_len - needle_len + 1; int pos = 0; void *p; while (pos < searchlen) { p = memchr((char *)haystack + pos, *(unsigned char *)needle, searchlen - pos); if (p == NULL) return -1; pos = (char *)p - (char *)haystack; if (memcmp(p, needle, needle_len) == 0) return pos; pos++; } return -1; } /* * error functions */ void error(const char *msg, ...) { va_list par; char buf[4096]; va_start(par, msg); vsnprintf(buf, 4096, msg, par); va_end(par); fprintf(stderr, PROGNAME ": %s\n", buf); } void errore(const char *msg, ...) { va_list par; char buf[4096]; va_start(par, msg); vsnprintf(buf, 4096, msg, par); va_end(par); fprintf(stderr, PROGNAME ": %s: %s\n", buf, strerror(errno)); } void bailout(const char *msg, ...) { va_list par; char buf[4096]; va_start(par, msg); vsnprintf(buf, 4096, msg, par); va_end(par); fprintf(stderr, PROGNAME ": %s\n", buf); exit(1); } void bailoute(const char *msg, ...) { va_list par; char buf[4096]; va_start(par, msg); vsnprintf(buf, 4096, msg, par); va_end(par); fprintf(stderr, PROGNAME ": %s: %s\n", buf, strerror(errno)); exit(1); } /* EOF */ disktype-9/LICENSE0000664000076500007650000000215207622023547014712 0ustar chrispchrisp00000000000000 * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * disktype-9/linux.c0000664000076500007650000004153110440636362015211 0ustar chrispchrisp00000000000000/* * linux.c * Detection of Linux file systems and boot codes * * Copyright (c) 2003-2006 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * ext2/ext3 file system */ void detect_ext23(SECTION *section, int level) { unsigned char *buf; char s[256]; u4 blocksize; u8 blockcount; if (get_buffer(section, 1024, 1024, (void **)&buf) < 1024) return; if (get_le_short(buf + 56) == 0xEF53) { if (get_le_long(buf + 96) & 0x0008) /* JOURNAL_DEV flag */ print_line(level, "Ext3 external journal"); else if (get_le_long(buf + 92) & 0x0004) /* HAS_JOURNAL flag */ print_line(level, "Ext3 file system"); else print_line(level, "Ext2 file system"); get_string(buf + 120, 16, s); if (s[0]) print_line(level + 1, "Volume name \"%s\"", s); format_uuid(buf + 104, s); print_line(level + 1, "UUID %s", s); get_string(buf + 136, 64, s); if (s[0]) print_line(level + 1, "Last mounted at \"%s\"", s); blocksize = 1024 << get_le_long(buf + 24); blockcount = get_le_long(buf + 4); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); /* 76 4 s_rev_level */ /* 62 2 s_minor_rev_level */ /* 72 4 s_creator_os */ /* 92 3x4 s_feature_compat, s_feature_incompat, s_feature_ro_compat */ } } /* * ReiserFS file system */ void detect_reiser(SECTION *section, int level) { unsigned char *buf; int i, at, newformat; int offsets[3] = { 8, 64, -1 }; char s[256]; u8 blockcount; u4 blocksize; for (i = 0; offsets[i] >= 0; i++) { at = offsets[i]; if (get_buffer(section, at * 1024, 1024, (void **)&buf) < 1024) continue; /* check signature */ if (memcmp(buf + 52, "ReIsErFs", 8) == 0) { print_line(level, "ReiserFS file system (old 3.5 format, standard journal, starts at %d KiB)", at); newformat = 0; } else if (memcmp(buf + 52, "ReIsEr2Fs", 9) == 0) { print_line(level, "ReiserFS file system (new 3.6 format, standard journal, starts at %d KiB)", at); newformat = 1; } else if (memcmp(buf + 52, "ReIsEr3Fs", 9) == 0) { newformat = get_le_short(buf + 72); if (newformat == 0) { print_line(level, "ReiserFS file system (old 3.5 format, non-standard journal, starts at %d KiB)", at); } else if (newformat == 2) { print_line(level, "ReiserFS file system (new 3.6 format, non-standard journal, starts at %d KiB)", at); newformat = 1; } else { print_line(level, "ReiserFS file system (v3 magic, but unknown version %d, starts at %d KiB)", newformat, at); continue; } } else continue; /* get data */ blockcount = get_le_long(buf); blocksize = get_le_short(buf + 44); /* for new format only: hashtype = get_le_long(buf + 64); */ /* get label */ get_string(buf + 100, 16, s); if (s[0]) print_line(level + 1, "Volume name \"%s\"", s); format_uuid(buf + 84, s); print_line(level + 1, "UUID %s", s); /* print size */ format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); /* TODO: print hash code */ } } /* * Reiser4 file system */ void detect_reiser4(SECTION *section, int level) { unsigned char *buf; char s[256]; int layout_id; char layout_name[64]; u4 blocksize; u8 blockcount; if (get_buffer(section, 16 * 4096, 1024, (void **)&buf) < 1024) return; /* check signature */ if (memcmp(buf, "ReIsEr4", 7) != 0) return; /* get data from master superblock */ layout_id = get_le_short(buf + 16); blocksize = get_le_short(buf + 18); if (layout_id == 0) strcpy(layout_name, "4.0 layout"); else sprintf(layout_name, "Unknown layout with ID %d", layout_id); format_size(s, blocksize); print_line(level, "Reiser4 file system (%s, block size %s)", layout_name, s); /* get label and UUID */ get_string(buf + 36, 16, s); if (s[0]) print_line(level + 1, "Volume name \"%s\"", s); format_uuid(buf + 20, s); print_line(level + 1, "UUID %s", s); if (layout_id == 0) { /* read 4.0 superblock */ if (get_buffer(section, 17 * 4096, 1024, (void **)&buf) < 1024) return; if (memcmp(buf + 52, "ReIsEr40FoRmAt", 14) != 0) { print_line(level + 1, "Superblock for 4.0 format missing"); return; } blockcount = get_le_quad(buf); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); } } /* * Linux RAID persistent superblock */ static char *levels[] = { "Multipath", "\'HSM\'", "\'translucent\'", "Linear", "RAID0", "RAID1", NULL, NULL, "RAID4(?)", "RAID5" }; void detect_linux_raid(SECTION *section, int level) { unsigned char *buf; u8 pos; int rlevel, nr_disks, raid_disks, spare; u1 uuid[16]; char s[256]; /* don't do this if: * - the size is unknown (0) * - the size is too small for the calculation * - it is inefficient to read from the end of the source */ if (section->size < 65536 || section->source->sequential) return; /* get RAID superblock from the end of the device */ pos = (section->size & ~65535) - 65536; if (get_buffer(section, pos, 4096, (void **)&buf) < 4096) return; /* signature */ if (get_le_long(buf) != 0xa92b4efc) return; print_line(level, "Linux RAID disk, version %lu.%lu.%lu", get_le_long(buf + 4), get_le_long(buf + 8), get_le_long(buf + 12)); /* get some data */ rlevel = (int)(long)get_le_long(buf + 28); /* is signed, actually */ nr_disks = get_le_long(buf + 36); raid_disks = get_le_long(buf + 40); spare = nr_disks - raid_disks; /* find the name for the personality in the table */ if (rlevel < -4 || rlevel > 5 || levels[rlevel+4] == NULL) { print_line(level + 1, "Unknown RAID level %d using %d regular %d spare disks", rlevel, raid_disks, spare); } else { print_line(level + 1, "%s set using %d regular %d spare disks", levels[rlevel+4], raid_disks, spare); } /* get the UUID */ memcpy(uuid, buf + 5*4, 4); memcpy(uuid + 4, buf + 13*4, 3*4); format_uuid(uuid, s); print_line(level + 1, "RAID set UUID %s", s); } /* * Linux LVM1 */ void detect_linux_lvm(SECTION *section, int level) { unsigned char *buf; char s[256]; int minor_version, pv_number; u8 pe_size, pe_count, pe_start; if (get_buffer(section, 0, 1024, (void **)&buf) < 1024) return; /* signature */ if (buf[0] != 'H' || buf[1] != 'M') return; /* helpful sanity check... */ if (get_le_long(buf + 36) == 0 || get_le_long(buf + 40) == 0) return; minor_version = get_le_short(buf + 2); print_line(level, "Linux LVM1 volume, version %d%s", minor_version, (minor_version < 1 || minor_version > 2) ? " (unknown)" : ""); /* volume group name */ get_string(buf + 172, 128, s); print_line(level + 1, "Volume group name \"%s\"", s); /* "UUID" of this physical volume */ format_uuid_lvm(buf + 0x2c, s); print_line(level + 1, "PV UUID %s", s); /* number of this physical volume */ pv_number = get_le_long(buf + 432); print_line(level + 1, "PV number %d", pv_number); /* volume size */ pe_size = get_le_long(buf + 452); pe_count = get_le_long(buf + 456); format_blocky_size(s, pe_count, pe_size * 512, "PEs", NULL); print_line(level + 1, "Useable size %s", s); /* get start of first PE */ if (minor_version == 1) { /* minor format 1: first PE starts after the declared length of the PE tables */ pe_start = get_le_long(buf + 36) + get_le_long(buf + 40); } else if (minor_version == 2) { /* minor format 2: a field in the header indicates this */ pe_start = get_le_long(buf + 464) << 9; } else { /* unknown minor format */ pe_start = 0; } /* try to detect from first PE */ if (pe_start > 0) { analyze_recursive(section, level + 1, pe_start, 0, 0); /* TODO: elaborate on this by reading the PE allocation map */ } } /* * Linux LVM2 */ void detect_linux_lvm2(SECTION *section, int level) { unsigned char *buf; int at, i; char s[256]; u8 labelsector; u4 labeloffset; u8 pvsize, mdoffset, mdsize; int mda_version; for (at = 0; at < 4; at++) { if (get_buffer(section, at * 512, 512, (void **)&buf) < 512) continue; /* check signature */ if (memcmp(buf, "LABELONE", 8) != 0) continue; labelsector = get_le_quad(buf + 8); labeloffset = get_le_long(buf + 20); if (memcmp(buf + 24, "LVM2 001", 8) != 0) { get_string(buf + 24, 8, s); print_line(level, "LABELONE label at sector %d, unknown type \"%s\"", at, s); return; } print_line(level, "Linux LVM2 volume, version 001"); print_line(level + 1, "LABELONE label at sector %d", at); if (labeloffset >= 512 || labelsector > 256 || labelsector != at) { print_line(level + 1, "LABELONE data inconsistent, aborting analysis"); return; } /* "UUID" of this physical volume */ format_uuid_lvm(buf + labeloffset, s); print_line(level + 1, "PV UUID %s", s); /* raw volume size */ pvsize = get_le_quad(buf + labeloffset + 32); format_size_verbose(s, pvsize); print_line(level + 1, "Volume size %s", s); /* find first metadata area in list */ mdoffset = 0; for (i = 0; i < 16; i++) if (get_le_quad(buf + labeloffset + 40 + i * 16) == 0) { i++; mdoffset = get_le_quad(buf + labeloffset + 40 + i * 16); mdsize = get_le_quad(buf + labeloffset + 40 + i * 16 + 8); break; } if (mdoffset == 0) return; if (get_buffer(section, mdoffset, mdsize, (void **)&buf) < mdsize) return; if (memcmp(buf + 4, " LVM2 x[5A%r0N*>", 16) != 0) return; mda_version = get_le_long(buf + 20); print_line(level + 1, "Meta-data version %d", mda_version); /* TODO: parse the metadata area (big task...) */ return; } } /* * Linux swap area */ void detect_linux_swap(SECTION *section, int level) { int i, en, pagesize; unsigned char *buf; u4 version, pages; char s[256]; int pagesizes[] = { 4096, 8192, 0 }; for (i = 0; pagesizes[i]; i++) { pagesize = pagesizes[i]; if (get_buffer(section, pagesize - 512, 512, (void **)&buf) != 512) break; /* assumes page sizes increase through the loop */ if (memcmp((char *)buf + 512 - 10, "SWAP-SPACE", 10) == 0) { print_line(level, "Linux swap, version 1, %d KiB pages", pagesize >> 10); } if (memcmp((char *)buf + 512 - 10, "SWAPSPACE2", 10) == 0) { if (get_buffer(section, 1024, 512, (void **)&buf) != 512) break; /* really shouldn't happen */ for (en = 0; en < 2; en++) { version = get_ve_long(en, buf); if (version >= 1 && version < 10) break; } if (en < 2) { print_line(level, "Linux swap, version 2, subversion %d, %d KiB pages, %s", (int)version, pagesize >> 10, get_ve_name(en)); if (version == 1) { pages = get_ve_long(en, buf + 4) - 1; format_blocky_size(s, pages, pagesize, "pages", NULL); print_line(level + 1, "Swap size %s", s); } } else { print_line(level, "Linux swap, version 2, illegal subversion, %d KiB pages", pagesize >> 10); } } } } /* * various file systems */ void detect_linux_misc(SECTION *section, int level) { int magic, fill, off, en; unsigned char *buf; char s[256]; u8 size, blocks, blocksize; fill = get_buffer(section, 0, 2048, (void **)&buf); if (fill < 512) return; /* minix file system */ if (fill >= 2048) { int version = 0, namesize = 14; magic = get_le_short(buf + 1024 + 16); if (magic == 0x137F) version = 1; if (magic == 0x138F) { version = 1; namesize = 30; } if (magic == 0x2468) version = 2; if (magic == 0x2478) { version = 2; namesize = 30; } if (version) { print_line(level, "Minix file system (v%d, %d chars)", version, namesize); if (version == 1) blocks = get_le_short(buf + 1024 + 2); else blocks = get_le_long(buf + 1024 + 20); blocks = (blocks - get_le_short(buf + 1024 + 8)) << get_le_short(buf + 1024 + 10); format_blocky_size(s, blocks, 1024, "blocks", NULL); print_line(level + 1, "Volume size %s", s); } } /* Linux romfs */ if (memcmp(buf, "-rom1fs-", 8) == 0) { size = get_be_long(buf + 8); print_line(level, "Linux romfs"); print_line(level+1, "Volume name \"%.300s\"", (char *)(buf + 16)); format_size_verbose(s, size); print_line(level+1, "Volume size %s", s); } /* Linux cramfs */ for (off = 0; off <= 512; off += 512) { if (fill < off + 512) break; for (en = 0; en < 2; en++) { if (get_ve_long(en, buf + off) == 0x28cd3d45) { print_line(level, "Linux cramfs, starts sector %d, %s", off >> 9, get_ve_name(en)); get_string(buf + off + 48, 16, s); print_line(level + 1, "Volume name \"%s\"", s); size = get_ve_long(en, buf + off + 4); blocks = get_ve_long(en, buf + off + 40); format_size_verbose(s, size); print_line(level + 1, "Compressed size %s", s); format_blocky_size(s, blocks, 4096, "blocks", " -assumed-"); print_line(level + 1, "Data size %s", s); } } } /* Linux squashfs */ for (en = 0; en < 2; en++) { if (get_ve_long(en, buf) == 0x73717368) { int major, minor; major = get_ve_short(en, buf + 28); minor = get_ve_short(en, buf + 30); print_line(level, "Linux squashfs, version %d.%d, %s", major, minor, get_ve_name(en)); if (major > 2) size = get_ve_quad(en, buf + 63); else size = get_ve_long(en, buf + 8); if (major > 1) blocksize = get_ve_long(en, buf + 51); else blocksize = get_ve_short(en, buf + 32); format_size_verbose(s, size); print_line(level + 1, "Compressed size %s", s); format_size(s, blocksize); print_line(level + 1, "Block size %s", s); } } } /* * various boot code signatures */ void detect_linux_loader(SECTION *section, int level) { int fill, executable, id; unsigned char *buf; if (section->flags & FLAG_IN_DISKLABEL) return; fill = get_buffer(section, 0, 2048, (void **)&buf); if (fill < 512) return; executable = (get_le_short(buf + 510) == 0xaa55) ? 1 : 0; /* boot sector stuff */ if (executable && (memcmp(buf + 2, "LILO", 4) == 0 || memcmp(buf + 6, "LILO", 4) == 0)) print_line(level, "LILO boot loader"); if (executable && memcmp(buf + 3, "SYSLINUX", 8) == 0) print_line(level, "SYSLINUX boot loader"); if (fill >= 1024 && find_memory(buf, fill, "ISOLINUX", 8) >= 0) print_line(level, "ISOLINUX boot loader"); /* we know GRUB a little better... */ if (executable && find_memory(buf, 512, "Geom\0Hard Disk\0Read\0 Error\0", 27) >= 0) { if (buf[0x3e] == 3) { print_line(level, "GRUB boot loader, compat version %d.%d, boot drive 0x%02x", (int)buf[0x3e], (int)buf[0x3f], (int)buf[0x40]); } else if (executable && buf[0x1bc] == 2 && buf[0x1bd] <= 2) { id = buf[0x3e]; if (id == 0x10) { print_line(level, "GRUB boot loader, compat version %d.%d, normal version", (int)buf[0x1bc], (int)buf[0x1bd]); } else if (id == 0x20) { print_line(level, "GRUB boot loader, compat version %d.%d, LBA version", (int)buf[0x1bc], (int)buf[0x1bd]); } else { print_line(level, "GRUB boot loader, compat version %d.%d", (int)buf[0x1bc], (int)buf[0x1bd]); } } else { print_line(level, "GRUB boot loader, unknown compat version %d", buf[0x3e]); } } /* Linux kernel loader */ if (fill >= 1024 && memcmp(buf + 512 + 2, "HdrS", 4) == 0) { print_line(level, "Linux kernel build-in loader"); } /* Debian install floppy splitter */ /* (not exactly boot code, but should be detected before gzip/tar) */ if (memcmp(buf, "Floppy split ", 13) == 0) { char *name = (char *)buf + 32; char *number = (char *)buf + 164; char *total = (char *)buf + 172; print_line(level, "Debian floppy split, name \"%s\", disk %s of %s", name, number, total); } } /* EOF */ disktype-9/main.c0000664000076500007650000001161507663726560015013 0ustar chrispchrisp00000000000000/* * main.c * Main entry point and global utility functions. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" #ifdef USE_MACOS_TYPE #include #endif /* * local functions */ static void analyze_file(const char *filename); static void print_kind(int filekind, u8 size, int size_known); #ifdef USE_MACOS_TYPE static void show_macos_type(const char *filename); #endif /* * entry point */ int main(int argc, char *argv[]) { int i; /* argument check */ if (argc < 2) { fprintf(stderr, "Usage: %s ...\n", PROGNAME); return 1; } /* loop over filenames */ print_line(0, ""); for (i = 1; i < argc; i++) { analyze_file(argv[i]); print_line(0, ""); } return 0; } /* * Analyze one file */ static void analyze_file(const char *filename) { int fd, filekind; u8 filesize; struct stat sb; char *reason; SOURCE *s; print_line(0, "--- %s", filename); /* stat check */ if (stat(filename, &sb) < 0) { errore("Can't stat %.300s", filename); return; } filekind = 0; filesize = 0; reason = NULL; if (S_ISREG(sb.st_mode)) { filesize = sb.st_size; print_kind(filekind, filesize, 1); } else if (S_ISBLK(sb.st_mode)) filekind = 1; else if (S_ISCHR(sb.st_mode)) filekind = 2; else if (S_ISDIR(sb.st_mode)) reason = "Is a directory"; else if (S_ISFIFO(sb.st_mode)) reason = "Is a FIFO"; #ifdef S_ISSOCK else if (S_ISSOCK(sb.st_mode)) reason = "Is a socket"; #endif else reason = "Is an unknown kind of special file"; if (reason != NULL) { error("%.300s: %s", filename, reason); return; } /* Mac OS type & creator code (if running on Mac OS X) */ #ifdef USE_MACOS_TYPE if (filekind == 0) show_macos_type(filename); #endif /* empty regular files need no further analysis */ if (filekind == 0 && filesize == 0) return; /* open for reading */ fd = open(filename, O_RDONLY); if (fd < 0) { errore("Can't open %.300s", filename); return; } /* (try to) guard against TTY character devices */ if (filekind == 2) { if (isatty(fd)) { error("%.300s: Is a TTY device", filename); return; } } /* create a source */ s = init_file_source(fd, filekind); /* tell the user what it is */ if (filekind != 0) print_kind(filekind, s->size, s->size_known); /* now analyze it */ analyze_source(s, 0); /* finish it up */ close_source(s); } static void print_kind(int filekind, u8 size, int size_known) { char buf[256], *kindname; if (filekind == 0) kindname = "Regular file"; else if (filekind == 1) kindname = "Block device"; else if (filekind == 2) kindname = "Character device"; else kindname = "Unknown kind"; if (size_known) { format_size_verbose(buf, size); print_line(0, "%s, size %s", kindname, buf); } else { print_line(0, "%s, unknown size", kindname); } } /* * Mac OS type & creator code */ #ifdef USE_MACOS_TYPE static void show_macos_type(const char *filename) { int err; FSRef ref; FSCatalogInfo info; FInfo *finfo; err = FSPathMakeRef(filename, &ref, NULL); if (err == 0) { err = FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &info, NULL, NULL, NULL); } if (err == 0) { finfo = (FInfo *)(info.finderInfo); if (finfo->fdType != 0 || finfo->fdCreator != 0) { char typecode[5], creatorcode[5], s1[256], s2[256]; memcpy(typecode, &finfo->fdType, 4); typecode[4] = 0; format_ascii(typecode, s1); memcpy(creatorcode, &finfo->fdCreator, 4); creatorcode[4] = 0; format_ascii(creatorcode, s2); print_line(0, "Type code \"%s\", creator code \"%s\"", s1, s2); } else { print_line(0, "No type and creator code"); } } if (err) { print_line(0, "Type and creator code unknown (error %d)", err); } } #endif /* EOF */ disktype-9/Makefile0000664000076500007650000000303110361514003015324 0ustar chrispchrisp00000000000000### ### Makefile for disktype ### RM = rm -f CC = gcc OBJS = main.o lib.o \ buffer.o file.o cdaccess.o cdimage.o vpc.o compressed.o \ detect.o apple.o amiga.o atari.o dos.o cdrom.o \ linux.o unix.o beos.o archives.o \ udf.o blank.o cloop.o TARGET = disktype CPPFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 CFLAGS = -Wall LDFLAGS = LIBS = ifeq ($(NOSYS),) system = $(shell uname) ifeq ($(system),Linux) CPPFLAGS += -DUSE_IOCTL_LINUX endif ifeq ($(system),FreeBSD) # not entirely tested yet #CPPFLAGS += -DUSE_IOCTL_FREEBSD endif ifeq ($(system),Darwin) CPPFLAGS += -DUSE_MACOS_TYPE -DUSE_IOCTL_DARWIN LIBS += -framework CoreServices ifeq (/Developer/SDKs/MacOSX10.4u.sdk,$(wildcard /Developer/SDKs/MacOSX10.4u.sdk)) CPPFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk CFLAGS += -arch i386 -arch ppc LDFLAGS += -arch i386 -arch ppc -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk endif endif ifeq ($(system),AmigaOS) CC += -noixemul CFLAGS += -m68020-60 -msmall-code LDFLAGS += -m68020-60 endif endif # real making all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) $(OBJS): %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< # cleanup clean: $(RM) *.o *~ *% $(TARGET) distclean: clean $(RM) .depend # automatic dependencies depend: dep dep: for i in $(OBJS:.o=.c) ; do $(CC) $(CPPFLAGS) -MM $$i ; done > .depend ifeq (.depend,$(wildcard .depend)) include .depend endif # eof disktype-9/README0000664000076500007650000000761510440761777014604 0ustar chrispchrisp00000000000000$Id: README,v 1.17 2006/06/05 07:57:51 chrisp Exp $ -*- text -*- disktype 9 ============ The purpose of disktype is to detect the content format of a disk or disk image. It knows about common file systems, partition tables, and boot codes. The program is written in C and is designed to compile on any modern Unix flavour. It is self-contained and in general works without special libraries or headers. Some system-dependent features can be used to gather additional information. Installation -------------- GNU make is required to build disktype. The Makefile is set up to use GCC, but disktype should compile with any C compiler. To change the compiler, you can edit the Makefile or set the standard variables CC, CPPFLAGS, CFLAGS, LDFLAGS, and LIBS from the make command line. The Makefile uses uname to determine the system type and enables certain system-dependent features based on that. If you run into problems, you can disable all system-dependent features by setting the variable NOSYS, as in 'make NOSYS=1'. Running make results in the binary 'disktype'. Copy it to a 'bin' directory of your choice, optionally stripping it on the way. It does not require any additional files. The manual page 'disktype.1' can be copied to /usr/local/share/man/man1 or a similar directory that is suitable for your system and policy. If you package disktype for binary distribution, please also include the README, HISTORY, TODO, and LICENSE files in a place like /usr/share/doc/disktype. Usage ------- The 'disktype' program can be run with any number of regular files or device special files as arguments. They will be analyzed in the order given, and the results printed to standard output. There are no switches in this version. Note that running disktype on device files like your hard disk will likely require root rights. See the online documentation at for some example command lines. Recognized Formats -------------------- The following formats are recognized by this version of disktype. File systems: FAT12/FAT16/FAT32, NTFS, HPFS, MFS, HFS, HFS Plus, ISO9660, ext2/ext3, Minix, ReiserFS, Reiser4, Linux romfs, Linux cramfs, Linux squashfs, UFS (some variations), SysV FS (some variations), JFS, XFS, Amiga FS/FFS, Amiga SFS, Amiga PFS, BeOS BFS, QNX4 FS, UDF, 3DO CD-ROM file system, Veritas VxFS, Xbox DVD file system. Partitioning: DOS/PC style, EFI GPT, Apple, Amiga "Rigid Disk", ATARI ST (AHDI3), BSD disklabel, Linux RAID physical disks, Linux LVM1 physical volumes, Linux LVM2 physical volumes, Solaris x86 disklabel (vtoc), Solaris SPARC disklabel. Other structures: Debian split floppy header, Linux swap. Disk images: Raw CD image (.bin), Virtual PC hard disk image, Apple UDIF disk image (limited), Linux cloop (limited). Boot loaders: LILO, GRUB, SYSLINUX, ISOLINUX, Linux kernel, FreeBSD loader, Windows/MS-DOS loader, BeOS loader, Haiku loader, Sega Dreamcast. Compression formats: gzip, compress, bzip2. Archive formats: tar, cpio, bar, dump/restore. Compressed files (gzip, compress, bzip2 formats) will also have their contents analyzed using transparent decompression. The appropriate compression program must be installed on the system, i.e. 'gzip' for the gzip and compress formats, 'bzip2' for the bzip2 format. Disk images in general will also have their contents analyzed using the proper mapping, with the exception of the Apple UDIF format. See the online documentation at for more details on the supported formats and their quirks. Future Plans -------------- To fulfill its purpose, disktype needs to know about as much formats as possible. If you know a file system not yet included and can provide me with (pointers to) format information, please contact me at . I'm also looking for information on disk image formats (e.g. used by backup apps or CD mastering software). EOF disktype-9/Seedfile0000664000076500007650000000055210361514003015334 0ustar chrispchrisp00000000000000# Seedfile for disktype package disktype 8; binary disktype { source main.c lib.c buffer.c file.c cdaccess.c cdimage.c vpc.c compressed.c detect.c apple.c amiga.c atari.c dos.c cdrom.c linux.c unix.c beos.c archives.c udf.c blank.c cloop.c; cflags "-D_LARGEFILE_SOURCE" "-D_FILE_OFFSET_BITS=64"; } manpage disktype.1; disktype-9/TODO0000664000076500007650000000104310440332744014365 0ustar chrispchrisp00000000000000$Id: TODO,v 1.12 2006/06/03 16:16:36 chrisp Exp $ -*- text -*- disktype ToDo =============== Check NTFS, HPFS, FAT stuff Check EVMS Nero CD images (.nrg) Other disklabels: SGI, OSF, Ultrix, Acorn, MS LDM, IBM, Minix, Unixware Other FS: SGI EFS, SCO BFS, Acorn ADFS, JFFS1/2, IBM CMS FS Reverse-engineer the format of Apple disk images (esp. .dmg's) Port CD TOC access (ioctl's) to non-Linux systems Use C99 fixed-size integer types (see "c99-branch" in CVS) Make disktype a reusable library Record detection results in a data structure disktype-9/udf.c0000664000076500007650000001355710361562101014626 0ustar chrispchrisp00000000000000/* * udf.c * Detection of UDF file system * * UDF support integrated by Aaron Geyer of StorageQuest, Inc. * * UDF sniffer based on Richard Freeman's work at StorageQuest, Inc. * * Extensive changes by Christoph Pfisterer * * Copyright (c) 2003 Aaron Geyer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include "global.h" static int probe_udf(SECTION *section, int level, int sector_size); static int validate_tag(unsigned char *buf, u4 sector); void detect_udf(SECTION *section, int level) { unsigned char *buffer; unsigned char sig_bea[7] = {0x00, 0x42, 0x45, 0x41, 0x30, 0x31, 0x01}; /* B E A 0 1 */ unsigned char sig_nsr2[7] = {0x00, 0x4e, 0x53, 0x52, 0x30, 0x32, 0x01}; /* N S R 0 2 */ unsigned char sig_nsr3[7] = {0x00, 0x4e, 0x53, 0x52, 0x30, 0x33, 0x01}; /* N S R 0 3 */ unsigned char sig_tea[7] = {0x00, 0x54, 0x45, 0x41, 0x30, 0x31, 0x01}; /* T E A 0 1 */ int recog_state, sector; int detected = 0; int probe_result; int sizes[] = { 2048, 512, 1024, 4096, -1 }; int i; /* check the Volume Recognition Area (shared with ISO9660) */ recog_state = 0; for (sector = 16; sector < 64; sector++) { if (get_buffer(section, sector * 2048, 2048, (void **)&buffer) < 2048) return; /* empty ID check (end of sequence) */ if (buffer[2] == buffer[1] && buffer[3] == buffer[1] && buffer[4] == buffer[1] && buffer[5] == buffer[1]) break; if (recog_state == 0 && memcmp(buffer, sig_bea, 7) == 0) recog_state = 1; if (recog_state == 1 && memcmp(buffer, sig_tea, 7) == 0) recog_state = 0; if (recog_state == 1 && (memcmp(buffer, sig_nsr2, 7) == 0 || memcmp(buffer, sig_nsr3, 7) == 0)) { detected = 1; break; } } if (!detected) return; /* We now know we should look for an actual UDF file system */ /* The UDF anchor descriptor resides at sector 256 (and some other places). Unfortunately, the sector size may vary, and it isn't recorded anywhere. The base standard allows any multiple of 512 bytes, but the various UDF standards restrict this. For now, we check the common sizes 512, 1K, 2K, and 4K, and give up else. */ for (i = 0; sizes[i] > 0; i++) { probe_result = probe_udf(section, level, sizes[i]); if (probe_result > 0) return; } /* We couldn't find the actual file system, but the stuff found in the recognition area is worth reporting anyway */ print_line(level, "UDF recognition sequence, unable to locate anchor descriptor"); } static int probe_udf(SECTION *section, int level, int sector_size) { unsigned char *buffer; u4 count, addr, sect; int seen_primary = 0; int seen_logical = 0; int i; char s[256]; /* first read the Anchor Volume Descriptor Pointer @ sector 256 */ if (get_buffer(section, 256 * sector_size, 512, (void **)&buffer) < 512) return 0; if (!validate_tag(buffer, 256)) return 0; /* tag identifier */ if (get_le_short(buffer) != 2) return 0; print_line(level, "UDF file system"); print_line(level + 1, "Sector size %d bytes", sector_size); /* get the Volume Descriptor Area */ count = get_le_long(buffer + 16) / sector_size; addr = get_le_long(buffer + 20); /* look for a Logical Volume Descriptor */ for (i = 0; i < count; i++) { sect = addr + i; if (get_buffer(section, (u8)sect * sector_size, 512, (void **)&buffer) < 512) break; if (!validate_tag(buffer, sect)) continue; /* switch by tag identifier */ switch (get_le_short(buffer)) { case 1: /* Primary Volume Descriptor */ if (!seen_primary) { seen_primary = 1; if (buffer[24] == 8) { get_string(buffer + 25, 30, s); print_line(level+1, "Volume name \"%s\"", s); } else if (buffer[24] == 16) { format_utf16_le(buffer + 25, 30, s); print_line(level+1, "Volume name \"%s\"", s); } else { print_line(level+1, "Volume name encoding not supported"); } } break; case 6: /* Logical Volume Descriptor */ if (!seen_logical) { seen_logical = 1; if (memcmp(buffer + 216+1, "*OSTA UDF Compliant", 19) == 0) { print_line(level+1, "UDF version %x.%02x", (int)buffer[216+25], (int)buffer[216+24]); } } break; } } if (!seen_primary) { print_line(level + 1, "Primary Volume Descriptor missing"); } return 1; /* some problems */ } static int validate_tag(unsigned char *buf, u4 sector) { int cksum, i; /* tag checksum */ cksum = 0; for (i = 0; i < 16; i++) if (i != 4) cksum += buf[i]; if ((cksum & 0xFF) != buf[4]) return 0; /* reserverd */ if (buf[5] != 0) return 0; /* tag location */ if (get_le_long(buf + 12) != sector) return 0; return 1; } /* EOF */ disktype-9/unix.c0000664000076500007650000004075207774247441015055 0ustar chrispchrisp00000000000000/* * unix.c * Detection of general Unix file systems * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * JFS (for Linux) */ void detect_jfs(SECTION *section, int level) { unsigned char *buf; int version; char s[256]; u4 blocksize; u8 blockcount; if (get_buffer(section, 32768, 512, (void **)&buf) < 512) return; /* check signature */ if (memcmp(buf, "JFS1", 4) != 0) return; /* tell the user */ version = get_le_long(buf + 4); print_line(level, "JFS file system, version %d", version); get_string(buf + 101, 11, s); print_line(level + 1, "Volume name \"%s\"", s); blocksize = get_le_long(buf + 24); blockcount = get_le_quad(buf + 8); format_blocky_size(s, blockcount, blocksize, "h/w blocks", NULL); print_line(level + 1, "Volume size %s", s); } /* * XFS */ void detect_xfs(SECTION *section, int level) { unsigned char *buf; u4 raw_version, blocksize; u8 blockcount; int version; char s[256]; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; /* check signature */ if (get_be_long(buf) != 0x58465342) return; /* tell the user */ raw_version = get_be_short(buf + 0x64); version = raw_version & 0x000f; print_line(level, "XFS file system, version %d", version); get_string(buf + 0x6c, 12, s); print_line(level + 1, "Volume name \"%s\"", s); format_uuid(buf + 32, s); print_line(level + 1, "UUID %s", s); blocksize = get_be_long(buf + 4); blockcount = get_be_quad(buf + 8); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); } /* * UFS file system from various BSD strains */ void detect_ufs(SECTION *section, int level) { unsigned char *buf; int i, at, en, namelen, offsets[5] = { 0, 8, 64, 256, -1 }; u4 magic; char s[256]; /* NextStep/OpenStep apparently can move the superblock further into the device. Linux uses steps of 8 blocks (of the applicable block size) to scan for it. We only scan at the canonical location for now. */ /* Possible block sizes: 512 (old formats), 1024 (most), 2048 (CD media) */ for (i = 0; offsets[i] >= 0; i++) { at = offsets[i]; if (get_buffer(section, at * 1024, 1536, (void **)&buf) < 1536) break; for (en = 0; en < 2; en++) { magic = get_ve_long(en, buf + 1372); if (magic == 0x00011954) { print_line(level, "UFS file system, %d KiB offset, %s", at, get_ve_name(en)); } else if (magic == 0x00095014) { print_line(level, "UFS file system, %d KiB offset, long file names, %s", at, get_ve_name(en)); } else if (magic == 0x00195612) { print_line(level, "UFS file system, %d KiB offset, fs_featurebits, %s", at, get_ve_name(en)); } else if (magic == 0x05231994) { print_line(level, "UFS file system, %d KiB offset, fs_featurebits, >4GB support, %s", at, get_ve_name(en)); } else if (magic == 0x19540119) { print_line(level, "UFS2 file system, %d KiB offset, %s", at, get_ve_name(en)); } else continue; /* volume name by FreeBSD convention */ get_string(buf + 680, 32, s); if (s[0]) print_line(level + 1, "Volume name \"%s\" (in superblock)", s); /* last mount point */ get_string(buf + 212, 255, s); /* actually longer, but varies */ if (s[0]) print_line(level + 1, "Last mounted at \"%s\"", s); /* volume name by Darwin convention */ if (get_buffer(section, 7 * 1024, 1024, (void **)&buf) == 1024) { if (get_ve_long(en, buf) == 0x4c41424c && /* "LABL" */ get_ve_long(en, buf + 8) == 1) { /* version 1 */ namelen = get_ve_short(en, buf + 16); get_string(buf + 18, namelen, s); /* automatically limits to 255 */ print_line(level + 1, "Volume name \"%s\" (in label v%lu)", s, get_ve_long(en, buf + 8)); } } return; } } } /* * System V file system */ void detect_sysv(SECTION *section, int level) { unsigned char *buf; int i, at, en, offsets[5] = { 512, 1024, -1 }; s4 blocksize_code; char s[256]; for (i = 0; offsets[i] >= 0; i++) { at = offsets[i]; if (get_buffer(section, at, 1024, (void **)&buf) < 1024) break; for (en = 0; en < 2; en++) { if (get_ve_long(en, buf + 1016) == 0x2b5544) { blocksize_code = get_ve_long(en, buf + 1020); s[0] = 0; if (blocksize_code == 1) strcpy(s, "512 byte blocks"); else if (blocksize_code == 2) strcpy(s, "1 KiB blocks"); else if (blocksize_code == 3) strcpy(s, "2 KiB blocks"); else snprintf(s, 255, "unknown block size code %d", (int)blocksize_code); print_line(level, "XENIX file system (SysV variant), %s, %s", get_ve_name(en), s); return; } if (get_ve_long(en, buf + 504) == 0xfd187e20) { blocksize_code = get_ve_long(en, buf + 508); s[0] = 0; if (blocksize_code == 1) strcpy(s, "512 byte blocks"); else if (blocksize_code == 2) strcpy(s, "1 KiB blocks"); else snprintf(s, 255, "unknown block size code %d", (int)blocksize_code); print_line(level, "SysV file system, %s, %s", get_ve_name(en), s); return; } } } } /* * BSD disklabel */ static char * bsdtype_names[] = { "Unused", "swap", "Sixth Edition", "Seventh Edition", "System V", "V7 with 1 KiB blocks", "Eighth Edition, 4 KiB blocks", "4.2BSD fast file system", "ext2 or MS-DOS", "4.4BSD log-structured file system", "\"Other\"", "HPFS", "ISO9660", "bootstrap", "AmigaDOS fast file system", "Macintosh HFS", "Digital Unix AdvFS", }; static char * get_name_for_bsdtype(int type) { if (type >= 0 && type <= 16) return bsdtype_names[type]; return "Unknown"; } void detect_bsd_disklabel(SECTION *section, int level) { unsigned char *buf; int i, off, partcount, types[16], min_offset_valid, did_recurse; u4 starts[16], sizes[16]; u4 sectsize, nsectors, ntracks, ncylinders, secpercyl, secperunit; u8 offset, min_offset, base_offset; char s[256], append[64], pn; if (section->flags & FLAG_IN_DISKLABEL) return; if (get_buffer(section, 512, 512, (void **)&buf) < 512) return; if (get_le_long(buf) != 0x82564557 || get_le_long(buf + 132) != 0x82564557) return; sectsize = get_le_long(buf + 40); nsectors = get_le_long(buf + 44); ntracks = get_le_long(buf + 48); ncylinders = get_le_long(buf + 52); secpercyl = get_le_long(buf + 56); secperunit = get_le_long(buf + 60); partcount = get_le_short(buf + 138); if (partcount <= 8) { print_line(level, "BSD disklabel (at sector 1), %d partitions", partcount); } else if (partcount > 8 && partcount <= 16) { print_line(level, "BSD disklabel (at sector 1), %d partitions (more than usual, but valid)", partcount); } else if (partcount > 16) { print_line(level, "BSD disklabel (at sector 1), %d partitions (broken, limiting to 16)", partcount); partcount = 16; } if (sectsize != 512) { print_line(level + 1, "Unusual sector size %d bytes, your mileage may vary"); } min_offset = 0; min_offset_valid = 0; for (i = 0, off = 148; i < partcount; i++, off += 16) { starts[i] = get_le_long(buf + off + 4); sizes[i] = get_le_long(buf + off); types[i] = buf[off + 12]; if (types[i] != 0 || i == 2) { offset = (u8)starts[i] * 512; if (!min_offset_valid || offset < min_offset) { min_offset = offset; min_offset_valid = 1; } } } /* if min_offset_valid is still 0, the default of min_offset=0 is okay */ if (section->pos == min_offset) { /* either min_offset is zero, or we were analyzing the whole disk */ base_offset = section->pos; } else if (section->pos == 0) { /* are we analyzing the slice alone? */ print_line(level + 1, "Adjusting offsets for disklabel in a DOS partition at sector %llu", min_offset >> 9); base_offset = min_offset; } else if (min_offset == 0) { /* assume relative offsets after all */ base_offset = 0; } else { print_line(level + 1, "Warning: Unable to adjust offsets, your mileage may vary"); base_offset = section->pos; } /* loop over partitions: print and analyze */ did_recurse = 0; for (i = 0; i < partcount; i++) { pn = 'a' + i; if (types[i] == 0 && i != 2) continue; sprintf(append, " from %lu", starts[i]); format_blocky_size(s, sizes[i], 512, "sectors", append); print_line(level, "Partition %c: %s", pn, s); print_line(level + 1, "Type %d (%s)", types[i], get_name_for_bsdtype(types[i])); if (types[i] == 0 || sizes[i] == 0) continue; offset = (u8)starts[i] * 512; if (offset < base_offset) { print_line(level + 1, "(Illegal start offset, no detection)"); } else if (offset == base_offset) { print_line(level + 1, "Includes the disklabel and boot code"); /* recurse for content detection, but carefully */ analyze_recursive(section, level + 1, offset - base_offset, (u8)sizes[i] * 512, FLAG_IN_DISKLABEL); did_recurse = 1; } else { /* recurse for content detection */ analyze_recursive(section, level + 1, offset - base_offset, (u8)sizes[i] * 512, 0); } } if (did_recurse) stop_detect(); /* don't run other detectors; we already did that for an overlapping partition. */ } /* * FreeBSD boot loader (?) */ void detect_bsd_loader(SECTION *section, int level) { unsigned char *buf; if (section->flags & FLAG_IN_DISKLABEL) return; if (get_buffer(section, 0, 512, (void **)&buf) == 512) { if (get_le_short(buf + 0x1b0) == 0xbb66) { print_line(level, "FreeBSD boot manager (i386 boot0 at sector 0)"); } else if (get_le_long(buf + 0x1f6) == 0 && get_le_long(buf + 0x1fa) == 50000 && get_le_short(buf + 0x1fe) == 0xaa55) { print_line(level, "FreeBSD boot loader (i386 boot1 at sector 0)"); } } if (get_buffer(section, 1024, 512, (void **)&buf) == 512) { if (memcmp(buf + 2, "BTX", 3) == 0) { print_line(level, "FreeBSD boot loader (i386 boot2/BTX %d.%02d at sector 2)", (int)buf[5], (int)buf[6]); } } } /* * Solaris SPARC disklabel */ void detect_solaris_disklabel(SECTION *section, int level) { unsigned char *buf; int i, off1, off2, types[8], did_recurse; u4 sizes[8]; u8 starts[8], cylsize, offset; char s[256], append[256], pn; if (section->flags & FLAG_IN_DISKLABEL) return; if (get_buffer(section, 0, 512, (void **)&buf) < 512) return; if (get_be_short(buf + 508) != 0xDABE) return; print_line(level, "Solaris SPARC disklabel"); cylsize = (u8)get_be_short(buf + 436) * (u8)get_be_short(buf + 438); for (i = 0, off1 = 142, off2 = 444; i < 8; i++, off1 += 4, off2 += 8) { types[i] = get_be_short(buf + off1); starts[i] = get_be_long(buf + off2) * cylsize; sizes[i] = get_be_long(buf + off2 + 4); } /* loop over partitions: print and analyze */ did_recurse = 0; for (i = 0; i < 8; i++) { pn = '0' + i; if (sizes[i] == 0) continue; sprintf(append, " from %llu", starts[i]); format_blocky_size(s, sizes[i], 512, "sectors", append); print_line(level, "Partition %c: %s", pn, s); print_line(level + 1, "Type %d", types[i]); offset = starts[i] * 512; if (offset == 0) { print_line(level + 1, "Includes the disklabel"); /* recurse for content detection, but carefully */ analyze_recursive(section, level + 1, offset, (u8)sizes[i] * 512, FLAG_IN_DISKLABEL); did_recurse = 1; } else { /* recurse for content detection */ analyze_recursive(section, level + 1, offset, (u8)sizes[i] * 512, 0); } } if (did_recurse) stop_detect(); /* don't run other detectors; we already did that for the first partition, which overlaps with the disklabel itself. */ } /* * Solaris x86 vtoc */ static char * vtoctype_names[] = { "Unused", "Boot", "Root", "Swap", "Usr", "Overlap", "Stand", "Var", "Home", "Alternate sector", "Cache" }; static char * get_name_for_vtoctype(int type) { if (type >= 0 && type <= 10) return vtoctype_names[type]; return "Unknown"; } void detect_solaris_vtoc(SECTION *section, int level) { unsigned char *buf; int i, off, partcount, sectorsize, types[16], did_recurse; u4 starts[16], sizes[16]; u4 version; u8 offset; char s[256], append[64]; if (section->flags & FLAG_IN_DISKLABEL) return; if (get_buffer(section, 512, 512, (void **)&buf) < 512) return; if (get_le_long(buf + 12) != 0x600DDEEE) return; version = get_le_long(buf + 16); if (version != 1) { print_line(level, "Solaris x86 disklabel, unknown version %lu", version); return; } partcount = get_le_short(buf + 30); if (partcount > 16) { print_line(level, "Solaris x86 disklabel, version 1, %d partitions (limiting to 16)", partcount); partcount = 16; } else { print_line(level, "Solaris x86 disklabel, version 1, %d partitions", partcount); } sectorsize = get_le_short(buf + 28); if (sectorsize != 512) print_line(level + 1, "Unusual sector size %d bytes, your mileage may vary", sectorsize); get_string(buf + 20, 8, s); if (s[0]) print_line(level + 1, "Volume name \"%s\"", s); for (i = 0, off = 72; i < partcount; i++, off += 12) { types[i] = get_le_short(buf + off); starts[i] = get_le_long(buf + off + 4); sizes[i] = get_le_long(buf + off + 8); } /* loop over partitions: print and analyze */ did_recurse = 0; for (i = 0; i < partcount; i++) { if (sizes[i] == 0) continue; sprintf(append, " from %lu", starts[i]); format_blocky_size(s, sizes[i], 512, "sectors", append); print_line(level, "Partition %d: %s", i, s); print_line(level + 1, "Type %d (%s)", types[i], get_name_for_vtoctype(types[i])); offset = (u8)starts[i] * 512; if (offset == 0) { print_line(level + 1, "Includes the disklabel"); /* recurse for content detection, but carefully */ analyze_recursive(section, level + 1, offset, (u8)sizes[i] * 512, FLAG_IN_DISKLABEL); did_recurse = 1; } else { /* recurse for content detection */ analyze_recursive(section, level + 1, offset, (u8)sizes[i] * 512, 0); } } if (did_recurse) stop_detect(); /* don't run other detectors; we already did that for an overlapping partition. */ } /* * QNX4 file system */ void detect_qnx(SECTION *section, int level) { unsigned char *buf; if (get_buffer(section, 512, 512, (void **)&buf) < 512) return; /* check signature */ if (get_le_long(buf) != 0x0000002f) return; /* NOTE: This is actually the string "/", the file name of the root directory. QNX4 fs does not have a real superblock, just an aggregate of 4 inodes for certain special files. */ /* tell the user */ print_line(level, "QNX4 file system"); } /* * Veritas VxFS */ void detect_vxfs(SECTION *section, int level) { unsigned char *buf; int en, version; u4 blocksize, blockcount; char s[256]; if (get_buffer(section, 1024, 1024, (void **)&buf) < 1024) return; /* check signature */ for (en = 0; en < 2; en++) { if (get_ve_long(en, buf) == 0xA501FCF5) { version = get_ve_long(en, buf + 4); print_line(level, "Veritas VxFS file system, version %d, %s", version, get_ve_name(en)); blocksize = get_ve_long(en, buf + 32); blockcount = get_ve_long(en, buf + 36); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); } } } /* EOF */ disktype-9/vpc.c0000664000076500007650000001744207663726560014663 0ustar chrispchrisp00000000000000/* * vpc.c * Layered data source for Virtual PC hard disk images. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "global.h" /* * types */ typedef struct vhd_chunk { int present; u8 off; u1 bitmap[1]; } VHD_CHUNK; typedef struct vhd_source { SOURCE c; u8 off; u4 chunk_size; u4 chunk_count; u4 *raw_map; VHD_CHUNK **chunks; } VHD_SOURCE; /* * helper functions */ static SOURCE *init_vhd_source(SECTION *section, int level, u8 total_size, u8 sparse_offset); static int read_block_vhd(SOURCE *s, u8 pos, void *buf); static void close_vhd(SOURCE *s); /* * cd image detection */ void detect_vhd(SECTION *section, int level) { unsigned char *buf; int found, type; u8 sparse_offset, total_size; char s[256]; SOURCE *src; found = 0; /* check for info block at the beginning */ if (get_buffer(section, 0, 511, (void **)&buf) < 511) return; if (memcmp(buf, "conectix", 8) == 0) { found = 1; } /* check for info block at the end if possible */ if (!found && section->size > 1024 && !section->source->sequential) { if (get_buffer(section, section->size - 511, 511, (void **)&buf) < 511) return; if (memcmp(buf, "conectix", 8) == 0) { found = 1; } } if (!found) return; /* okay, now buf points to the info block, wherever it was found */ type = get_be_long(buf + 0x3c); total_size = get_be_quad(buf + 0x28); /* copy at 0x30 ... ??? */ if (type == 2) { print_line(level, "Connectix Virtual PC hard disk image, fixed size"); } else if (type == 3) { print_line(level, "Connectix Virtual PC hard disk image, dynamic size"); } else if (type == 4) { print_line(level, "Connectix Virtual PC hard disk image, differential"); } else { print_line(level, "Connectix Virtual PC hard disk image, unknown type %d", type); } format_size_verbose(s, total_size); print_line(level + 1, "Disk size %s", s); if (type == 3) { /* dynamically sized, set up a mapping data source */ sparse_offset = get_be_quad(buf + 16); src = init_vhd_source(section, level, total_size, sparse_offset); if (src != NULL) { /* analyze it */ analyze_source(src, level); close_source(src); } } if (type == 3 || type == 4) stop_detect(); } /* * initialize the mapping source */ static SOURCE *init_vhd_source(SECTION *section, int level, u8 total_size, u8 sparse_offset) { VHD_SOURCE *vs; unsigned char *buf; u8 map_offset; u4 map_size; char s[256]; /* allocate and init source structure */ vs = (VHD_SOURCE *)malloc(sizeof(VHD_SOURCE)); if (vs == NULL) bailout("Out of memory"); memset(vs, 0, sizeof(VHD_SOURCE)); vs->c.size_known = 1; vs->c.size = total_size; vs->c.blocksize = 512; vs->c.foundation = section->source; vs->c.read_block = read_block_vhd; vs->c.close = close_vhd; vs->off = section->pos; /* read sparse information block */ if (get_buffer(section, sparse_offset, 512, (void **)&buf) < 512) { print_line(level + 1, "Error reading the sparse image info block"); goto errorexit; } map_offset = get_be_quad(buf + 16); vs->chunk_count = get_be_long(buf + 28); vs->chunk_size = get_be_long(buf + 32); format_size(s, vs->chunk_size); print_line(level + 1, "Dynamic sizing uses %lu chunks of %s", vs->chunk_count, s); if ((u8)vs->chunk_count * vs->chunk_size < total_size) { print_line(level + 1, "Error: Sparse parameters don't match total size"); goto errorexit; } if (vs->chunk_size < 4096) { print_line(level + 1, "Error: Sparse chunk size too small (%lu bytes)", vs->chunk_size); goto errorexit; } if (vs->chunk_size > 2*1024*1024) { /* written-to bitmap wouldn't fit in one sector */ print_line(level + 1, "Error: Sparse chunk size too large (%lu bytes)", vs->chunk_size); goto errorexit; } /* allocate further data structures */ map_size = vs->chunk_count * 4; vs->raw_map = (u4 *)malloc(map_size); if (vs->raw_map == NULL) bailout("Out of memory"); vs->chunks = (VHD_CHUNK **)malloc(vs->chunk_count * sizeof(VHD_CHUNK *)); if (vs->chunks == NULL) bailout("Out of memory"); memset(vs->chunks, 0, vs->chunk_count * sizeof(VHD_CHUNK *)); /* read the chunk map */ if (get_buffer_real(section->source, vs->off + map_offset, map_size, (void *)vs->raw_map, NULL) < map_size) { print_line(level + 1, "Error reading the sparse image map"); goto errorexit; } return (SOURCE *)vs; errorexit: close_vhd((SOURCE *)vs); free(vs); return NULL; } /* * mapping read */ static int read_block_vhd(SOURCE *s, u8 pos, void *buf) { VHD_SOURCE *vs = (VHD_SOURCE *)s; SOURCE *fs = s->foundation; u4 chunk, chunk_start_sector, sector; u8 chunk_disk_off, sector_pos; unsigned char *filebuf; int present; chunk = (u4)(pos / vs->chunk_size); if (chunk >= vs->chunk_count) return 0; if (vs->chunks[chunk] == NULL) { /* create data structure for the chunk */ chunk_start_sector = get_be_long(vs->raw_map + chunk); /* NOTE: raw_map is a u4*, so C does the arithmetics for us */ if (chunk_start_sector == 0xffffffff) { present = 0; } else { chunk_disk_off = vs->off + (u8)chunk_start_sector * 512; if (get_buffer_real(fs, chunk_disk_off, 512, NULL, (void **)&filebuf) < 512) present = 0; else present = 1; } if (!present) { vs->chunks[chunk] = (VHD_CHUNK *)malloc(sizeof(VHD_CHUNK)); if (vs->chunks[chunk] == NULL) bailout("Out of memory"); vs->chunks[chunk]->present = 0; } else { vs->chunks[chunk] = (VHD_CHUNK *)malloc(sizeof(VHD_CHUNK) + 512); if (vs->chunks[chunk] == NULL) bailout("Out of memory"); vs->chunks[chunk]->present = 1; vs->chunks[chunk]->off = chunk_disk_off + 512; memcpy(vs->chunks[chunk]->bitmap, filebuf, 512); } } if (!vs->chunks[chunk]->present) { /* whole chunk is missing */ memset(buf, 0, 512); return 1; } sector = (u4)((pos - (u8)chunk * vs->chunk_size) / 512); if (vs->chunks[chunk]->bitmap[sector >> 3] & (128 >> (sector & 7))) { /* sector is present and in use */ sector_pos = vs->chunks[chunk]->off + (u8)sector * 512; if (get_buffer_real(fs, sector_pos, 512, buf, NULL) < 512) return 0; } else { /* sector has not been written to (although it's present on disk) */ memset(buf, 0, 512); } return 1; } /* * cleanup */ static void close_vhd(SOURCE *s) { VHD_SOURCE *vs = (VHD_SOURCE *)s; u4 chunk; /* free raw chunk map */ if (vs->raw_map != NULL) free(vs->raw_map); /* free chunk info data */ if (vs->chunks != NULL) { for (chunk = 0; chunk < vs->chunk_count; chunk++) { if (vs->chunks[chunk] != NULL) free(vs->chunks[chunk]); } free(vs->chunks); } } /* EOF */