📄 write.c
字号:
/* * 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 <string.h>#include <stdlib.h>#include "config.h"#include "mkisofs.h"#include "iso9660.h"#include <time.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include "foolhash.h"#include "md5.h"#ifdef HAVE_UNISTD_H#include <unistd.h>#endif #ifdef __SVR4extern char * strdup(const char *);#endif#ifdef VMSextern char * strdup(const char *);#endifextern struct hash_table *md5_hash;/* 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;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_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) { fprintf(stderr, "Cannot open '%s'.\n", nbuf); exit(1); } } while(count) { int got = fwrite(buffer,size,count,file); if(got<=0) { fprintf(stderr,"cannot fwrite %d*%d\n",size,count); exit(1); } 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) {#if defined(sun) || defined(_AUX_SOURCE) fprintf(stderr, "cannot open %s: (%d)\n", filename, errno);#else fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));#endif exit(1); } 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) { fprintf(stderr,"cannot read from %s\n",filename); exit(1); } 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 % 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)); }#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); } 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); } dwnext = dwpnt; dwpnt = dwpnt->next; free(dwnext); }} /* write_files(... */#if 0static void dump_filelist(){ struct deferred_write * dwpnt; dwpnt = dw_head; while(dwpnt) { fprintf(stderr, "File %s\n",dwpnt->name); dwpnt = dwpnt->next; } fprintf(stderr,"\n");}#endifstatic 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 ) { 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 \000 or \001, * and thus should always be sorted correctly. I need to figure * out why I thought I needed this in the first place. */#if 0 if( strcmp(rpnt, ".") == 0 ) return -1; if( strcmp(lpnt, ".") == 0 ) return 1; if( strcmp(rpnt, "..") == 0 ) return -1; if( strcmp(lpnt, "..") == 0 ) return 1;#else /* * The code above is wrong (as explained in Eric's comment), leading to incorrect * sort order iff the -L option ("allow leading dots") is in effect and a directory * contains entries that start with a dot. * * (TF, Tue Dec 29 13:49:24 CET 1998) */ if((*r)->isorec.name_len[0] == 1 && *rpnt == 0) return -1; /* '.' */ if((*l)->isorec.name_len[0] == 1 && *lpnt == 0) return 1; if((*r)->isorec.name_len[0] == 1 && *rpnt == 1) return -1; /* '..' */ if((*l)->isorec.name_len[0] == 1 && *lpnt == 1) return 1;#endif while(*rpnt && *lpnt) { if(*rpnt == ';' && *lpnt != ';') return -1; if(*rpnt != ';' && *lpnt == ';') return 1; if(*rpnt == ';' && *lpnt == ';') return 0; if(*rpnt == '.' && *lpnt != '.') return -1; if(*rpnt != '.' && *lpnt == '.') return 1; if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1; if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1; rpnt++; lpnt++; } if(*rpnt) return 1; if(*lpnt) return -1; return 0;}/* * Function: sort_directory * * Purpose: Sort the directory in the appropriate ISO9660 * order. * * Notes: Returns 0 if OK, returns > 0 if an error occurred. */int FDECL1(sort_directory, struct directory_entry **, sort_dir){ int dcount = 0; int xcount = 0; int j; int i, len; struct directory_entry * s_entry; struct directory_entry ** sortlist; /* need to keep a count of how many entries are hidden */ s_entry = *sort_dir; while(s_entry) { if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) xcount++; dcount++; s_entry = s_entry->next; } if( dcount == 0 ) { return 0; } /* * OK, now we know how many there are. Build a vector for sorting. */ sortlist = (struct directory_entry **) e_malloc(sizeof(struct directory_entry *) * dcount); j = dcount - 1; dcount = 0; s_entry = *sort_dir; while(s_entry) { if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) { /* put any hidden entries at the end of the vector */ sortlist[j--] = s_entry; } else { sortlist[dcount] = s_entry; dcount++; } len = s_entry->isorec.name_len[0]; s_entry->isorec.name[len] = 0; s_entry = s_entry->next; } /* * Each directory is required to contain at least . and .. */ if( dcount < 2 ) { sort_goof = 1; } else { /* only sort the non-hidden entries */ sort_goof = 0;#ifdef __STDC__ qsort(sortlist, dcount, sizeof(struct directory_entry *), (int (*)(const void *, const void *))compare_dirs);#else qsort(sortlist, dcount, sizeof(struct directory_entry *), compare_dirs);#endif /* * Now reassemble the linked list in the proper sorted order * We still need the hidden entries, as they may be used in the * Joliet tree. */ for(i=0; i<dcount+xcount-1; i++) { sortlist[i]->next = sortlist[i+1]; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -