/* $Id: iso9660.c,v 1.1.1.1 2009/02/21 21:25:18 khorben Exp $ */ /* * ISO filesystem by (suzanne) vega. * driven by tomato luv. */ #include #include #include #include #include "plugin.h" /* types */ /* some structure and macros were stolen from NetBSD includes */ #define ISODCL(from, to) (to - from + 1) #pragma pack(1) struct iso_volume_descriptor { u_char type[ISODCL(1,1)]; /* 711 */ char id[ISODCL(2,6)]; char version[ISODCL(7,7)]; char data[ISODCL(8,2048)]; }; #pragma pack() /* volume descriptor types */ #define ISO_VD_BOOTSECT 0 #define ISO_VD_PRIMARY 1 #define ISO_VD_SUPPLEMENTARY 2 #define ISO_VD_PARTITION 3 #define ISO_VD_END 255 #define ISO_STANDARD_ID "CD001" #define ISO_ECMA_ID "CDW01" #define ISO_EMPTY "" struct iso_primary_descriptor { char type [ISODCL ( 1, 1)]; /* 711 */ char id [ISODCL ( 2, 6)]; char version [ISODCL ( 7, 7)]; /* 711 */ char unused1 [ISODCL ( 8, 8)]; char system_id [ISODCL ( 9, 40)]; /* achars */ char volume_id [ISODCL ( 41, 72)]; /* dchars */ char unused2 [ISODCL ( 73, 80)]; char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ char unused3 [ISODCL ( 89, 120)]; char volume_set_size [ISODCL (121, 124)]; /* 723 */ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ char logical_block_size [ISODCL (129, 132)]; /* 723 */ char path_table_size [ISODCL (133, 140)]; /* 733 */ char type_l_path_table [ISODCL (141, 144)]; /* 731 */ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ char type_m_path_table [ISODCL (149, 152)]; /* 732 */ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ char volume_set_id [ISODCL (191, 318)]; /* dchars */ char publisher_id [ISODCL (319, 446)]; /* achars */ char preparer_id [ISODCL (447, 574)]; /* achars */ char application_id [ISODCL (575, 702)]; /* achars */ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ char file_structure_version [ISODCL (882, 882)]; /* 711 */ char unused4 [ISODCL (883, 883)]; char application_data [ISODCL (884, 1395)]; char unused5 [ISODCL (1396, 2048)]; }; #define ISO_DEFAULT_BLOCK_SIZE 2048 struct iso_supplementary_descriptor { char type [ISODCL ( 1, 1)]; /* 711 */ char id [ISODCL ( 2, 6)]; char version [ISODCL ( 7, 7)]; /* 711 */ char flags [ISODCL ( 8, 8)]; /* 711? */ char system_id [ISODCL ( 9, 40)]; /* achars */ char volume_id [ISODCL ( 41, 72)]; /* dchars */ char unused2 [ISODCL ( 73, 80)]; char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ char escape [ISODCL ( 89, 120)]; char volume_set_size [ISODCL (121, 124)]; /* 723 */ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ char logical_block_size [ISODCL (129, 132)]; /* 723 */ char path_table_size [ISODCL (133, 140)]; /* 733 */ char type_l_path_table [ISODCL (141, 144)]; /* 731 */ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ char type_m_path_table [ISODCL (149, 152)]; /* 732 */ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ char volume_set_id [ISODCL (191, 318)]; /* dchars */ char publisher_id [ISODCL (319, 446)]; /* achars */ char preparer_id [ISODCL (447, 574)]; /* achars */ char application_id [ISODCL (575, 702)]; /* achars */ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ char file_structure_version [ISODCL (882, 882)]; /* 711 */ char unused4 [ISODCL (883, 883)]; char application_data [ISODCL (884, 1395)]; char unused5 [ISODCL (1396, 2048)]; }; /* variables */ static char a_char_lazy[] = " !\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; static char a_char_strict[] = " !\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_"; static char d_char_lazy[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static char d_char_strict[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; typedef enum typechar { TYPE_LAZY_A_CHARS, TYPE_LAZY_D_CHARS, TYPE_STRICT_A_CHARS, TYPE_STRICT_D_CHARS } ctype_t; static __inline int isonum_711(u_char *) __attribute__ ((unused)); /* 7.1.1: unsigned char */ static __inline int isonum_711(u_char *p) { return *p; } /* 7.2.3: unsigned both-endian (little, then big) 16-bit value */ static __inline uint16_t isonum_723(u_char *p) { #if defined(UNALIGNED_ACCESS) && \ ((BYTE_ORDER == LITTLE_ENDIAN) || (BYTE_ORDER == BIG_ENDIAN)) #if BYTE_ORDER == LITTLE_ENDIAN return *(uint16_t *)p; #else return *(uint16_t *)(p + 2); #endif #else /* !UNALIGNED_ACCESS or weird byte order */ return *p|(p[1] << 8); #endif } /* 7.3.3: unsigned both-endian (little, then big) 32-bit value */ static __inline uint32_t isonum_733(u_char *p) { #if defined(UNALIGNED_ACCESS) && \ ((BYTE_ORDER == LITTLE_ENDIAN) || (BYTE_ORDER == BIG_ENDIAN)) #if BYTE_ORDER == LITTLE_ENDIAN return *(uint32_t *)p; #else return *(uint32_t *)(p + 4); #endif #else /* !UNALIGNED_ACCESS or weird byte order */ return *p|(p[1] << 8)|(p[2] << 16)|(p[3] << 24); #endif } /* signatures */ static unsigned char sig1[] = ISO_STANDARD_ID; static unsigned char sig2[] = ISO_ECMA_ID; static unsigned char sig3[] = ISO_EMPTY; /* plugin */ static PluginMagic iso9660_magic[] = { { (2*sizeof(struct iso_volume_descriptor)), 0, sig1, sizeof(sig1)-1 }, { (2*sizeof(struct iso_volume_descriptor)), 0, sig2, sizeof(sig2)-1 }, { 0, 0, NULL, 0 } }; static int iso9660_callback(PluginHelper * ph, int signature, FILE * fp); Plugin plugin = { PT_ARCHIVE | PT_EXECUTABLE, "ISO9660", iso9660_magic, iso9660_callback }; #define ISO_FLAGS_VDBOOT 0x00000001 #define ISO_FLAGS_VDPRIM 0x00000002 #define ISO_FLAGS_VDSUPP 0x00000004 #define ISO_FLAGS_VDPART 0x00000010 #define ISO_FLAGS_VDEND 0x00000020 /* plugin_callback */ int _plugin_check_isovdprimary(struct iso_primary_descriptor * i ); static int iso9660_callback(PluginHelper * ph, int signature, FILE * fp) { fpos_t pos; int rc = 0, score = 0; int iso_flag = 0x00000000; char buffer[2048]; struct iso_volume_descriptor * isovd; struct iso_primary_descriptor * isopri; fpos_t fpos; //ph->printf(ph, "callback called!\n"); //fprintf(stderr,"prout prout prout we are in plugin callback!!!\n"); //fprintf(stderr, "isovd: %d isopri: %d\n", sizeof(struct iso_volume_descriptor), sizeof(struct iso_primary_descriptor)); reread: memset(buffer, 0, sizeof(buffer)); //while ( !feof(fp) ) { //rc = fread((void *)buffer, sizeof(struct iso_volume_descriptor), 1, fp); rc = fread((void *)buffer, sizeof(char), 2048, fp); //rc = read(fileno(fp), buffer, sizeof(struct iso_volume_descriptor)); //fprintf(stderr, "fread() rc: %d\n", rc); /* cast type */ isovd = (struct iso_volume_descriptor *) buffer; isopri = (struct iso_primary_descriptor *) buffer; fgetpos(fp, &fpos); //fprintf(stderr, "sizeof(): %u\n", sizeof(fpos_t)); //fprintf(stderr, "fread(@%08x) rc: %d bytes (isovd sz: %d bytes)\n", (int)fpos, rc, sizeof(struct iso_volume_descriptor)); /* if (fpos == 0x8000) { fprintf(stderr, "BUFFER[0]: %02x\n",buffer[0]); fprintf(stderr, "BUFFER[1]: %02x\n",buffer[1]); fprintf(stderr, "BUFFER[2]: %02x\n",buffer[2]); fprintf(stderr, "BUFFER[3]: %02x\n",buffer[3]); fprintf(stderr, "BUFFER[4]: %02x\n",buffer[4]); } */ if ((rc*sizeof(struct iso_volume_descriptor)) < sizeof(struct iso_volume_descriptor)) return score; switch (isonum_711(isovd->type)) { case ISO_VD_BOOTSECT: //fprintf(stderr, "VD BOOT!\n"); iso_flag |= ISO_FLAGS_VDBOOT; break; case ISO_VD_PRIMARY: fprintf(stderr, "VD PRIM!\n"); iso_flag |= ISO_FLAGS_VDPRIM; //fprintf(stderr, "file structure version: %d\n", isonum_711(isopri->file_structure_version)); rc = _plugin_check_isovdprimary(isopri); //fprintf(stderr, "plugin_check_rc: %d\n", rc); fgetpos(fp, &fpos); #ifdef DEBUG fprintf(stderr, "rc: %d fread(@%08x)\n", rc, (int)fpos); #endif if (rc < 0) return -1; else score += rc; #ifdef DEBUG fprintf(stderr, "flag: %08x type: %02x\n", iso_flag, isonum_711(isovd->type)); fprintf(stderr, "BUFFER[0]: %02x\n",buffer[0]); fprintf(stderr, "BUFFER[1]: %02x\n",buffer[1]); fprintf(stderr, "BUFFER[2]: %02x\n",buffer[2]); fprintf(stderr, "BUFFER[3]: %02x\n",buffer[3]); fprintf(stderr, "BUFFER[4]: %02x\n",buffer[4]); #endif score += 10; goto reread; break; case ISO_VD_SUPPLEMENTARY: #ifdef DEBUG fprintf(stderr, "VD SUP!\n"); #endif iso_flag |= ISO_FLAGS_VDSUPP; if (iso_flag & ISO_FLAGS_VDPRIM) score += 10; break; case ISO_VD_PARTITION: iso_flag |= ISO_FLAGS_VDPART; if (iso_flag & ISO_FLAGS_VDPRIM) score += 10; break; case ISO_VD_END: iso_flag |= ISO_FLAGS_VDEND; score += 10; if (iso_flag & ISO_FLAGS_VDPRIM) score += 30; return score; break; default: return -1; } memset(buffer, 0, sizeof(buffer)); //} /* printf("pos: %d\n", pos); pos = 0; printf("callback @ %d\n", pos); */ return -1; } /* * add PluginHelper for printf() functions control (verbosity) */ int _plugin_check_isXchar(ctype_t type, char * buf, size_t buflen) { char * ptr = NULL; size_t rc = 0; /* fprintf(stderr, "buf: '%s' buflen: %d bytes\n", buf, buflen); fprintf(stderr, "buf[8]: %02x\n", buf[8]); */ if (buflen > 0) { ptr = (char *) calloc (buflen+1, sizeof(char)); if (!ptr) return -1; memcpy(ptr, buf, buflen); switch (type) { case TYPE_LAZY_A_CHARS: rc = strspn(ptr, a_char_lazy); break; case TYPE_LAZY_D_CHARS: rc = strspn(ptr, d_char_lazy); break; case TYPE_STRICT_A_CHARS: rc = strspn(ptr, a_char_strict); break; case TYPE_STRICT_D_CHARS: rc = strspn(ptr, d_char_strict); break; } if (rc == buflen) { free(ptr); return rc; } } free(ptr); return 0; } /* * return 1 if STANDARD ID * return 2 if ECMA ID * return -1 otherwise * TODO: simplify */ int _plugin_check_isisoid(char * buf, size_t buflen) { int score = 0; char * id_standard = ISO_STANDARD_ID; char * id_ecma = ISO_ECMA_ID; /* test standard id */ if ( memcmp(buf, id_standard, buflen) == 0x0 ) { score += 15; return score; } /* test ecma id */ if ( memcmp(buf, id_ecma, buflen) == 0x0 ) { score += 10; return score; } return score; } /* * lame, very lame and simple ISO9660 primary * volume descriptor conformance check, more later... * * max score is 55 */ int _plugin_check_isovdprimary(struct iso_primary_descriptor * i ) { int score = 0; size_t j; int rc; rc = _plugin_check_isisoid(i->id, sizeof(i->id)); if (rc > 0) score += rc; else return -1; /* isprint(first check system ID) - a_chars */ rc = _plugin_check_isXchar(TYPE_LAZY_A_CHARS, i->system_id, sizeof(i->system_id)); if (rc > 0) score += 10; /* isprint(then check volume ID) - d_chars */ rc = _plugin_check_isXchar(TYPE_LAZY_D_CHARS, i->volume_id, sizeof(i->volume_id)); if (rc > 0) score += 10; /* isprint(then check file structure version) */ if (i->unused1 != '\0') return 0; rc = 0; for (j = 0, rc = 0 ; j < sizeof(i->unused2) ; j++) { if (i->unused2[j] == '\0') rc++; } if (rc < (signed)sizeof(i->unused2)) return -1; score += 10; rc = 0; for (j = 0, rc = 0 ; j < sizeof(i->unused3) ; j++) { if (i->unused3[j] == '\0') rc++; } if (rc < (signed)sizeof(i->unused3)) return -1; score += 10; return score; }