⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isofs.c

📁 LINUX 下, 以 QT/KDE 写的档案管理员
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************
                 	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 + -