📄 multi.c
字号:
/* @(#)multi.c 1.40 00/05/28 joerg */#ifndef lintstatic char sccsid[] = "@(#)multi.c 1.40 00/05/28 joerg";#endif/* * File multi.c - scan existing iso9660 image and merge into * iso9660 filesystem. Used for multisession support. * * Written by Eric Youngdale (1996). * Copyright (c) 1999,2000 J. Schilling * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "config.h"#include <stdxlib.h>#include <unixstd.h>#include <strdefs.h>#include <time.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#ifdef VMS#include <sys/file.h>#include <vms/fabdef.h>#include "vms.h"extern char *strdup(const char *);#endif#include "mkisofs.h"#include "iso9660.h"#ifdef USE_LIBSCHILY#include <standard.h>#include <schily.h>#endif#include <standard.h> /* Needed for scsitransp.h */#include <utypes.h> /* Needed for scsitransp.h */#include <scg/scsitransp.h> /* Needed for scsiprbytes() */#include <ctype.h> /* Needed for printasc() */#ifndef howmany#define howmany(x, y) (((x)+((y)-1))/(y))#endif#ifndef roundup#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))#endif/* * Cannot debug memset() with gdb on Linux, so use fillbytes() *//*#define memset(s, c, n) fillbytes(s, n, c)*/#define TF_CREATE 1#define TF_MODIFY 2#define TF_ACCESS 4#define TF_ATTRIBUTES 8static int isonum_711 __PR((unsigned char *p));static int isonum_721 __PR((unsigned char *p));static int isonum_723 __PR((unsigned char *p));static int isonum_731 __PR((unsigned char *p));static void printasc __PR((char *txt, unsigned char *p, int len));unsigned char *parse_xa __PR((unsigned char *pnt, int *lenp, struct directory_entry *dpnt));static int parse_rr __PR((unsigned char *pnt, int len, struct directory_entry *dpnt));static int check_rr_dates __PR((struct directory_entry *dpnt, struct directory_entry *current, struct stat *statbuf, struct stat *lstatbuf));static void free_directory_entry __PR((struct directory_entry * dirp));static int merge_old_directory_into_tree __PR((struct directory_entry *, struct directory *));static void check_rr_relocation __PR((struct directory_entry * de));#ifdef __STDC__static intisonum_711(unsigned char *p)#elsestatic intisonum_711(p) unsigned char *p;#endif{ return (*p & 0xff);}#ifdef __STDC__static intisonum_721(unsigned char *p)#elsestatic intisonum_721(p) unsigned char *p;#endif{ return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));}#ifdef __STDC__static intisonum_723(unsigned char *p)#elsestatic intisonum_723(p) unsigned char *p;#endif{#if 0 if (p[0] != p[3] || p[1] != p[2]) {#ifdef USE_LIBSCHILY comerrno(EX_BAD, "invalid format 7.2.3 number\n");#else fprintf(stderr, "invalid format 7.2.3 number\n"); exit(1);#endif }#endif return (isonum_721(p));}#ifdef __STDC__static intisonum_731(unsigned char *p)#elsestatic intisonum_731(p) unsigned char *p;#endif{ return ((p[0] & 0xff) | ((p[1] & 0xff) << 8) | ((p[2] & 0xff) << 16) | ((p[3] & 0xff) << 24));}#ifdef __STDC__intisonum_733(unsigned char *p)#elseintisonum_733(p) unsigned char *p;#endif{ return (isonum_731(p));}FILE *in_image = NULL;#ifndef USE_SCG/* * Don't define readsecs if mkisofs is linked with * the SCSI library. * readsecs() will be implemented as SCSI command in this case. * * Use global var in_image directly in readsecs() * the SCSI equivalent will not use a FILE* for I/O. * * The main point of this pointless abstraction is that Solaris won't let * you read 2K sectors from the cdrom driver. The fact that 99.9% of the * discs out there have a 2K sectorsize doesn't seem to matter that much. * Anyways, this allows the use of a scsi-generics type of interface on * Solaris. */#ifdef __STDC__static intreadsecs(int startsecno, void *buffer, int sectorcount)#elsestatic intreadsecs(startsecno, buffer, sectorcount) int startsecno; void *buffer; int sectorcount;#endif{ int f = fileno(in_image); if (lseek(f, (off_t) startsecno * SECTOR_SIZE, 0) == (off_t) - 1) {#ifdef USE_LIBSCHILY comerr(" Seek error on old image\n");#else fprintf(stderr, " Seek error on old image\n"); exit(10);#endif } if (read(f, buffer, (sectorcount * SECTOR_SIZE)) != (sectorcount * SECTOR_SIZE)) {#ifdef USE_LIBSCHILY comerr(" Read error on old image\n");#else fprintf(stderr, " Read error on old image\n"); exit(10);#endif } return sectorcount * SECTOR_SIZE;}#endifstatic voidprintasc(txt, p, len) char *txt; unsigned char *p; int len;{ int i; error("%s ", txt); for (i=0; i < len; i++) { if (isprint(p[i])) error("%c", p[i]); else error("."); } error("\n");}unsigned char *parse_xa(pnt, lenp, dpnt) unsigned char *pnt; int *lenp; struct directory_entry *dpnt;{ struct iso_xa_dir_record *xadp; int len = *lenp;static int did_xa = 0;/*error("len: %d\n", len);*/ if (len >= 14) { xadp = (struct iso_xa_dir_record *)pnt;/* if (dpnt) scsiprbytes("XA ", pnt, len);*/ if (xadp->signature[0] == 'X' && xadp->signature[1] == 'A' && xadp->reserved[0] == '\0') { len -= 14; pnt += 14; *lenp = len; if (!did_xa) { did_xa = 1; errmsgno(EX_BAD, "Found XA directory extension record.\n"); } } else if (pnt[2] == 0) { char *cp = NULL; if (dpnt) cp = (char *)&dpnt->isorec; if (cp) { scsiprbytes("ISOREC:", (Uchar *)cp, 33+cp[32]); printasc("ISOREC:", (Uchar *)cp, 33+cp[32]); scsiprbytes("XA REC:", pnt, len); printasc("XA REC:", pnt, len); } no_rr =1; *lenp = 0; if (cp) { errmsgno(EX_BAD, "Problems with old ISO directory entry for file: '%s'.\n", &cp[33]); } errmsgno(EX_BAD, "Illegal extended directory attributes found (bad XA disk?).\n");/* errmsgno(EX_BAD, "Disabling Rock Ridge for old session.\n");*/ comerrno(EX_BAD, "Try again using the -no-rr option.\n"); } } if (len >= 4 && pnt[3] != 1 && pnt[3] != 2) { scsiprbytes("BAD RR ATTRIBUTES:", pnt, len); printasc("BAD RR ATTRIBUTES:", pnt, len); } return (pnt);}/* * Parse the RR attributes so we can find the file name. */static intparse_rr(pnt, len, dpnt) unsigned char *pnt; int len; struct directory_entry *dpnt;{ int cont_extent; int cont_offset; int cont_size; char name_buf[256]; cont_extent = cont_offset = cont_size = 0; pnt = parse_xa(pnt, &len, dpnt /*0*/); while (len >= 4) { if (pnt[3] != 1 && pnt[3] != 2) {#ifdef USE_LIBSCHILY errmsgno(EX_BAD, "**BAD RRVERSION (%d) for %c%c\n", pnt[3], pnt[0], pnt[1]);#else fprintf(stderr, "**BAD RRVERSION (%d) for %c%c\n", pnt[3], pnt[0], pnt[1]);#endif return -1; }; if (strncmp((char *) pnt, "NM", 2) == 0) { strncpy(name_buf, (char *) pnt + 5, pnt[2] - 5); name_buf[pnt[2] - 5] = 0; dpnt->name = strdup(name_buf); dpnt->got_rr_name = 1; return 0; } if (strncmp((char *) pnt, "CE", 2) == 0) { cont_extent = isonum_733(pnt + 4); cont_offset = isonum_733(pnt + 12); cont_size = isonum_733(pnt + 20); }; len -= pnt[2]; pnt += pnt[2]; if (len <= 3 && cont_extent) { unsigned char sector[SECTOR_SIZE]; readsecs(cont_extent, sector, 1); if (parse_rr(§or[cont_offset], cont_size, dpnt) == -1) return (-1); }; }; /* Fall back to the iso name if no RR name found */ if (dpnt->name == NULL) { char *cp; strcpy(name_buf, dpnt->isorec.name); cp = strchr(name_buf, ';'); if (cp != NULL) { *cp = '\0'; } dpnt->name = strdup(name_buf); } return 0;}/* parse_rr *//* * Returns 1 if the two files are identical * Returns 0 if the two files differ */static intcheck_rr_dates(dpnt, current, statbuf, lstatbuf) struct directory_entry *dpnt; struct directory_entry *current; struct stat *statbuf; struct stat *lstatbuf;{ int cont_extent; int cont_offset; int cont_size; int offset; unsigned char *pnt; int len; int same_file; int same_file_type; mode_t mode; char time_buf[7]; cont_extent = cont_offset = cont_size = 0; same_file = 1; same_file_type = 1; pnt = dpnt->rr_attributes; len = dpnt->rr_attr_size; /* * We basically need to parse the rr attributes again, and dig out the * dates and file types. */ pnt = parse_xa(pnt, &len, /*dpnt*/ 0); while (len >= 4) { if (pnt[3] != 1 && pnt[3] != 2) {#ifdef USE_LIBSCHILY errmsgno(EX_BAD, "**BAD RRVERSION (%d) for %c%c\n", pnt[3], pnt[0], pnt[1]);#else fprintf(stderr, "**BAD RRVERSION (%d) for %c%c\n", pnt[3], pnt[0], pnt[1]);#endif return -1; }; /* * If we have POSIX file modes, make sure that the file type is * the same. If it isn't, then we must always write the new * file. */ if (strncmp((char *) pnt, "PX", 2) == 0) { mode = isonum_733(pnt + 4); if ((lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT)) { same_file_type = 0; same_file = 0; } } if (strncmp((char *) pnt, "TF", 2) == 0) { offset = 5; if (pnt[4] & TF_CREATE) { iso9660_date((char *) time_buf, lstatbuf->st_ctime); if (memcmp(time_buf, pnt + offset, 7) != 0) same_file = 0; offset += 7; } if (pnt[4] & TF_MODIFY) { iso9660_date((char *) time_buf, lstatbuf->st_mtime); if (memcmp(time_buf, pnt + offset, 7) != 0) same_file = 0; offset += 7; } } if (strncmp((char *) pnt, "CE", 2) == 0) { cont_extent = isonum_733(pnt + 4); cont_offset = isonum_733(pnt + 12); cont_size = isonum_733(pnt + 20); }; len -= pnt[2]; pnt += pnt[2]; if (len <= 3 && cont_extent) { unsigned char sector[SECTOR_SIZE]; readsecs(cont_extent, sector, 1); if (parse_rr(§or[cont_offset], cont_size, dpnt) == -1) return (-1); }; }; /* * If we have the same fundamental file type, then it is clearly safe * to reuse the TRANS.TBL entry. */ if (same_file_type) { current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; } return same_file;}struct directory_entry **read_merging_directory(mrootp, nent) struct iso_directory_record *mrootp; int *nent;{ unsigned char *cpnt; unsigned char *cpnt1; char *p; char *dirbuff; int i; struct iso_directory_record *idr; int len; int nbytes; struct directory_entry **pnt; int rlen; struct directory_entry **rtn; int seen_rockridge; unsigned char *tt_buf; int tt_extent; int tt_size; static int warning_given = 0; /* * This is the number of sectors we will need to read. We need to * round up to get the last fractional sector - we are asking for the * data in terms of a number of sectors. */ nbytes = roundup(isonum_733((unsigned char *) mrootp->size), SECTOR_SIZE); /* * First, allocate a buffer large enough to read in the entire * directory. */ dirbuff = (char *) e_malloc(nbytes); readsecs(isonum_733((unsigned char *) mrootp->extent), dirbuff, nbytes / SECTOR_SIZE); /* * Next look over the directory, and count up how many entries we have. */ len = isonum_733((unsigned char *) mrootp->size); i = 0; *nent = 0; while (i < len) { idr = (struct iso_directory_record *) & dirbuff[i]; if (idr->length[0] == 0) { i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); continue; } (*nent)++; i += idr->length[0]; } /* * Now allocate the buffer which will hold the array we are about to * return. */ rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn)); /* * Finally, scan the directory one last time, and pick out the relevant * bits of information, and store it in the relevant bits of the * structure. */ i = 0; pnt = rtn; tt_extent = 0; seen_rockridge = 0; tt_size = 0; while (i < len) { idr = (struct iso_directory_record *) & dirbuff[i]; if (idr->length[0] == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -