write.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:40k
- /*
- * Program write.c - dump memory structures to file for iso9660 filesystem.
- 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: write.c,v 1.21 1999/03/07 17:41:19 eric Exp $";
- #include "config.h"
- #include <string.h>
- #include <stdlib.h>
- #include "mkisofs.h"
- #include "iso9660.h"
- #include <time.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
-
- #ifdef USE_LIBSCHILY
- #include <standard.h>
- #endif
- #ifdef __SVR4
- extern char * strdup(const char *);
- #endif
- #ifdef VMS
- extern char * strdup(const char *);
- #endif
- /* Max number of sectors we will write at one time */
- #define NSECT 16
- /* Counters for statistics */
- static int table_size = 0;
- static int total_dir_size = 0;
- static int rockridge_size = 0;
- static struct directory ** pathlist;
- static int next_path_index = 1;
- static int sort_goof;
- static int is_rr_dir = 0;
- struct output_fragment * out_tail;
- struct output_fragment * out_list;
- struct iso_primary_descriptor vol_desc;
- static int root_gen __PR((void));
- static int generate_path_tables __PR((void));
- static int file_gen __PR((void));
- static int dirtree_dump __PR((void));
- /* Routines to actually write the disc. We write sequentially so that
- we could write a tape, or write the disc directly */
- #define FILL_SPACE(X) memset(vol_desc.X, ' ', sizeof(vol_desc.X))
- void FDECL2(set_721, char *, pnt, unsigned int, i)
- {
- pnt[0] = i & 0xff;
- pnt[1] = (i >> 8) & 0xff;
- }
- void FDECL2(set_722, char *, pnt, unsigned int, i)
- {
- pnt[0] = (i >> 8) & 0xff;
- pnt[1] = i & 0xff;
- }
- void FDECL2(set_723, char *, pnt, unsigned int, i)
- {
- pnt[3] = pnt[0] = i & 0xff;
- pnt[2] = pnt[1] = (i >> 8) & 0xff;
- }
- void FDECL2(set_731, char *, pnt, unsigned int, i)
- {
- pnt[0] = i & 0xff;
- pnt[1] = (i >> 8) & 0xff;
- pnt[2] = (i >> 16) & 0xff;
- pnt[3] = (i >> 24) & 0xff;
- }
- void FDECL2(set_732, char *, pnt, unsigned int, i)
- {
- pnt[3] = i & 0xff;
- pnt[2] = (i >> 8) & 0xff;
- pnt[1] = (i >> 16) & 0xff;
- pnt[0] = (i >> 24) & 0xff;
- }
- int FDECL1(get_731, char *, p)
- {
- return ((p[0] & 0xff)
- | ((p[1] & 0xff) << 8)
- | ((p[2] & 0xff) << 16)
- | ((p[3] & 0xff) << 24));
- }
- int FDECL1(get_732, char *, p)
- {
- return ((p[3] & 0xff)
- | ((p[2] & 0xff) << 8)
- | ((p[1] & 0xff) << 16)
- | ((p[0] & 0xff) << 24));
- }
- int FDECL1(get_733, char *, p)
- {
- return ((p[0] & 0xff)
- | ((p[1] & 0xff) << 8)
- | ((p[2] & 0xff) << 16)
- | ((p[3] & 0xff) << 24));
- }
- void FDECL2(set_733, char *, pnt, unsigned int, i)
- {
- pnt[7] = pnt[0] = i & 0xff;
- pnt[6] = pnt[1] = (i >> 8) & 0xff;
- pnt[5] = pnt[2] = (i >> 16) & 0xff;
- pnt[4] = pnt[3] = (i >> 24) & 0xff;
- }
- void FDECL4(xfwrite, void *, buffer, int, count, int, size, FILE *, file)
- {
- /*
- * This is a hack that could be made better. XXXIs this the only place?
- * It is definitely needed on Operating Systems that do not
- * allow to write files that are > 2GB.
- * If the system is fast enough to be able to feed 1400 KB/s
- * writing speed of a DVD-R drive, use stdout.
- * If the system cannot do this reliable, you need to use this
- * hacky option.
- */
- static int idx = 0;
- if (split_output != 0 &&
- (idx == 0 || ftell(file) >= (1024 * 1024 * 1024) )) {
- char nbuf[512];
- extern char *outfile;
- if (idx == 0)
- unlink(outfile);
- sprintf(nbuf, "%s_%02d", outfile, idx++);
- file = freopen(nbuf, "wb", file);
- if (file == NULL) {
- #ifdef USE_LIBSCHILY
- comerr("Cannot open '%s'.n", nbuf);
- #else
- fprintf(stderr, "Cannot open '%s'.n", nbuf);
- exit(1);
- #endif
- }
- }
- while(count)
- {
- int got = fwrite(buffer,size,count,file);
- if(got<=0)
- {
- #ifdef USE_LIBSCHILY
- comerr("cannot fwrite %d*%dn",size,count);
- #else
- fprintf(stderr,"cannot fwrite %d*%dn",size,count);
- exit(1);
- #endif
- }
- count-=got,*(char**)&buffer+=size*got;
- }
- }
- struct deferred_write
- {
- struct deferred_write * next;
- char * table;
- unsigned int extent;
- unsigned int size;
- char * name;
- };
- static struct deferred_write * dw_head = NULL, * dw_tail = NULL;
- unsigned int last_extent_written =0;
- static int path_table_index;
- static time_t begun;
- /* We recursively walk through all of the directories and assign extent
- numbers to them. We have already assigned extent numbers to everything that
- goes in front of them */
- static int FDECL1(assign_directory_addresses, struct directory *, node)
- {
- int dir_size;
- struct directory * dpnt;
- dpnt = node;
-
- while (dpnt)
- {
- /* skip if it's hidden */
- if(dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) {
- dpnt = dpnt->next;
- continue;
- }
- /*
- * If we already have an extent for this (i.e. it came from
- * a multisession disc), then don't reassign a new extent.
- */
- dpnt->path_index = next_path_index++;
- if( dpnt->extent == 0 )
- {
- dpnt->extent = last_extent;
- dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11;
-
- last_extent += dir_size;
-
- /*
- * Leave room for the CE entries for this directory. Keep them
- * close to the reference directory so that access will be
- * quick.
- */
- if(dpnt->ce_bytes)
- {
- last_extent += ROUND_UP(dpnt->ce_bytes) >> 11;
- }
- }
- if(dpnt->subdir)
- {
- assign_directory_addresses(dpnt->subdir);
- }
- dpnt = dpnt->next;
- }
- return 0;
- }
- static void FDECL3(write_one_file, char *, filename,
- unsigned int, size, FILE *, outfile)
- {
- char buffer[SECTOR_SIZE * NSECT];
- FILE * infile;
- int remain;
- int use;
- if ((infile = fopen(filename, "rb")) == NULL)
- {
- #ifdef USE_LIBSCHILY
- comerr("cannot open '%s'n", filename);
- #else
- #if defined(sun) || defined(_AUX_SOURCE)
- fprintf(stderr, "cannot open %s: (%d)n", filename, errno);
- #else
- fprintf(stderr, "cannot open %s: %sn", filename, strerror(errno));
- #endif
- exit(1);
- #endif
- }
- remain = size;
- while(remain > 0)
- {
- use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain);
- use = ROUND_UP(use); /* Round up to nearest sector boundary */
- memset(buffer, 0, use);
- if (fread(buffer, 1, use, infile) == 0)
- {
- #ifdef USE_LIBSCHILY
- comerr("cannot read from %sn",filename);
- #else
- fprintf(stderr,"cannot read from %sn",filename);
- exit(1);
- #endif
- }
- xfwrite(buffer, 1, use, outfile);
- last_extent_written += use/SECTOR_SIZE;
- #if 0
- if((last_extent_written % 1000) < use/SECTOR_SIZE)
- {
- fprintf(stderr,"%d..", last_extent_written);
- }
- #else
- if((last_extent_written % (gui?500:5000)) < use/SECTOR_SIZE)
- {
- time_t now;
- time_t the_end;
- double frac;
-
- time(&now);
- frac = last_extent_written / (double)last_extent;
- the_end = begun + (now - begun) / frac;
- fprintf(stderr, "%6.2f%% done, estimate finish %s",
- frac * 100., ctime(&the_end));
- fflush(stderr);
- }
- #endif
- remain -= use;
- }
- fclose(infile);
- } /* write_one_file(... */
- static void FDECL1(write_files, FILE *, outfile)
- {
- struct deferred_write * dwpnt, *dwnext;
- dwpnt = dw_head;
- while(dwpnt)
- {
- if(dwpnt->table)
- {
- xfwrite(dwpnt->table, 1, ROUND_UP(dwpnt->size), outfile);
- last_extent_written += ROUND_UP(dwpnt->size) / SECTOR_SIZE;
- table_size += dwpnt->size;
- /* fprintf(stderr,"Size %d ", dwpnt->size); */
- free(dwpnt->table);
- dwpnt->table = NULL;
- }
- else
- {
- #ifdef VMS
- vms_write_one_file(dwpnt->name, dwpnt->size, outfile);
- #else
- write_one_file(dwpnt->name, dwpnt->size, outfile);
- #endif
- free(dwpnt->name);
- dwpnt->name = NULL;
- }
- dwnext = dwpnt;
- dwpnt = dwpnt->next;
- free(dwnext);
- dwnext = NULL;
- }
- } /* write_files(... */
- #if 0
- static void dump_filelist()
- {
- struct deferred_write * dwpnt;
- dwpnt = dw_head;
- while(dwpnt)
- {
- fprintf(stderr, "File %sn",dwpnt->name);
- dwpnt = dwpnt->next;
- }
- fprintf(stderr,"n");
- }
- #endif
- static int FDECL2(compare_dirs, const void *, rr, const void *, ll)
- {
- char * rpnt, *lpnt;
- struct directory_entry ** r, **l;
-
- r = (struct directory_entry **) rr;
- l = (struct directory_entry **) ll;
- rpnt = (*r)->isorec.name;
- lpnt = (*l)->isorec.name;
- /*
- * If the entries are the same, this is an error.
- */
- if( strcmp(rpnt, lpnt) == 0 )
- {
- #ifdef USE_LIBSCHILY
- errmsgno(EX_BAD, "Error: %s and %s have the same ISO9660 namen",
- (*r)->whole_name, (*l)->whole_name);
- #else
- fprintf(stderr, "Error: %s and %s have the same ISO9660 namen",
- (*r)->whole_name, (*l)->whole_name);
- #endif
- sort_goof++;
- }
- /* Check we don't have the same RR name */
- if (use_RockRidge && !is_rr_dir) {
- /* entries *can* have the same RR name in the "rr_moved" directory
- so skip checks if we're in reloc_dir */
- if (!(strcmp((*r)->name, (*l)->name))) {
- #ifdef USE_LIBSCHILY
- errmsgno(EX_BAD, "Error: %s and %s have the same Rock Ridge namen",
- (*r)->whole_name, (*l)->whole_name);
- #else
- fprintf (stderr, "Error: %s and %s have the same Rock Ridge namen",
- (*r)->whole_name, (*l)->whole_name);
- #endif
- sort_goof++;
- }
- }
- /*
- * Put the '.' and '..' entries on the head of the sorted list.
- * For normal ASCII, this always happens to be the case, but out of
- * band characters cause this not to be the case sometimes.
- *
- * FIXME(eric) - these tests seem redundant, in taht the name is
- * never assigned these values. It will instead be