/* liso.c (list ISO) yamamori@kt.rim.or.jp */ #include #include #include "iso9660.h" /* iso9660.h from mkisofs-1.12 source */ #define get711(p) ((*(p))&0xff) #define get721(p) (get711(p)|(get711((p)+1)<<8)) #define get731(p) (get721(p)|(get721((p)+2)<<16)) #define get723(p) get721(p) #define get733(p) get731(p) static char buf[2048]; #define VD ((struct iso_primary_descriptor *)buf) #define EL ((struct eltorito_boot_descriptor *)buf) #define DR ((struct iso_directory_record *)buf) #define TZ(t) ((t)/4*100+((t)%4)*15) static struct rockridge { int RR, PX, NM, TF, SL; char *NM_name; int NM_size; unsigned int PX_mode, PX_link, PX_uid, PX_gid; int TF_ftime, TF_mtime, TF_atime, TF_ctime; char SL_name[256]; } rr; static char * ldate(char *p) { static char s[32]; sprintf(s, "%.2s/%.2s/%.4s %.2s:%.2s:%.2s.%.2s %+05d", &p[4], &p[6], &p[0], &p[8], &p[10], &p[12], &p[14], TZ(p[16])); return s; } static char * sdate(char *p) { static char s[32]; sprintf(s, "%02d/%02d/%04d %02d:%02d:%02d %+05d", p[1], p[2], p[0]+1900, p[3], p[4], p[5], TZ(p[6])); return s; } static void u_to_a(char *s, int n) { int i; if (n <= 1) {return;} for (i = 0; i < n/2; i++) { if (s[i*2] != 0 || (s[i] = s[i*2+1]) < 0) {s[i] = '?';} } s[i] = '\0'; } static void print_name(int n, char *s) { printf("%-15.*s", (s[0] <= 1)? s[0] + 1: n, (s[0] == 0)? ".": (s[0] == 1)? "..": s); } static void set_rockridge(int out) { int c, t; memset(&rr, 0, sizeof rr); for (c = DR->name - buf + DR->name_len[0], c += (c & 1); c + 4 < DR->length[0]; c += get711(&buf[c+2])) { if (out) {printf("%c%c ", buf[c], buf[c+1]);} switch ((buf[c]<<16)|(buf[c+1]<<8)|buf[c+3]) { case ('N'<<16)|('M'<<8)|1: rr.NM = c; rr.NM_name = &buf[rr.NM+5]; rr.NM_size = get711(&buf[c+2])-5; break; case ('P'<<16)|('X'<<8)|1: rr.PX = c; rr.PX_mode = get733(&buf[c+4]); rr.PX_link = get733(&buf[c+12]); rr.PX_uid = get733(&buf[c+20]); rr.PX_gid = get733(&buf[c+28]); break; case ('T'<<16)|('F'<<8)|1: rr.TF = c; t = c + 5; if (buf[c+4] & 1) {rr.TF_ftime = t; t += 7;} if (buf[c+4] & 2) {rr.TF_mtime = t; t += 7;} if (buf[c+4] & 4) {rr.TF_atime = t; t += 7;} if (buf[c+4] & 8) {rr.TF_ctime = t;} break; case ('S'<<16)|('L'<<8)|1: rr.SL = c; rr.SL_name[0] = '\0'; for (t = c + 5; t < c + get711(&buf[c+2]); t += get711(&buf[t+1])+2) { if (rr.SL_name[0] && rr.SL_name[strlen(rr.SL_name)-1] != '/') {strcat(rr.SL_name, "/");} switch (buf[t] & ~1) { case 0: strncat(rr.SL_name, &buf[t+2], get711(&buf[t+1])); break; case 2: strcat(rr.SL_name, "."); break; case 4: strcat(rr.SL_name, ".."); break; case 8: strcat(rr.SL_name, "/"); break; } } break; } } } static void list_dir(int cur, int size, int root, int joliet) { int len, pt; static char path[1024]; if (root) { printf(joliet? "\n------- Joliet\n": "\n------- ISO 9660 (Rock Ridge)\n"); path[0] = '/'; path[1] = '\0'; } printf("\n%s:\naddr=%08x\n", path, cur); fseek(stdin, cur, SEEK_SET); for (len = 0; len < size;) { if ((buf[0] = getchar()) == 0) {len++; continue;} len += DR->length[0]; fread(buf+1, DR->length[0] - 1, 1, stdin); printf("%08x %08x %02x ", get733(DR->extent)*2048, get733(DR->size), get711(DR->flags)); printf("%s ", sdate(DR->date)); if (joliet) {u_to_a(DR->name, DR->name_len[0]);} print_name(DR->name_len[0], DR->name); set_rockridge(1); if (rr.TF_mtime) {printf("\n%15cmtime=%s", ' ', sdate(&buf[rr.TF_mtime]));} if (rr.NM) {printf(" %.*s", rr.NM_size, rr.NM_name);} if (rr.SL) {printf(" -> %s", rr.SL_name);} if (rr.TF_atime) {printf("\n%15catime=%s", ' ', sdate(&buf[rr.TF_atime]));} if (rr.PX) { printf(" %06o %d %d/%d", rr.PX_mode, rr.PX_link, rr.PX_uid, rr.PX_gid);} if (rr.TF_ctime) {printf("\n%15cctime=%s", ' ', sdate(&buf[rr.TF_ctime]));} if (rr.TF_ftime) {printf("\n%15cftime=%s", ' ', sdate(&buf[rr.TF_ftime]));} putchar('\n'); } pt = strlen(path); if (path[pt-1] != '/') {path[pt++] = '/';} fseek(stdin, cur, SEEK_SET); for (len = 0; len < size;) { if ((buf[0] = getchar()) == 0) {len++; continue;} len += DR->length[0]; fread(buf+1, DR->length[0] - 1, 1, stdin); if (joliet) {u_to_a(DR->name, DR->name_len[0]);} if ((DR->flags[0] & 2) && ((DR->name[0] >= 2) || root)) { set_rockridge(0); if (rr.NM_name) {sprintf(&path[pt], "%.*s", rr.NM_size, rr.NM_name);} else {sprintf(&path[pt], "%.*s", DR->name_len[0], DR->name);} list_dir(get733(DR->extent)*2048, get733(DR->size), 0, joliet); fseek(stdin, cur + len, SEEK_SET); } } } static void print_volume(int joliet) { #define PRI(f, m) printf((f), sizeof VD->m, VD->m) #define PR(f, m) {if (joliet) {u_to_a(VD->m, sizeof VD->m);} PRI((f), m);} printf("---------------- type = %d \"CD001\" ---\n", get711(VD->type)); PR( " system_id = %.*s\n", system_id); PR( " volume_id = %.*s\n", volume_id); PR( " volume_set_id = %.*s\n", volume_set_id); printf(" path_table_size = %08x\n", get733(VD->path_table_size)); printf(" type_l_path_table = %08x\n", get731(VD->type_l_path_table)*2048); PR( " publisher_id = %.*s\n", publisher_id); PR( " preparer_id = %.*s\n", preparer_id); PR( " application_id = %.*s\n", application_id); PR( " copyright_file_id = %.*s\n", copyright_file_id); PR( " abstract_file_id = %.*s\n", abstract_file_id); PR( "bibliographic_file_id = %.*s\n", bibliographic_file_id); printf(" creation_date = %s\n", ldate(VD->creation_date)); printf(" modification_date = %s\n", ldate(VD->modification_date)); printf(" expiration_date = %s\n", ldate(VD->expiration_date)); printf(" effective_date = %s\n\n", ldate(VD->effective_date)); } static void print_el_torito() { printf("---------------- type = %d \"CD001\" ---\n", get711(EL->type)); printf(" system_id = %.*s\n", sizeof EL->system_id, EL->system_id); printf(" bootcat_ptr = %08x\n\n", get731(EL->bootcat_ptr)*2048); } int main(int argc, char **argv) { int cur, iso = 0, jol = 0; if (argc < 2 && isatty(0)) { fprintf(stderr, "Usage: %s filename\n", argv[0]); return 1; } if (argc >= 2 && (freopen(argv[1], "r", stdin) == (FILE *)NULL)) { perror(argv[1]); return 1; } fseek(stdin, (cur = 0x8000), SEEK_SET); for (;; cur += sizeof buf) { fread(buf, sizeof buf, 1, stdin); if (strncmp(VD->id, "CD001", sizeof VD->id)) {fprintf(stderr, "\"CD001\" not found at %#x\n", cur+1); return 1;} switch (get711(VD->type)) { case 1: print_volume(0); iso = cur; continue; case 2: print_volume(1); jol = cur; continue; case 0: print_el_torito(); continue; case 255: break; default: continue; } break; } if (iso) {list_dir((char *)VD->root_directory_record - buf + iso, 34, 1, 0);} if (jol) {list_dir((char *)VD->root_directory_record - buf + jol, 34, 1, 1);} return 0; }