📄 isofs.c
字号:
/***************************************************************************
isofs.c - libisofs
implementation
-------------------
begin : Oct 25 2002
copyright : (C) 2002 by Szombathelyi Gy�gy
email : gyurco@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "isofs.h"
/**************************************************************/
/* internal function from the linux kernel (isofs fs) */
static time_t getisotime(int year,int month,int day,int hour,
int minute,int second,int tz) {
int days, i;
time_t crtime;
year-=1970;
if (year < 0) {
crtime = 0;
} else {
int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
days = year * 365;
if (year > 2)
days += (year+1) / 4;
for (i = 1; i < month; i++)
days += monlen[i-1];
if (((year+2) % 4) == 0 && month > 2)
days++;
days += day - 1;
crtime = ((((days * 24) + hour) * 60 + minute) * 60)
+ second;
/* sign extend */
if (tz & 0x80)
tz |= (-1 << 8);
/*
* The timezone offset is unreliable on some disks,
* so we make a sanity check. In no case is it ever
* more than 13 hours from GMT, which is 52*15min.
* The time is always stored in localtime with the
* timezone offset being what get added to GMT to
* get to localtime. Thus we need to subtract the offset
* to get to true GMT, which is what we store the time
* as internally. On the local system, the user may set
* their timezone any way they wish, of course, so GMT
* gets converted back to localtime on the receiving
* system.
*
* NOTE: mkisofs in versions prior to mkisofs-1.10 had
* the sign wrong on the timezone offset. This has now
* been corrected there too, but if you are getting screwy
* results this may be the explanation. If enough people
* complain, a user configuration option could be added
* to add the timezone offset in with the wrong sign
* for 'compatibility' with older discs, but I cannot see how
* it will matter that much.
*
* Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann)
* for pointing out the sign error.
*/
if (-52 <= tz && tz <= 52)
crtime -= tz * 15 * 60;
}
return crtime;
}
/**
* Returns the Unix from the ISO9660 9.1.5 time format
*/
time_t isodate_915(char * p, int hs) {
return getisotime(1900+p[0],p[1],p[2],p[3],p[4],p[5],hs==0 ? p[6] : 0);
}
/**
* Returns the Unix from the ISO9660 8.4.26.1 time format
* BUG: hundredth of seconds are ignored, because Unix time_t has one second
* resolution (I think it's no problem at all)
*/
time_t isodate_84261(char * p, int hs) {
int year,month,day,hour,minute,second;
year=(p[0]-'0')*1000 + (p[1]-'0')*100 + (p[2]-'0')*10 + p[3]-'0';
month=(p[4]-'0')*10 + (p[5]-'0');
day=(p[6]-'0')*10 + (p[7]-'0');
hour=(p[8]-'0')*10 + (p[9]-'0');
minute=(p[10]-'0')*10 + (p[11]-'0');
second=(p[12]-'0')*10 + (p[13]-'0');
return getisotime(year,month,day,hour,minute,second,hs==0 ? p[16] : 0);
}
void FreeBootTable(boot_head *boot) {
boot_entry *be,*next;
be=boot->defentry;
while (be) {
next=be->next;
free(be);
be=next;
}
boot->defentry=NULL;
}
int BootImageSize(int media,int len) {
int ret;
switch(media & 0xf) {
case 0:
ret=len; /* No emulation */
break;
case 1:
ret=80*2*15; /* 1.2 MB */
break;
case 2:
ret=80*2*18; /* 1.44 MB */
break;
case 3:
ret=80*2*36; /* 2.88 MB */
break;
case 4:
/* FIXME!!! */
ret=len; /* Hard Disk */
break;
default:
ret=len;
}
return ret;
}
static boot_entry *CreateBootEntry(char *be) {
boot_entry *entry;
entry = (boot_entry*) malloc(sizeof(boot_entry));
if (!entry) return NULL;
memset(entry, 0, sizeof(boot_entry));
memcpy(entry->data,be,0x20);
return entry;
}
int ReadBootTable(readfunc *read,int sector, boot_head *head, void *udata) {
char buf[2048], *c, *be;
int i,end=0;
unsigned short sum;
boot_entry *defcur=NULL,*deflast=NULL;
register struct validation_entry *ventry=NULL;
head->sections=NULL;
head->defentry=NULL;
while (1) {
be = (char*) &buf;
if ( read(be, sector, 1, udata) != 1 ) goto err;
/* first entry needs to be a validation entry */
if (!ventry) {
ventry=(struct validation_entry *) be;
if ( isonum_711(ventry->type) !=1 ) goto err;
sum=0;
c = (char*) ventry;
for (i=0;i<16;i++) { sum += isonum_721(c); c+=2; }
if (sum) goto err;
memcpy(&head->ventry,be,0x20);
be += 0x20;
}
while (!end && (be < (char *)(&buf+1))) {
switch (isonum_711(be)) {
case 0x88:
defcur=CreateBootEntry(be);
if (!defcur) goto err;
if (deflast)
deflast->next=defcur;
else
head->defentry=defcur;
defcur->prev=deflast;
deflast=defcur;
break;
case 0x90:
case 0x91:
break;
default:
end=1;
break;
}
be += 0x20;
}
if (end) break;
sector ++;
}
return 0;
err:
FreeBootTable(head);
return -1;
}
/**
* Creates the linked list of the volume descriptors
*/
iso_vol_desc *ReadISO9660(readfunc *read,int sector,void *udata) {
int i;
struct iso_volume_descriptor buf;
iso_vol_desc *first=NULL,*current=NULL,*prev=NULL;
for (i=0;i<100;i++) {
if (read( (char*) &buf, sector+i+16, 1, udata) != 1 ) {
FreeISO9660(first);
return NULL;
}
if (!memcmp(ISO_STANDARD_ID,&buf.id,5)) {
switch ( isonum_711(&buf.type[0]) ) {
case ISO_VD_BOOT:
case ISO_VD_PRIMARY:
case ISO_VD_SUPPLEMENTARY:
current=(iso_vol_desc*) malloc(sizeof(iso_vol_desc));
if (!current) {
FreeISO9660(first);
return NULL;
}
current->prev=prev;
current->next=NULL;
if (prev) prev->next=current;
memcpy(&(current->data),&buf,2048);
if (!first) first=current;
prev=current;
break;
case ISO_VD_END:
return first;
break;
}
} else if (!memcmp(HS_STANDARD_ID,(struct hs_volume_descriptor*) &buf,5)) {
/* High Sierra format not supported (yet) */
}
}
return first;
}
/**
* Frees the linked list of volume descriptors
*/
void FreeISO9660(iso_vol_desc *data) {
iso_vol_desc *current;
while (data) {
current=data;
data=current->next;
free(current);
}
}
/**
* Frees the strings in 'rrentry'
*/
void FreeRR(rr_entry *rrentry) {
if (rrentry->name) {
free(rrentry->name);
rrentry->name=NULL;
}
if (rrentry->sl) {
free(rrentry->sl);
rrentry->name=NULL;
}
}
static int str_nappend(char **d,char *s,int n) {
int i=0;
char *c;
/* i=strnlen(s,n)+1; */
while (i<n && s[i]) i++;
i++;
if (*d) i+=(strlen(*d)+1);
c=(char*) malloc(i);
if (!c) return -ENOMEM;
if (*d) {
strcpy(c,*d);
strncat(c,s,n);
free(*d);
} else
strncpy(c,s,n);
c[i-1]=0;
*d=c;
return 0;
}
static int str_append(char **d,char *s) {
int i;
char *c;
i=strlen(s)+1;
if (*d) i+=(strlen(*d)+1);
c=(char*) malloc(i);
if (!c) return -ENOMEM;
if (*d) {
strcpy(c,*d);
strcat(c,s);
free(*d);
} else
strcpy(c,s);
c[i-1]=0;
*d=c;
return 0;
}
#define rrtlen(c) (((unsigned char) c & 0x80) ? 17 : 7)
#define rrctime(f,c) ((unsigned char) f & 0x80) ? isodate_84261(c,0) : isodate_915(c,0)
/**
* Parses the System Use area and fills rr_entry with values
*/
int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry) {
int suspoffs,susplen,i,f,ret=0;
char *r, *c;
struct rock_ridge *rr;
suspoffs=33+isonum_711(idr->name_len);
if (!(isonum_711(idr->name_len) & 1)) suspoffs++;
susplen=isonum_711(idr->length)-suspoffs;
r= & (((char*) idr)[suspoffs]);
rr = (struct rock_ridge*) r;
memset(rrentry,0,sizeof(rr_entry));
rrentry->len = sizeof(rr_entry);
while (susplen > 0) {
if (isonum_711(&rr->len) > susplen || rr->len == 0) break;
if (rr->signature[0]=='N' && rr->signature[1]=='M') {
if (!(rr->u.NM.flags & 0x26) && rr->len>5 && !rrentry->name) {
if (str_nappend(&rrentry->name,rr->u.NM.name,isonum_711(&rr->len)-5)) {
FreeRR(rrentry); return -ENOMEM;
}
ret++;
}
} else if (rr->signature[0]=='P' && rr->signature[1]=='X' &&
(isonum_711(&rr->len)==44 || isonum_711(&rr->len)==36)) {
rrentry->mode=isonum_733(rr->u.PX.mode);
rrentry->nlink=isonum_733(rr->u.PX.n_links);
rrentry->uid=isonum_733(rr->u.PX.uid);
rrentry->gid=isonum_733(rr->u.PX.gid);
if (isonum_711(&rr->len)==44) rrentry->serno=isonum_733(rr->u.PX.serno);
ret++;
} else if (rr->signature[0]=='P' && rr->signature[1]=='N' &&
isonum_711(&rr->len)==20) {
rrentry->dev_major=isonum_733(rr->u.PN.dev_high);
rrentry->dev_minor=isonum_733(rr->u.PN.dev_low);
ret++;
} else if (rr->signature[0]=='P' && rr->signature[1]=='L' &&
isonum_711(&rr->len)==12) {
rrentry->pl=isonum_733(rr->u.PL.location);
ret++;
} else if (rr->signature[0]=='C' && rr->signature[1]=='L' &&
isonum_711(&rr->len)==12) {
rrentry->cl=isonum_733(rr->u.CL.location);
ret++;
} else if (rr->signature[0]=='R' && rr->signature[1]=='E' &&
isonum_711(&rr->len)==4) {
rrentry->re=1;
ret++;
} else if (rr->signature[0]=='S' && rr->signature[1]=='L' &&
isonum_711(&rr->len)>7) {
i = isonum_711(&rr->len)-5;
c = (char*) rr;
c += 5;
while (i>0) {
switch(c[0] & ~1) {
case 0x2:
if (str_append(&rrentry->sl,(char *)".")) {
FreeRR(rrentry); return -ENOMEM;
}
break;
case 0x4:
if (str_append(&rrentry->sl,(char *)"..")) {
FreeRR(rrentry); return -ENOMEM;
}
break;
}
if ( (c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl &&
strlen(rrentry->sl)>1) ) {
if (str_append(&rrentry->sl,(char *)"/")) {
FreeRR(rrentry); return -ENOMEM;
}
}
if ((unsigned char)c[1]>0) {
if (str_nappend(&rrentry->sl,c+2,(unsigned char)c[1])) {
FreeRR(rrentry); return -ENOMEM;
}
}
i -= ((unsigned char)c[1] + 2);
c += ((unsigned char)c[1] + 2);
}
ret++;
} else if (rr->signature[0]=='T' && rr->signature[1]=='F' &&
isonum_711(&rr->len)>5) {
i = isonum_711(&rr->len)-5;
f = rr->u.TF.flags;
c = (char*) rr;
c += 5;
while (i >= rrtlen(f)) {
if (f & 1) {
rrentry->t_creat=rrctime(f,c);
f &= ~1;
} else if (f & 2) {
rrentry->t_mtime=rrctime(f,c);
f &= ~2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -