1
/***************************************************************************
6
copyright : (C) 2002 by Szombathelyi Gy�gy
7
email : gyurco@users.sourceforge.net
8
***************************************************************************/
10
/***************************************************************************
12
* This program is free software; you can redistribute it and/or modify *
13
* it under the terms of the GNU General Public License as published by *
14
* the Free Software Foundation; either version 2 of the License, or *
15
* (at your option) any later version. *
17
***************************************************************************/
26
/**************************************************************/
29
/* internal function from the linux kernel (isofs fs) */
30
static time_t getisotime(int year,int month,int day,int hour,
31
int minute,int second,int tz) {
41
int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
46
for (i = 1; i < month; i++)
48
if (((year+2) % 4) == 0 && month > 2)
51
crtime = ((((days * 24) + hour) * 60 + minute) * 60)
59
* The timezone offset is unreliable on some disks,
60
* so we make a sanity check. In no case is it ever
61
* more than 13 hours from GMT, which is 52*15min.
62
* The time is always stored in localtime with the
63
* timezone offset being what get added to GMT to
64
* get to localtime. Thus we need to subtract the offset
65
* to get to true GMT, which is what we store the time
66
* as internally. On the local system, the user may set
67
* their timezone any way they wish, of course, so GMT
68
* gets converted back to localtime on the receiving
71
* NOTE: mkisofs in versions prior to mkisofs-1.10 had
72
* the sign wrong on the timezone offset. This has now
73
* been corrected there too, but if you are getting screwy
74
* results this may be the explanation. If enough people
75
* complain, a user configuration option could be added
76
* to add the timezone offset in with the wrong sign
77
* for 'compatibility' with older discs, but I cannot see how
78
* it will matter that much.
80
* Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
81
* for pointing out the sign error.
83
if (-52 <= tz && tz <= 52)
84
crtime -= tz * 15 * 60;
91
* Returns the Unix from the ISO9660 9.1.5 time format
93
time_t isodate_915(char * p, int hs) {
95
return getisotime(1900+p[0],p[1],p[2],p[3],p[4],p[5],hs==0 ? p[6] : 0);
99
* Returns the Unix from the ISO9660 8.4.26.1 time format
100
* BUG: hundredth of seconds are ignored, because Unix time_t has one second
101
* resolution (I think it's no problem at all)
103
time_t isodate_84261(char * p, int hs) {
104
int year,month,day,hour,minute,second;
105
year=(p[0]-'0')*1000 + (p[1]-'0')*100 + (p[2]-'0')*10 + p[3]-'0';
106
month=(p[4]-'0')*10 + (p[5]-'0');
107
day=(p[6]-'0')*10 + (p[7]-'0');
108
hour=(p[8]-'0')*10 + (p[9]-'0');
109
minute=(p[10]-'0')*10 + (p[11]-'0');
110
second=(p[12]-'0')*10 + (p[13]-'0');
111
return getisotime(year,month,day,hour,minute,second,hs==0 ? p[16] : 0);
114
void FreeBootTable(boot_head *boot) {
115
boot_entry *be,*next;
126
long long BootImageSize(int media,unsigned int len) {
129
switch(media & 0xf) {
131
ret=len; /* No emulation */
134
ret=80*2*15; /* 1.2 MB */
137
ret=80*2*18; /* 1.44 MB */
140
ret=80*2*36; /* 2.88 MB */
144
ret=len; /* Hard Disk */
152
static boot_entry *CreateBootEntry(char *be) {
155
entry = (boot_entry*) malloc(sizeof(boot_entry));
156
if (!entry) return NULL;
157
memset(entry, 0, sizeof(boot_entry));
158
memcpy(entry->data,be,0x20);
162
int ReadBootTable(readfunc *read,unsigned int sector, boot_head *head, void *udata) {
164
char buf[2048], *c, *be;
167
boot_entry *defcur=NULL,*deflast=NULL;
168
register struct validation_entry *ventry=NULL;
174
if ( read(be, sector, 1, udata) != 1 ) goto err;
176
/* first entry needs to be a validation entry */
178
ventry=(struct validation_entry *) be;
179
if ( isonum_711(ventry->type) !=1 ) goto err;
182
for (i=0;i<16;i++) { sum += isonum_721(c); c+=2; }
184
memcpy(&head->ventry,be,0x20);
188
while (!end && (be < (char *)(&buf+1))) {
189
switch (isonum_711(be)) {
191
defcur=CreateBootEntry(be);
192
if (!defcur) goto err;
194
deflast->next=defcur;
196
head->defentry=defcur;
197
defcur->prev=deflast;
223
* Creates the linked list of the volume descriptors
225
iso_vol_desc *ReadISO9660(readfunc *read,unsigned int sector,void *udata) {
228
struct iso_volume_descriptor buf;
229
iso_vol_desc *first=NULL,*current=NULL,*prev=NULL;
231
for (i=0;i<100;i++) {
232
if (read( (char*) &buf, sector+i+16, 1, udata) != 1 ) {
236
if (!memcmp(ISO_STANDARD_ID,&buf.id,5)) {
237
switch ( isonum_711(&buf.type[0]) ) {
241
case ISO_VD_SUPPLEMENTARY:
242
current=(iso_vol_desc*) malloc(sizeof(iso_vol_desc));
249
if (prev) prev->next=current;
250
memcpy(&(current->data),&buf,2048);
251
if (!first) first=current;
259
} else if (!memcmp(HS_STANDARD_ID,(struct hs_volume_descriptor*) &buf,5)) {
260
/* High Sierra format not supported (yet) */
268
* Frees the linked list of volume descriptors
270
void FreeISO9660(iso_vol_desc *data) {
272
iso_vol_desc *current;
283
* Frees the strings in 'rrentry'
285
void FreeRR(rr_entry *rrentry) {
296
static int str_nappend(char **d,char *s,int n) {
300
/* i=strnlen(s,n)+1; */
301
while (i<n && s[i]) i++;
303
if (*d) i+=(strlen(*d)+1);
305
if (!c) return -ENOMEM;
318
static int str_append(char **d,char *s) {
323
if (*d) i+=(strlen(*d)+1);
325
if (!c) return -ENOMEM;
337
#define rrtlen(c) (((unsigned char) c & 0x80) ? 17 : 7)
338
#define rrctime(f,c) ((unsigned char) f & 0x80) ? isodate_84261(c,0) : isodate_915(c,0)
340
* Parses the System Use area and fills rr_entry with values
342
int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry) {
344
int suspoffs,susplen,i,f,ret=0;
346
struct rock_ridge *rr;
348
suspoffs=33+isonum_711(idr->name_len);
349
if (!(isonum_711(idr->name_len) & 1)) suspoffs++;
350
susplen=isonum_711(idr->length)-suspoffs;
351
r= & (((char*) idr)[suspoffs]);
352
rr = (struct rock_ridge*) r;
354
memset(rrentry,0,sizeof(rr_entry));
355
rrentry->len = sizeof(rr_entry);
357
while (susplen > 0) {
358
if (isonum_711(&rr->len) > susplen || rr->len == 0) break;
359
if (rr->signature[0]=='N' && rr->signature[1]=='M') {
360
if (!(rr->u.NM.flags & 0x26) && rr->len>5 && !rrentry->name) {
362
if (str_nappend(&rrentry->name,rr->u.NM.name,isonum_711(&rr->len)-5)) {
363
FreeRR(rrentry); return -ENOMEM;
367
} else if (rr->signature[0]=='P' && rr->signature[1]=='X' &&
368
(isonum_711(&rr->len)==44 || isonum_711(&rr->len)==36)) {
369
rrentry->mode=isonum_733(rr->u.PX.mode);
370
rrentry->nlink=isonum_733(rr->u.PX.n_links);
371
rrentry->uid=isonum_733(rr->u.PX.uid);
372
rrentry->gid=isonum_733(rr->u.PX.gid);
373
if (isonum_711(&rr->len)==44) rrentry->serno=isonum_733(rr->u.PX.serno);
375
} else if (rr->signature[0]=='P' && rr->signature[1]=='N' &&
376
isonum_711(&rr->len)==20) {
377
rrentry->dev_major=isonum_733(rr->u.PN.dev_high);
378
rrentry->dev_minor=isonum_733(rr->u.PN.dev_low);
380
} else if (rr->signature[0]=='P' && rr->signature[1]=='L' &&
381
isonum_711(&rr->len)==12) {
382
rrentry->pl=isonum_733(rr->u.PL.location);
384
} else if (rr->signature[0]=='C' && rr->signature[1]=='L' &&
385
isonum_711(&rr->len)==12) {
386
rrentry->cl=isonum_733(rr->u.CL.location);
388
} else if (rr->signature[0]=='R' && rr->signature[1]=='E' &&
389
isonum_711(&rr->len)==4) {
392
} else if (rr->signature[0]=='S' && rr->signature[1]=='L' &&
393
isonum_711(&rr->len)>7) {
394
i = isonum_711(&rr->len)-5;
400
if (str_append(&rrentry->sl,(char *)".")) {
401
FreeRR(rrentry); return -ENOMEM;
405
if (str_append(&rrentry->sl,(char *)"..")) {
406
FreeRR(rrentry); return -ENOMEM;
410
if ( (c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl &&
411
strlen(rrentry->sl)>1) ) {
412
if (str_append(&rrentry->sl,(char *) DIR_SEPARATOR )) {
413
FreeRR(rrentry); return -ENOMEM;
417
if ((unsigned char)c[1]>0) {
418
if (str_nappend(&rrentry->sl,c+2,(unsigned char)c[1])) {
419
FreeRR(rrentry); return -ENOMEM;
422
i -= ((unsigned char)c[1] + 2);
423
c += ((unsigned char)c[1] + 2);
426
} else if (rr->signature[0]=='T' && rr->signature[1]=='F' &&
427
isonum_711(&rr->len)>5) {
429
i = isonum_711(&rr->len)-5;
434
while (i >= rrtlen(f)) {
436
rrentry->t_creat=rrctime(f,c);
439
rrentry->t_mtime=rrctime(f,c);
442
rrentry->t_atime=rrctime(f,c);
445
rrentry->t_ctime=rrctime(f,c);
448
rrentry->t_backup=rrctime(f,c);
451
rrentry->t_expire=rrctime(f,c);
454
rrentry->t_effect=rrctime(f,c);
463
} else if (rr->signature[0]=='Z' && rr->signature[1]=='F' &&
464
isonum_711(&rr->len)==16) {
465
/* Linux-specific extension: transparent decompression */
466
rrentry->z_algo[0]=rr->u.ZF.algorithm[0];
467
rrentry->z_algo[1]=rr->u.ZF.algorithm[1];
468
rrentry->z_params[0]=rr->u.ZF.parms[0];
469
rrentry->z_params[1]=rr->u.ZF.parms[1];
470
rrentry->z_size=isonum_733(rr->u.ZF.real_size);
473
/* printf("SUSP sign: %c%c\n",rr->signature[0],rr->signature[1]); */
476
susplen -= isonum_711(&rr->len);
477
r += isonum_711(&rr->len);
478
rr = (struct rock_ridge*) r;
485
* Iterates over the directory entries. The directory is in 'buf',
486
* the size of the directory is 'size'. 'callback' is called for each
487
* directory entry with the parameter 'udata'.
489
int ProcessDir(readfunc *read,int extent,int size,dircallback *callback,void *udata) {
493
struct iso_directory_record *idr;
496
siz=((size>>11)+1)<<11;
501
buf=(char*) malloc(siz);
502
if (!buf) return -ENOMEM;
503
if (read(buf,extent,siz>>11,udata)!=siz>>11) {
509
idr=(struct iso_directory_record*) &buf[pos];
510
if (isonum_711(idr->length)==0) {
512
size-=(2048 - (pos & 0x7ff));
516
idr=(struct iso_directory_record*) &buf[pos];
518
pos+=isonum_711(idr->length);
519
pos+=isonum_711(idr->ext_attr_length);
520
size-=isonum_711(idr->length);
521
size-=isonum_711(idr->ext_attr_length);
524
if (isonum_711(idr->length)
526
isonum_711(idr->length)<33+isonum_711(idr->name_len)) {
527
/* Invalid directory entry */
530
if ((ret=callback(idr,udata))) break;
538
* returns the joliet level from the volume descriptor
540
int JolietLevel(struct iso_volume_descriptor *ivd) {
542
register struct iso_supplementary_descriptor *isd;
544
isd = (struct iso_supplementary_descriptor *) ivd;
546
if (isonum_711(ivd->type)==ISO_VD_SUPPLEMENTARY) {
547
if (isd->escape[0]==0x25 &&
548
isd->escape[1]==0x2f) {
550
switch (isd->escape[2]) {
566
/********************************************************************/
573
#include <sys/types.h>
574
#include <sys/stat.h>
577
int level=0,joliet=0,dirs,files;
581
int readf(char *buf, unsigned int start, unsigned int len,void *udata) {
584
if ((ret=lseek64(fd, (long long)start << (long long)11, SEEK_SET))<0) return ret;
585
ret=read(fd, buf, len << 11u);
586
if (ret<0) return ret;
590
void dumpchars(char *c,int len) {
600
for (i=0;i<num*5;i++) { printf(" "); };
603
void dumpflags(char flags) {
604
if (flags & 1) printf("HIDDEN ");
605
if (flags & 2) printf("DIR ");
606
if (flags & 4) printf("ASF ");
609
void dumpjoliet(char *c,int len) {
616
outptr=(char*) &outbuf;
618
if ((iconv(iconv_d,&c,&len,&outptr,&out))<0) {
619
printf("conversion error=%d",errno);
623
dumpchars((char*) &outbuf,ret);
626
void dumpchardesc(char *c,int len) {
635
void dumpiso915time(char *t, int hs) {
640
time=isodate_915(t,hs);
641
c=(char*) ctime(&time);
642
if (c && c[strlen(c)-1]==0x0a) c[strlen(c)-1]=0;
643
if (c) printf("%s",c);
646
void dumpiso84261time(char *t, int hs) {
651
time=isodate_84261(t,hs);
652
c=(char*) ctime(&time);
653
if (c && c[strlen(c)-1]==0x0a) c[strlen(c)-1]=0;
654
if (c) printf("%s",c);
657
void dumpdirrec(struct iso_directory_record *dir) {
659
if (isonum_711(dir->name_len)==1) {
660
switch (dir->name[0]) {
668
printf("%c",dir->name[0]);
672
dumpchardesc(dir->name,isonum_711(dir->name_len));
673
printf(" size=%d",isonum_733(dir->size));
674
printf(" extent=%d ",isonum_733(dir->extent));
675
dumpflags(isonum_711(dir->flags));
676
dumpiso915time((char*) &(dir->date),0);
679
void dumprrentry(rr_entry *rr) {
680
printf(" NM=[%s] uid=%d gid=%d nlink=%d mode=%o ",
681
rr->name,rr->uid,rr->gid,rr->nlink,rr->mode);
682
if (S_ISCHR(rr->mode) || S_ISBLK(rr->mode))
683
printf("major=%d minor=%d ",rr->dev_major,rr->dev_minor);
684
if (rr->mode & S_IFLNK && rr->sl) printf("slink=%s ",rr->sl);
687
if (rr->t_creat) printf("t_creat: %s",ctime(&rr->t_creat));
688
if (rr->st_mtime) printf("st_mtime: %s",ctime(&rr->st_mtime));
689
if (rr->st_atime) printf("st_atime: %s",ctime(&rr->st_atime));
690
if (rr->st_ctime) printf("st_ctime: %s",ctime(&rr->st_ctime));
691
if (rr->t_backup) printf("t_backup: %s",ctime(&rr->t_backup));
692
if (rr->t_expire) printf("t_expire: %s",ctime(&rr->t_expire));
693
if (rr->t_effect) printf("t_effect: %s",ctime(&rr->t_effect));
697
void dumpsusp(char *c, int len) {
701
void dumpboot(struct el_torito_boot_descriptor *ebd) {
702
printf("version: %d\n",isonum_711(ebd->version));
703
printf("system id: ");dumpchars(ebd->system_id,ISODCL(8,39));printf("\n");
704
printf("boot catalog start: %d\n",isonum_731(ebd->boot_catalog));
707
void dumpdefentry(struct default_entry *de) {
708
printf("Default entry: \n");
709
printf(" bootid=%x\n",isonum_711(de->bootid));
710
printf(" media emulation=%d (",isonum_711(de->media));
711
switch(isonum_711(de->media) & 0xf) {
713
printf("No emulation");
716
printf("1.2 Mb floppy");
719
printf("1.44 Mb floppy");
722
printf("2.88 Mb floppy");
728
printf("Unknown/Invalid");
732
printf(" loadseg=%d\n",isonum_721(de->loadseg));
733
printf(" systype=%d\n",isonum_711(de->systype));
734
printf(" start lba=%d count=%d\n",isonum_731(de->start),
735
isonum_721(de->seccount));
738
void dumpbootcat(boot_head *bh) {
741
printf("System id: ");dumpchars(bh->ventry.id,ISODCL(28,5));printf("\n");
744
dumpdefentry(be->data);
749
void dumpdesc(struct iso_primary_descriptor *ipd) {
751
printf("system id: ");dumpchardesc(ipd->system_id,ISODCL(9,40));printf("\n");
752
printf("volume id: ");dumpchardesc(ipd->volume_id,ISODCL(41,72));printf("\n");
753
printf("volume space size: %d\n",isonum_733(ipd->volume_space_size));
754
printf("volume set size: %d\n",isonum_723(ipd->volume_set_size));
755
printf("volume seq num: %d\n",isonum_723(ipd->volume_set_size));
756
printf("logical block size: %d\n",isonum_723(ipd->logical_block_size));
757
printf("path table size: %d\n",isonum_733(ipd->path_table_size));
758
printf("location of type_l path table: %d\n",isonum_731(ipd->type_l_path_table));
759
printf("location of optional type_l path table: %d\n",isonum_731(ipd->opt_type_l_path_table));
760
printf("location of type_m path table: %d\n",isonum_732(ipd->type_m_path_table));
761
printf("location of optional type_m path table: %d\n",isonum_732(ipd->opt_type_m_path_table));
763
printf("Root dir record:\n");dumpdirrec((struct iso_directory_record*) &ipd->root_directory_record);
765
printf("Volume set id: ");dumpchardesc(ipd->volume_set_id,ISODCL(191,318));printf("\n");
766
printf("Publisher id: ");dumpchardesc(ipd->publisher_id,ISODCL(319,446));printf("\n");
767
printf("Preparer id: ");dumpchardesc(ipd->preparer_id,ISODCL(447,574));printf("\n");
768
printf("Application id: ");dumpchardesc(ipd->application_id,ISODCL(575,702));printf("\n");
769
printf("Copyright id: ");dumpchardesc(ipd->copyright_file_id,ISODCL(703,739));printf("\n");
770
printf("Abstract file id: ");dumpchardesc(ipd->abstract_file_id,ISODCL(740,776));printf("\n");
771
printf("Bibliographic file id: ");dumpchardesc(ipd->bibliographic_file_id,ISODCL(777,813));printf("\n");
772
printf("Volume creation date: ");dumpiso84261time(ipd->creation_date,0);printf("\n");
773
printf("Volume modification date: ");dumpiso84261time(ipd->modification_date,0);printf("\n");
774
printf("Volume expiration date: ");dumpiso84261time(ipd->expiration_date,0);printf("\n");
775
printf("Volume effective date: ");dumpiso84261time(ipd->effective_date,0);printf("\n");
776
printf("File structure version: %d\n",isonum_711(ipd->file_structure_version));
779
int mycallb(struct iso_directory_record *idr,void *udata) {
782
sp(level);dumpdirrec(idr);
783
if (level==0) printf(" (Root directory) ");
786
if (ParseRR(idr,&rrentry)>0) {
787
sp(level);printf(" ");dumprrentry(&rrentry);printf("\n");
790
if ( !(idr->flags[0] & 2) ) files++;
791
if ( (idr->flags[0] & 2) && (level==0 || isonum_711(idr->name_len)>1) ) {
794
ProcessDir(&readf,isonum_733(idr->extent),isonum_733(idr->size),&mycallb,udata);
800
/************************************************/
802
int main(int argc, char *argv[]) {
809
fprintf(stderr,"\nUsage: %s iso-file-name or device [starting sector]\n\n",argv[0]);
813
sector=atoi(argv[2]);
814
printf("Using starting sector number %d\n",sector);
816
fd=open(argv[1],O_RDONLY);
818
fprintf(stderr,"open error\n");
821
iconv_d=iconv_open("ISO8859-2","UTF16BE");
823
fprintf(stderr,"iconv open error\n");
827
desc=ReadISO9660(&readf,sector,NULL);
829
printf("No volume descriptors\n");
834
printf("\n\n--------------- Volume descriptor (%d.) type %d: ---------------\n\n",
835
i,isonum_711(desc->data.type));
836
switch (isonum_711(desc->data.type)) {
839
struct el_torito_boot_descriptor* bootdesc;
840
bootdesc=&(desc->data);
842
if ( !memcmp(EL_TORITO_ID,bootdesc->system_id,ISODCL(8,39)) ) {
844
if (ReadBootTable(&readf,isonum_731(bootdesc->boot_catalog),&boot,NULL)) {
845
printf("Boot Catalog Error\n");
848
FreeBootTable(&boot);
855
case ISO_VD_SUPPLEMENTARY:
857
joliet = JolietLevel(&desc->data);
858
printf("Joliet level: %d\n",joliet);
859
dumpdesc((struct iso_primary_descriptor*) &desc->data);
860
printf("\n\n--------------- Directory structure: -------------------\n\n");
862
mycallb( &( ((struct iso_primary_descriptor*) &desc->data)->root_directory_record), NULL );
863
printf("\nnumber of directories: %d\n",dirs);
864
printf("\nnumber of files: %d\n",files);
871
iconv_close(iconv_d);
877
#endif /* ISOFS_MAIN */
1
/*****************************************************************************
2
* Copyright (C) 2002 Szombathelyi György <gyurco@users.sourceforge.net> *
4
* This program is free software; you can redistribute it and/or modify *
5
* it under the terms of the GNU General Public License as published by *
6
* the Free Software Foundation; either version 2 of the License, or *
7
* (at your option) any later version. *
9
* This package is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License for more details. *
14
* You should have received a copy of the GNU General Public License *
15
* along with this package; if not, write to the Free Software *
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
17
*****************************************************************************/
26
/**************************************************************/
29
/* internal function from the linux kernel (isofs fs) */
30
static time_t getisotime(int year, int month, int day, int hour,
31
int minute, int second, int tz)
42
int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
46
days += (year + 1) / 4;
47
for (i = 1; i < month; i++)
49
if (((year + 2) % 4) == 0 && month > 2)
52
crtime = ((((days * 24) + hour) * 60 + minute) * 60)
60
* The timezone offset is unreliable on some disks,
61
* so we make a sanity check. In no case is it ever
62
* more than 13 hours from GMT, which is 52*15min.
63
* The time is always stored in localtime with the
64
* timezone offset being what get added to GMT to
65
* get to localtime. Thus we need to subtract the offset
66
* to get to true GMT, which is what we store the time
67
* as internally. On the local system, the user may set
68
* their timezone any way they wish, of course, so GMT
69
* gets converted back to localtime on the receiving
72
* NOTE: mkisofs in versions prior to mkisofs-1.10 had
73
* the sign wrong on the timezone offset. This has now
74
* been corrected there too, but if you are getting screwy
75
* results this may be the explanation. If enough people
76
* complain, a user configuration option could be added
77
* to add the timezone offset in with the wrong sign
78
* for 'compatibility' with older discs, but I cannot see how
79
* it will matter that much.
81
* Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
82
* for pointing out the sign error.
84
if (-52 <= tz && tz <= 52)
85
crtime -= tz * 15 * 60;
92
* Returns the Unix from the ISO9660 9.1.5 time format
94
time_t isodate_915(char * p, int hs)
97
return getisotime(1900 + p[0], p[1], p[2], p[3], p[4], p[5], hs == 0 ? p[6] : 0);
101
* Returns the Unix from the ISO9660 8.4.26.1 time format
102
* BUG: hundredth of seconds are ignored, because Unix time_t has one second
103
* resolution (I think it's no problem at all)
105
time_t isodate_84261(char * p, int hs)
107
int year, month, day, hour, minute, second;
108
year = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + p[3] - '0';
109
month = (p[4] - '0') * 10 + (p[5] - '0');
110
day = (p[6] - '0') * 10 + (p[7] - '0');
111
hour = (p[8] - '0') * 10 + (p[9] - '0');
112
minute = (p[10] - '0') * 10 + (p[11] - '0');
113
second = (p[12] - '0') * 10 + (p[13] - '0');
114
return getisotime(year, month, day, hour, minute, second, hs == 0 ? p[16] : 0);
117
void FreeBootTable(boot_head *boot)
119
boot_entry *be, *next;
127
boot->defentry = NULL;
130
long long BootImageSize(int media, unsigned int len)
134
switch (media & 0xf) {
136
ret = len; /* No emulation */
139
ret = 80 * 2 * 15; /* 1.2 MB */
142
ret = 80 * 2 * 18; /* 1.44 MB */
145
ret = 80 * 2 * 36; /* 2.88 MB */
149
ret = len; /* Hard Disk */
157
static boot_entry *CreateBootEntry(char *be)
161
entry = (boot_entry*) malloc(sizeof(boot_entry));
162
if (!entry) return NULL;
163
memset(entry, 0, sizeof(boot_entry));
164
memcpy(entry->data, be, 0x20);
168
int ReadBootTable(readfunc *read, unsigned int sector, boot_head *head, void *udata)
171
char buf[2048], *c, *be;
174
boot_entry *defcur = NULL, *deflast = NULL;
175
register struct validation_entry *ventry = NULL;
177
head->sections = NULL;
178
head->defentry = NULL;
181
if (read(be, sector, 1, udata) != 1) goto err;
183
/* first entry needs to be a validation entry */
185
ventry = (struct validation_entry *) be;
186
if (isonum_711(ventry->type) != 1) goto err;
189
for (i = 0;i < 16;i++) {
190
sum += isonum_721(c); c += 2;
193
memcpy(&head->ventry, be, 0x20);
197
while (!end && (be < (char *)(&buf + 1))) {
198
switch (isonum_711(be)) {
200
defcur = CreateBootEntry(be);
201
if (!defcur) goto err;
203
deflast->next = defcur;
205
head->defentry = defcur;
206
defcur->prev = deflast;
232
* Creates the linked list of the volume descriptors
234
iso_vol_desc *ReadISO9660(readfunc *read, unsigned int sector, void *udata)
238
struct iso_volume_descriptor buf;
239
iso_vol_desc *first = NULL, *current = NULL, *prev = NULL;
241
for (i = 0;i < 100;i++) {
242
if (read((char*) &buf, sector + i + 16, 1, udata) != 1) {
246
if (!memcmp(ISO_STANDARD_ID, &buf.id, 5)) {
247
switch (isonum_711(&buf.type[0])) {
251
case ISO_VD_SUPPLEMENTARY:
252
current = (iso_vol_desc*) malloc(sizeof(iso_vol_desc));
257
current->prev = prev;
258
current->next = NULL;
259
if (prev) prev->next = current;
260
memcpy(&(current->data), &buf, 2048);
261
if (!first) first = current;
269
} else if (!memcmp(HS_STANDARD_ID, (struct hs_volume_descriptor*) &buf, 5)) {
270
/* High Sierra format not supported (yet) */
278
* Frees the linked list of volume descriptors
280
void FreeISO9660(iso_vol_desc *data)
283
iso_vol_desc *current;
288
data = current->next;
294
* Frees the strings in 'rrentry'
296
void FreeRR(rr_entry *rrentry)
300
rrentry->name = NULL;
304
rrentry->name = NULL;
308
static int str_nappend(char **d, char *s, int n)
313
/* i=strnlen(s,n)+1; */
314
while (i < n && s[i]) i++;
316
if (*d) i += (strlen(*d) + 1);
317
c = (char*) malloc(i);
318
if (!c) return -ENOMEM;
331
static int str_append(char **d, char *s)
337
if (*d) i += (strlen(*d) + 1);
338
c = (char*) malloc(i);
339
if (!c) return -ENOMEM;
351
#define rrtlen(c) (((unsigned char) c & 0x80) ? 17 : 7)
352
#define rrctime(f,c) ((unsigned char) f & 0x80) ? isodate_84261(c,0) : isodate_915(c,0)
354
* Parses the System Use area and fills rr_entry with values
356
int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry)
359
int suspoffs, susplen, i, f, ret = 0;
361
struct rock_ridge *rr;
363
suspoffs = 33 + isonum_711(idr->name_len);
364
if (!(isonum_711(idr->name_len) & 1)) suspoffs++;
365
susplen = isonum_711(idr->length) - suspoffs;
366
r = & (((char*) idr)[suspoffs]);
367
rr = (struct rock_ridge*) r;
369
memset(rrentry, 0, sizeof(rr_entry));
370
rrentry->len = sizeof(rr_entry);
372
while (susplen > 0) {
373
if (isonum_711(&rr->len) > susplen || rr->len == 0) break;
374
if (rr->signature[0] == 'N' && rr->signature[1] == 'M') {
375
if (!(rr->u.NM.flags & 0x26) && rr->len > 5 && !rrentry->name) {
377
if (str_nappend(&rrentry->name, rr->u.NM.name, isonum_711(&rr->len) - 5)) {
378
FreeRR(rrentry); return -ENOMEM;
382
} else if (rr->signature[0] == 'P' && rr->signature[1] == 'X' &&
383
(isonum_711(&rr->len) == 44 || isonum_711(&rr->len) == 36)) {
384
rrentry->mode = isonum_733(rr->u.PX.mode);
385
rrentry->nlink = isonum_733(rr->u.PX.n_links);
386
rrentry->uid = isonum_733(rr->u.PX.uid);
387
rrentry->gid = isonum_733(rr->u.PX.gid);
388
if (isonum_711(&rr->len) == 44) rrentry->serno = isonum_733(rr->u.PX.serno);
390
} else if (rr->signature[0] == 'P' && rr->signature[1] == 'N' &&
391
isonum_711(&rr->len) == 20) {
392
rrentry->dev_major = isonum_733(rr->u.PN.dev_high);
393
rrentry->dev_minor = isonum_733(rr->u.PN.dev_low);
395
} else if (rr->signature[0] == 'P' && rr->signature[1] == 'L' &&
396
isonum_711(&rr->len) == 12) {
397
rrentry->pl = isonum_733(rr->u.PL.location);
399
} else if (rr->signature[0] == 'C' && rr->signature[1] == 'L' &&
400
isonum_711(&rr->len) == 12) {
401
rrentry->cl = isonum_733(rr->u.CL.location);
403
} else if (rr->signature[0] == 'R' && rr->signature[1] == 'E' &&
404
isonum_711(&rr->len) == 4) {
407
} else if (rr->signature[0] == 'S' && rr->signature[1] == 'L' &&
408
isonum_711(&rr->len) > 7) {
409
i = isonum_711(&rr->len) - 5;
415
if (str_append(&rrentry->sl, (char *)".")) {
416
FreeRR(rrentry); return -ENOMEM;
420
if (str_append(&rrentry->sl, (char *)"..")) {
421
FreeRR(rrentry); return -ENOMEM;
425
if ((c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl &&
426
strlen(rrentry->sl) > 1)) {
427
if (str_append(&rrentry->sl, (char *) DIR_SEPARATOR)) {
428
FreeRR(rrentry); return -ENOMEM;
432
if ((unsigned char)c[1] > 0) {
433
if (str_nappend(&rrentry->sl, c + 2, (unsigned char)c[1])) {
434
FreeRR(rrentry); return -ENOMEM;
437
i -= ((unsigned char)c[1] + 2);
438
c += ((unsigned char)c[1] + 2);
441
} else if (rr->signature[0] == 'T' && rr->signature[1] == 'F' &&
442
isonum_711(&rr->len) > 5) {
444
i = isonum_711(&rr->len) - 5;
449
while (i >= rrtlen(f)) {
451
rrentry->t_creat = rrctime(f, c);
454
rrentry->t_mtime = rrctime(f, c);
457
rrentry->t_atime = rrctime(f, c);
460
rrentry->t_ctime = rrctime(f, c);
463
rrentry->t_backup = rrctime(f, c);
466
rrentry->t_expire = rrctime(f, c);
469
rrentry->t_effect = rrctime(f, c);
478
} else if (rr->signature[0] == 'Z' && rr->signature[1] == 'F' &&
479
isonum_711(&rr->len) == 16) {
480
/* Linux-specific extension: transparent decompression */
481
rrentry->z_algo[0] = rr->u.ZF.algorithm[0];
482
rrentry->z_algo[1] = rr->u.ZF.algorithm[1];
483
rrentry->z_params[0] = rr->u.ZF.parms[0];
484
rrentry->z_params[1] = rr->u.ZF.parms[1];
485
rrentry->z_size = isonum_733(rr->u.ZF.real_size);
488
/* printf("SUSP sign: %c%c\n",rr->signature[0],rr->signature[1]); */
491
susplen -= isonum_711(&rr->len);
492
r += isonum_711(&rr->len);
493
rr = (struct rock_ridge*) r;
500
* Iterates over the directory entries. The directory is in 'buf',
501
* the size of the directory is 'size'. 'callback' is called for each
502
* directory entry with the parameter 'udata'.
504
int ProcessDir(readfunc *read, int extent, int size, dircallback *callback, void *udata)
507
int pos = 0, ret = 0, siz;
509
struct iso_directory_record *idr;
512
siz = ((size >> 11) + 1) << 11;
517
buf = (char*) malloc(siz);
518
if (!buf) return -ENOMEM;
519
if (read(buf, extent, siz >> 11, udata) != siz >> 11) {
525
idr = (struct iso_directory_record*) & buf[pos];
526
if (isonum_711(idr->length) == 0) {
528
size -= (2048 - (pos & 0x7ff));
529
if (size <= 2) break;
532
idr = (struct iso_directory_record*) & buf[pos];
534
pos += isonum_711(idr->length);
535
pos += isonum_711(idr->ext_attr_length);
536
size -= isonum_711(idr->length);
537
size -= isonum_711(idr->ext_attr_length);
540
if (isonum_711(idr->length)
542
isonum_711(idr->length) < 33 + isonum_711(idr->name_len)) {
543
/* Invalid directory entry */
546
if ((ret = callback(idr, udata))) break;
554
* returns the joliet level from the volume descriptor
556
int JolietLevel(struct iso_volume_descriptor *ivd)
559
register struct iso_supplementary_descriptor *isd;
561
isd = (struct iso_supplementary_descriptor *) ivd;
563
if (isonum_711(ivd->type) == ISO_VD_SUPPLEMENTARY) {
564
if (isd->escape[0] == 0x25 &&
565
isd->escape[1] == 0x2f) {
567
switch (isd->escape[2]) {
583
/********************************************************************/
590
#include <sys/types.h>
591
#include <sys/stat.h>
594
int level = 0, joliet = 0, dirs, files;
598
int readf(char *buf, unsigned int start, unsigned int len, void *udata)
602
if ((ret = lseek64(fd, (long long)start << (long long)11, SEEK_SET)) < 0) return ret;
603
ret = read(fd, buf, len << 11u);
604
if (ret < 0) return ret;
608
void dumpchars(char *c, int len)
620
for (i = 0;i < num*5;i++) {
625
void dumpflags(char flags)
627
if (flags & 1) printf("HIDDEN ");
628
if (flags & 2) printf("DIR ");
629
if (flags & 4) printf("ASF ");
632
void dumpjoliet(char *c, int len)
640
outptr = (char*) & outbuf;
642
if ((iconv(iconv_d, &c, &len, &outptr, &out)) < 0) {
643
printf("conversion error=%d", errno);
647
dumpchars((char*) &outbuf, ret);
650
void dumpchardesc(char *c, int len)
660
void dumpiso915time(char *t, int hs)
666
time = isodate_915(t, hs);
667
c = (char*) ctime(&time);
668
if (c && c[strlen(c)-1] == 0x0a) c[strlen(c)-1] = 0;
669
if (c) printf("%s", c);
672
void dumpiso84261time(char *t, int hs)
678
time = isodate_84261(t, hs);
679
c = (char*) ctime(&time);
680
if (c && c[strlen(c)-1] == 0x0a) c[strlen(c)-1] = 0;
681
if (c) printf("%s", c);
684
void dumpdirrec(struct iso_directory_record *dir)
687
if (isonum_711(dir->name_len) == 1) {
688
switch (dir->name[0]) {
696
printf("%c", dir->name[0]);
700
dumpchardesc(dir->name, isonum_711(dir->name_len));
701
printf(" size=%d", isonum_733(dir->size));
702
printf(" extent=%d ", isonum_733(dir->extent));
703
dumpflags(isonum_711(dir->flags));
704
dumpiso915time((char*) &(dir->date), 0);
707
void dumprrentry(rr_entry *rr)
709
printf(" NM=[%s] uid=%d gid=%d nlink=%d mode=%o ",
710
rr->name, rr->uid, rr->gid, rr->nlink, rr->mode);
711
if (S_ISCHR(rr->mode) || S_ISBLK(rr->mode))
712
printf("major=%d minor=%d ", rr->dev_major, rr->dev_minor);
713
if (rr->mode & S_IFLNK && rr->sl) printf("slink=%s ", rr->sl);
716
if (rr->t_creat) printf("t_creat: %s",ctime(&rr->t_creat));
717
if (rr->st_mtime) printf("st_mtime: %s",ctime(&rr->st_mtime));
718
if (rr->st_atime) printf("st_atime: %s",ctime(&rr->st_atime));
719
if (rr->st_ctime) printf("st_ctime: %s",ctime(&rr->st_ctime));
720
if (rr->t_backup) printf("t_backup: %s",ctime(&rr->t_backup));
721
if (rr->t_expire) printf("t_expire: %s",ctime(&rr->t_expire));
722
if (rr->t_effect) printf("t_effect: %s",ctime(&rr->t_effect));
726
void dumpsusp(char *c, int len)
731
void dumpboot(struct el_torito_boot_descriptor *ebd)
733
printf("version: %d\n", isonum_711(ebd->version));
734
printf("system id: ");dumpchars(ebd->system_id, ISODCL(8, 39));printf("\n");
735
printf("boot catalog start: %d\n", isonum_731(ebd->boot_catalog));
738
void dumpdefentry(struct default_entry *de)
740
printf("Default entry: \n");
741
printf(" bootid=%x\n", isonum_711(de->bootid));
742
printf(" media emulation=%d (", isonum_711(de->media));
743
switch (isonum_711(de->media) & 0xf) {
745
printf("No emulation");
748
printf("1.2 Mb floppy");
751
printf("1.44 Mb floppy");
754
printf("2.88 Mb floppy");
760
printf("Unknown/Invalid");
764
printf(" loadseg=%d\n", isonum_721(de->loadseg));
765
printf(" systype=%d\n", isonum_711(de->systype));
766
printf(" start lba=%d count=%d\n", isonum_731(de->start),
767
isonum_721(de->seccount));
770
void dumpbootcat(boot_head *bh)
774
printf("System id: ");dumpchars(bh->ventry.id, ISODCL(28, 5));printf("\n");
777
dumpdefentry(be->data);
782
void dumpdesc(struct iso_primary_descriptor *ipd)
785
printf("system id: ");dumpchardesc(ipd->system_id, ISODCL(9, 40));printf("\n");
786
printf("volume id: ");dumpchardesc(ipd->volume_id, ISODCL(41, 72));printf("\n");
787
printf("volume space size: %d\n", isonum_733(ipd->volume_space_size));
788
printf("volume set size: %d\n", isonum_723(ipd->volume_set_size));
789
printf("volume seq num: %d\n", isonum_723(ipd->volume_set_size));
790
printf("logical block size: %d\n", isonum_723(ipd->logical_block_size));
791
printf("path table size: %d\n", isonum_733(ipd->path_table_size));
792
printf("location of type_l path table: %d\n", isonum_731(ipd->type_l_path_table));
793
printf("location of optional type_l path table: %d\n", isonum_731(ipd->opt_type_l_path_table));
794
printf("location of type_m path table: %d\n", isonum_732(ipd->type_m_path_table));
795
printf("location of optional type_m path table: %d\n", isonum_732(ipd->opt_type_m_path_table));
797
printf("Root dir record:\n");dumpdirrec((struct iso_directory_record*) &ipd->root_directory_record);
799
printf("Volume set id: ");dumpchardesc(ipd->volume_set_id, ISODCL(191, 318));printf("\n");
800
printf("Publisher id: ");dumpchardesc(ipd->publisher_id, ISODCL(319, 446));printf("\n");
801
printf("Preparer id: ");dumpchardesc(ipd->preparer_id, ISODCL(447, 574));printf("\n");
802
printf("Application id: ");dumpchardesc(ipd->application_id, ISODCL(575, 702));printf("\n");
803
printf("Copyright id: ");dumpchardesc(ipd->copyright_file_id, ISODCL(703, 739));printf("\n");
804
printf("Abstract file id: ");dumpchardesc(ipd->abstract_file_id, ISODCL(740, 776));printf("\n");
805
printf("Bibliographic file id: ");dumpchardesc(ipd->bibliographic_file_id, ISODCL(777, 813));printf("\n");
806
printf("Volume creation date: ");dumpiso84261time(ipd->creation_date, 0);printf("\n");
807
printf("Volume modification date: ");dumpiso84261time(ipd->modification_date, 0);printf("\n");
808
printf("Volume expiration date: ");dumpiso84261time(ipd->expiration_date, 0);printf("\n");
809
printf("Volume effective date: ");dumpiso84261time(ipd->effective_date, 0);printf("\n");
810
printf("File structure version: %d\n", isonum_711(ipd->file_structure_version));
813
int mycallb(struct iso_directory_record *idr, void *udata)
817
sp(level);dumpdirrec(idr);
818
if (level == 0) printf(" (Root directory) ");
821
if (ParseRR(idr, &rrentry) > 0) {
822
sp(level);printf(" ");dumprrentry(&rrentry);printf("\n");
825
if (!(idr->flags[0] & 2)) files++;
826
if ((idr->flags[0] & 2) && (level == 0 || isonum_711(idr->name_len) > 1)) {
829
ProcessDir(&readf, isonum_733(idr->extent), isonum_733(idr->size), &mycallb, udata);
835
/************************************************/
837
int main(int argc, char *argv[])
840
int i = 1, sector = 0;
845
fprintf(stderr, "\nUsage: %s iso-file-name or device [starting sector]\n\n", argv[0]);
849
sector = atoi(argv[2]);
850
printf("Using starting sector number %d\n", sector);
852
fd = open(argv[1], O_RDONLY);
854
fprintf(stderr, "open error\n");
857
iconv_d = iconv_open("ISO8859-2", "UTF16BE");
859
fprintf(stderr, "iconv open error\n");
863
desc = ReadISO9660(&readf, sector, NULL);
865
printf("No volume descriptors\n");
870
printf("\n\n--------------- Volume descriptor (%d.) type %d: ---------------\n\n",
871
i, isonum_711(desc->data.type));
872
switch (isonum_711(desc->data.type)) {
875
struct el_torito_boot_descriptor* bootdesc;
876
bootdesc = &(desc->data);
878
if (!memcmp(EL_TORITO_ID, bootdesc->system_id, ISODCL(8, 39))) {
880
if (ReadBootTable(&readf, isonum_731(bootdesc->boot_catalog), &boot, NULL)) {
881
printf("Boot Catalog Error\n");
884
FreeBootTable(&boot);
891
case ISO_VD_SUPPLEMENTARY:
893
joliet = JolietLevel(&desc->data);
894
printf("Joliet level: %d\n", joliet);
895
dumpdesc((struct iso_primary_descriptor*) &desc->data);
896
printf("\n\n--------------- Directory structure: -------------------\n\n");
898
mycallb(&(((struct iso_primary_descriptor*) &desc->data)->root_directory_record), NULL);
899
printf("\nnumber of directories: %d\n", dirs);
900
printf("\nnumber of files: %d\n", files);
907
iconv_close(iconv_d);
913
#endif /* ISOFS_MAIN */