rock.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:16k
- /*
- * File rock.c - generate RRIP records for iso9660 filesystems.
- Written by Eric Youngdale (1993).
- Copyright 1993 Yggdrasil Computing, Incorporated
- 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. */
- static char rcsid[] ="$Id: rock.c,v 1.8 1999/03/02 03:41:26 eric Exp $";
- #include "config.h"
- #include <stdlib.h>
- #include <unixstd.h>
- #include <device.h>
- #include "mkisofs.h"
- #include "iso9660.h"
- #include <string.h>
- #ifdef DOESNT_WORK
- #ifdef NON_UNIXFS
- /*
- * This is the dead code
- */
- #define S_ISLNK(m) (0)
- #else
- #ifndef S_ISLNK
- #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
- #endif
- #endif
- #else
- /*
- * This is the new code
- */
- #include <statdefs.h>
- #endif
- #ifdef USE_LIBSCHILY
- #include <standard.h>
- #endif
- #define SU_VERSION 1
- #define SL_ROOT 8
- #define SL_PARENT 4
- #define SL_CURRENT 2
- #define SL_CONTINUE 1
- #define CE_SIZE 28
- #define CL_SIZE 12
- #define ER_SIZE 8
- #define NM_SIZE 5
- #define PL_SIZE 12
- #define PN_SIZE 20
- #define PX_SIZE 36
- #define RE_SIZE 4
- #define SL_SIZE 20
- #define ZZ_SIZE 15
- #ifdef __QNX__
- #define TF_SIZE (5 + 4 * 7)
- #else
- #define TF_SIZE (5 + 3 * 7)
- #endif
- /* If we need to store this number of bytes, make sure we
- do not box ourselves in so that we do not have room for
- a CE entry for the continuation record */
- #define MAYBE_ADD_CE_ENTRY(BYTES)
- (BYTES + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
- /*
- * Buffer to build RR attributes
- */
- static unsigned char Rock[16384];
- static unsigned char symlink_buff[256];
- static int ipnt = 0;
- static int recstart = 0;
- static int currlen = 0;
- static int mainrec = 0;
- static int reclimit;
- static void add_CE_entry __PR((void));
- static void add_CE_entry(){
- if(recstart)
- set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart);
- Rock[ipnt++] ='C';
- Rock[ipnt++] ='E';
- Rock[ipnt++] = CE_SIZE;
- Rock[ipnt++] = SU_VERSION;
- set_733((char*)Rock + ipnt, 0);
- ipnt += 8;
- set_733((char*)Rock + ipnt, 0);
- ipnt += 8;
- set_733((char*)Rock + ipnt, 0);
- ipnt += 8;
- recstart = ipnt;
- currlen = 0;
- if(!mainrec) mainrec = ipnt;
- reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
- }
- #ifdef __STDC__
- int generate_rock_ridge_attributes (char * whole_name, char * name,
- struct directory_entry * s_entry,
- struct stat * statbuf,
- struct stat * lstatbuf,
- int deep_opt)
- #else
- int generate_rock_ridge_attributes (whole_name, name,
- s_entry,
- statbuf,
- lstatbuf,
- deep_opt)
- char * whole_name; char * name; struct directory_entry * s_entry;
- struct stat * statbuf, *lstatbuf;
- int deep_opt;
- #endif
- {
- int flagpos, flagval;
- int need_ce;
- statbuf = statbuf; /* this shuts up unreferenced compiler warnings */
- mainrec = recstart = ipnt = 0;
- reclimit = 0xf8;
- /* no need to fill in the RR stuff if we won't see the file */
- if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
- return 0;
- /* Obtain the amount of space that is currently used for the directory
- record. Assume max for name, since name conflicts may cause us
- to rename the file later on */
- currlen = sizeof(s_entry->isorec);
- /* Identify that we are using the SUSP protocol */
- if(deep_opt & NEED_SP){
- Rock[ipnt++] ='S';
- Rock[ipnt++] ='P';
- Rock[ipnt++] = 7;
- Rock[ipnt++] = SU_VERSION;
- Rock[ipnt++] = 0xbe;
- Rock[ipnt++] = 0xef;
- Rock[ipnt++] = 0;
- };
- /* First build the posix name field */
- Rock[ipnt++] ='R';
- Rock[ipnt++] ='R';
- Rock[ipnt++] = 5;
- Rock[ipnt++] = SU_VERSION;
- flagpos = ipnt;
- flagval = 0;
- Rock[ipnt++] = 0; /* We go back and fix this later */
- if(strcmp(name,".") && strcmp(name,"..")){
- char * npnt;
- int remain, use;
- remain = strlen(name);
- npnt = name;
- while(remain){
- use = remain;
- need_ce = 0;
- /* Can we fit this SUSP and a CE entry? */
- if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
- use = reclimit - currlen - CE_SIZE - (ipnt - recstart);
- need_ce++;
- }
- /* Only room for 256 per SUSP field */
- if(use > 0xf8) use = 0xf8;
- /* First build the posix name field */
- Rock[ipnt++] ='N';
- Rock[ipnt++] ='M';
- Rock[ipnt++] = NM_SIZE + use;
- Rock[ipnt++] = SU_VERSION;
- Rock[ipnt++] = (remain != use ? 1 : 0);
- flagval |= (1<<3);
- strncpy((char *)&Rock[ipnt], npnt, use);
- npnt += use;
- ipnt += use;
- remain -= use;
- if(remain && need_ce) add_CE_entry();
- };
- };
- /*
- * Add the posix modes
- */
- if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry();
- Rock[ipnt++] ='P';
- Rock[ipnt++] ='X';
- Rock[ipnt++] = PX_SIZE;
- Rock[ipnt++] = SU_VERSION;
- flagval |= (1<<0);
- set_733((char*)Rock + ipnt, lstatbuf->st_mode);
- ipnt += 8;
- set_733((char*)Rock + ipnt, lstatbuf->st_nlink);
- ipnt += 8;
- set_733((char*)Rock + ipnt, lstatbuf->st_uid);
- ipnt += 8;
- set_733((char*)Rock + ipnt, lstatbuf->st_gid);
- ipnt += 8;
- /*
- * Check for special devices
- */
- #if defined(S_IFCHR) || defined(S_IFBLK)
- #ifndef NON_UNIXFS
- if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
- if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry();
- Rock[ipnt++] ='P';
- Rock[ipnt++] ='N';
- Rock[ipnt++] = PN_SIZE;
- Rock[ipnt++] = SU_VERSION;
- flagval |= (1<<1);
- #if 1
- /*
- * This is the new and only code which uses <device.h>
- */
- set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev ));
- ipnt += 8;
- set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev));
- ipnt += 8;
- #else
- /*
- * If we don't have sysmacros.h, then we have to guess as to how
- * best to pick apart the device number for major/minor.
- * Note: this may very well be wrong for many systems, so
- * it is always best to use the major/minor macros if the
- * system supports it.
- */
- if(sizeof(dev_t) <= 2) {
- set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8));
- ipnt += 8;
- set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff);
- ipnt += 8;
- }
- else if(sizeof(dev_t) <= 4) {
- set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8);
- ipnt += 8;
- set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff);
- ipnt += 8;
- }
- else {
- set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16);
- ipnt += 8;
- set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
- ipnt += 8;
- }
- #endif
- };
- #endif
- #endif /* defined(S_IFCHR) || defined(S_IFBLK) */
- /*
- * Check for and symbolic links. VMS does not have these.
- */
- #ifdef S_IFLNK
- if (S_ISLNK(lstatbuf->st_mode)){
- int lenpos, lenval, j0, j1;
- int nchar;
- unsigned char * cpnt, *cpnt1;
- #ifdef HAVE_READLINK
- nchar = readlink(whole_name, (char *)symlink_buff, sizeof(symlink_buff));
- #else
- nchar = -1;
- #endif /* HAVE_READLINK */
- symlink_buff[nchar < 0 ? 0 : nchar] = 0;
- nchar = strlen((char *) symlink_buff);
- set_733(s_entry->isorec.size, 0);
- cpnt = &symlink_buff[0];
- flagval |= (1<<2);
- if (! split_SL_field)
- {
- int sl_bytes = 0;
- for (cpnt1 = cpnt; *cpnt1 != ' '; cpnt1++)
- {
- if (*cpnt1 == '/')
- {
- sl_bytes += 4;
- }
- else
- {
- sl_bytes += 1;
- }
- }
- if (sl_bytes > 250)
- {
- /*
- * the symbolic link won't fit into one SL System Use Field
- * print an error message and continue with splited one
- */
- fprintf(stderr,"symbolic link ``%s'' to long for one SL System Use Field, splitting", cpnt);
- }
- if(MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry();
- }
- while(nchar){
- if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
- Rock[ipnt++] ='S';
- Rock[ipnt++] ='L';
- lenpos = ipnt;
- Rock[ipnt++] = SL_SIZE;
- Rock[ipnt++] = SU_VERSION;
- Rock[ipnt++] = 0; /* Flags */
- lenval = 5;
- while(*cpnt){
- cpnt1 = (unsigned char *) strchr((char *) cpnt, '/');
- if(cpnt1) {
- nchar--;
- *cpnt1 = 0;
- };
-
- /* We treat certain components in a special way. */
- if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){
- if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
- Rock[ipnt++] = SL_PARENT;
- Rock[ipnt++] = 0; /* length is zero */
- lenval += 2;
- nchar -= 2;
- } else if(cpnt[0] == '.' && cpnt[1] == 0){
- if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
- Rock[ipnt++] = SL_CURRENT;
- Rock[ipnt++] = 0; /* length is zero */
- lenval += 2;
- nchar -= 1;
- } else if(cpnt[0] == 0){
- if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
- Rock[ipnt++] = SL_ROOT;
- Rock[ipnt++] = 0; /* length is zero */
- lenval += 2;
- } else {
- /* If we do not have enough room for a component, start
- a new continuations segment now */
- if(split_SL_component ? MAYBE_ADD_CE_ENTRY(6) :
- MAYBE_ADD_CE_ENTRY(6 + strlen ((char *) cpnt)))
- {
- add_CE_entry();
- if(cpnt1)
- {
- *cpnt1 = '/';
- nchar++;
- cpnt1 = NULL; /* A kluge so that we can restart properly */
- }
- break;
- }
- j0 = strlen((char *) cpnt);
- while(j0) {
- j1 = j0;
- if(j1 > 0xf8) j1 = 0xf8;
- need_ce = 0;
- if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
- j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart);
- need_ce++;
- }
- Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0);
- Rock[ipnt++] = j1;
- strncpy((char *) Rock + ipnt, (char *) cpnt, j1);
- ipnt += j1;
- lenval += j1 + 2;
- cpnt += j1;
- nchar -= j1; /* Number we processed this time */
- j0 -= j1;
- if(need_ce) {
- add_CE_entry();
- if(cpnt1) {
- *cpnt1 = '/';
- nchar++;
- cpnt1 = NULL; /* A kluge so that we can restart properly */
- }
- break;
- }
- }
- };
- if(cpnt1) {
- cpnt = cpnt1 + 1;
- } else
- break;
- }
- Rock[lenpos] = lenval;
- if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */
- } /* while nchar */
- } /* Is a symbolic link */
- #endif /* S_IFLNK */
- /*
- * Add in the Rock Ridge TF time field
- */
- if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry();
- Rock[ipnt++] ='T';
- Rock[ipnt++] ='F';
- Rock[ipnt++] = TF_SIZE;
- Rock[ipnt++] = SU_VERSION;
- #ifdef __QNX__
- Rock[ipnt++] = 0x0f;
- #else
- Rock[ipnt++] = 0x0e;
- #endif
- flagval |= (1<<7);
- #ifdef __QNX__
- iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
- ipnt += 7;
- #endif
- iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
- ipnt += 7;
- iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
- ipnt += 7;
- iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
- ipnt += 7;
- /*
- * Add in the Rock Ridge RE time field
- */
- if(deep_opt & NEED_RE){
- if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry();
- Rock[ipnt++] ='R';
- Rock[ipnt++] ='E';
- Rock[ipnt++] = RE_SIZE;
- Rock[ipnt++] = SU_VERSION;
- flagval |= (1<<6);
- };
- /*
- * Add in the Rock Ridge PL record, if required.
- */
- if(deep_opt & NEED_PL){
- if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry();
- Rock[ipnt++] ='P';
- Rock[ipnt++] ='L';
- Rock[ipnt++] = PL_SIZE;
- Rock[ipnt++] = SU_VERSION;
- set_733((char*)Rock + ipnt, 0);
- ipnt += 8;
- flagval |= (1<<5);
- };
- /*
- * Add in the Rock Ridge CL field, if required.
- */
- if(deep_opt & NEED_CL){
- if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry();
- Rock[ipnt++] ='C';
- Rock[ipnt++] ='L';
- Rock[ipnt++] = CL_SIZE;
- Rock[ipnt++] = SU_VERSION;
- set_733((char*)Rock + ipnt, 0);
- ipnt += 8;
- flagval |= (1<<4);
- };
- #ifndef VMS
- /* If transparent compression was requested, fill in the correct
- field for this file */
- if(transparent_compression &&
- S_ISREG(lstatbuf->st_mode) &&
- strlen(name) > 3 &&
- strcmp(name + strlen(name) - 3,".gZ") == 0){
- FILE * zipfile;
- char * checkname;
- unsigned int file_size;
- unsigned char header[8];
- int OK_flag;
- /* First open file and verify that the correct algorithm was used */
- file_size = 0;
- OK_flag = 1;
- zipfile = fopen(whole_name, "rb");
- fread(header, 1, sizeof(header), zipfile);
- /* Check some magic numbers from gzip. */
- if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0;
- /* Make sure file was blocksized. */
- if(((header[3] & 0x40) == 0)) OK_flag = 0;
- /* OK, now go to the end of the file and get some more info */
- if(OK_flag){
- int status;
- status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END);
- if(status == -1) OK_flag = 0;
- }
- if(OK_flag){
- if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header))
- OK_flag = 0;
- else {
- int blocksize;
- blocksize = (header[3] << 8) | header[2];
- file_size = ((unsigned int)header[7] << 24) |
- ((unsigned int)header[6] << 16) |
- ((unsigned int)header[5] << 8) | header[4];
- #if 0
- fprintf(stderr,"Blocksize = %d %dn", blocksize, file_size);
- #endif
- if(blocksize != SECTOR_SIZE) OK_flag = 0;
- }
- }
- fclose(zipfile);
- checkname = strdup(whole_name);
- checkname[strlen(whole_name)-3] = 0;
- zipfile = fopen(checkname, "rb");
- if(zipfile) {
- OK_flag = 0;
- #ifdef USE_LIBSCHILY
- errmsg("Unable to insert transparent compressed file - name conflictn");
- #else
- fprintf(stderr, "Unable to insert transparent compressed file - name conflictn");
- #endif
- fclose(zipfile);
- }
- free(checkname);
- if(OK_flag){
- if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry();
- Rock[ipnt++] ='Z';
- Rock[ipnt++] ='Z';
- Rock[ipnt++] = ZZ_SIZE;
- Rock[ipnt++] = SU_VERSION;
- Rock[ipnt++] = 'g'; /* Identify compression technique used */
- Rock[ipnt++] = 'z';
- Rock[ipnt++] = 3;
- set_733((char*)Rock + ipnt, file_size); /* Real file size */
- ipnt += 8;
- };
- }
- #endif
- /*
- * Add in the Rock Ridge CE field, if required. We use this for the
- * extension record that is stored in the root directory.
- */
- if(deep_opt & NEED_CE) add_CE_entry();
- /*
- * Done filling in all of the fields. Now copy it back to a buffer for the
- * file in question.
- */
- /* Now copy this back to the buffer for the file */
- Rock[flagpos] = flagval;
- /* If there was a CE, fill in the size field */
- if(recstart)
- set_733((char*)Rock + recstart - 8, ipnt - recstart);
- s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt);
- s_entry->total_rr_attr_size = ipnt;
- s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
- memcpy(s_entry->rr_attributes, Rock, ipnt);
- return ipnt;
- }
- /* Guaranteed to return a single sector with the relevant info */
- char * FDECL4(generate_rr_extension_record, char *, id, char *, descriptor,
- char *, source, int *, size){
- int lipnt = 0;
- char * pnt;
- int len_id, len_des, len_src;
- len_id = strlen(id);
- len_des = strlen(descriptor);
- len_src = strlen(source);
- Rock[lipnt++] ='E';
- Rock[lipnt++] ='R';
- Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
- Rock[lipnt++] = 1;
- Rock[lipnt++] = len_id;
- Rock[lipnt++] = len_des;
- Rock[lipnt++] = len_src;
- Rock[lipnt++] = 1;
- memcpy(Rock + lipnt, id, len_id);
- lipnt += len_id;
- memcpy(Rock + lipnt, descriptor, len_des);
- lipnt += len_des;
- memcpy(Rock + lipnt, source, len_src);
- lipnt += len_src;
- if(lipnt > SECTOR_SIZE) {
- #ifdef USE_LIBSCHILY
- comerrno(EX_BAD, "Extension record too longn");
- #else
- fprintf(stderr,"Extension record too longn");
- exit(1);
- #endif
- };
- pnt = (char *) e_malloc(SECTOR_SIZE);
- memset(pnt, 0, SECTOR_SIZE);
- memcpy(pnt, Rock, lipnt);
- *size = lipnt;
- return pnt;
- }