📄 write.c
字号:
/* @(#)write.c 1.44 00/06/05 joerg */#ifndef lintstatic char sccsid[] = "@(#)write.c 1.44 00/06/05 joerg";#endif/* * Program write.c - dump memory structures to file for iso9660 filesystem. Written by Eric Youngdale (1993). Copyright 1993 Yggdrasil Computing, Incorporated 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. *//* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */#include "config.h"#include <strdefs.h>#include <stdxlib.h>#include "mkisofs.h"#include "iso9660.h"#ifdef SORTING#include "match.h"#endif /* SORTING */#include <time.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unixstd.h>#ifdef USE_LIBSCHILY#include <standard.h>#include <schily.h>#endif#ifdef __SVR4extern char *strdup __PR((const char *));#endif#ifdef VMSextern char *strdup __PR((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; void set_721 __PR((char *pnt, unsigned int i)); void set_722 __PR((char *pnt, unsigned int i)); void set_723 __PR((char *pnt, unsigned int i)); void set_731 __PR((char *pnt, unsigned int i)); void set_732 __PR((char *pnt, unsigned int i)); void set_733 __PR((char *pnt, unsigned int i)); int get_731 __PR((char *p)); int get_732 __PR((char *p)); int get_733 __PR((char *p)); void xfwrite __PR((void *buffer, int count, int size, FILE *file));static int assign_directory_addresses __PR((struct directory *node));#ifdef APPLE_HYBstatic void write_one_file __PR((char *filename, unsigned int size, FILE *outfile, unsigned int off));#elsestatic void write_one_file __PR((char *filename, unsigned int size, FILE *outfile));#endifstatic void write_files __PR((FILE *outfile));#if 0static void dump_filelist __PR((void));#endifstatic int compare_dirs __PR((const void *rr, const void *ll)); int sort_directory __PR((struct directory_entry **sort_dir, int rr));static int root_gen __PR((void));static void assign_file_addresses __PR((struct directory *dpnt));static void free_one_directory __PR((struct directory *dpnt));static void free_directories __PR((struct directory *dpnt)); void generate_one_directory __PR((struct directory *dpnt, FILE *outfile));static void build_pathlist __PR((struct directory *node));static int compare_paths __PR((void const *r, void const *l));static int generate_path_tables __PR((void)); void memcpy_max __PR((char *to, char *from, int max)); void outputlist_insert __PR((struct output_fragment *frag));static int file_write __PR((FILE *outfile));static int pvd_write __PR((FILE *outfile));static int evd_write __PR((FILE *outfile));static int vers_write __PR((FILE *outfile));static int pathtab_write __PR((FILE *outfile));static int exten_write __PR((FILE *outfile)); int oneblock_size __PR((int starting_extent));static int pathtab_size __PR((int starting_extent));static int padblock_size __PR((int starting_extent));static int padend_size __PR((int starting_extent));static int file_gen __PR((void));static int dirtree_dump __PR((void));static int dirtree_fixup __PR((int starting_extent));static int dirtree_size __PR((int starting_extent));static int ext_size __PR((int starting_extent));static int dirtree_write __PR((FILE *outfile));static int dirtree_cleanup __PR((FILE *outfile));static int padblock_write __PR((FILE *outfile));static int padend_write __PR((FILE *outfile));#ifdef APPLE_HYBstatic int hfs_pad;static void hfs_file_gen __PR((int start_extent));static void gen_prepboot __PR((void)); int get_adj_size __PR((int Csize)); int adj_size __PR((int Csize, int start_extent, int extra)); void adj_size_other __PR((struct directory *dpnt));static int hfs_hce_write __PR((FILE * outfile)); int insert_padding_file __PR((int size));#endif /* APPLE_HYB */#ifdef SORTINGstatic int compare_sort __PR((const void * rr, const void * ll));static void reassign_link_addresses __PR((struct directory * dpnt));static int sort_file_addresses __PR((void));#endif /* SORTING *//* * 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))voidset_721(pnt, i) char *pnt; unsigned int i;{ pnt[0] = i & 0xff; pnt[1] = (i >> 8) & 0xff;}voidset_722(pnt, i) char *pnt; unsigned int i;{ pnt[0] = (i >> 8) & 0xff; pnt[1] = i & 0xff;}voidset_723(pnt, i) char *pnt; unsigned int i;{ pnt[3] = pnt[0] = i & 0xff; pnt[2] = pnt[1] = (i >> 8) & 0xff;}voidset_731(pnt, i) char *pnt; unsigned int i;{ pnt[0] = i & 0xff; pnt[1] = (i >> 8) & 0xff; pnt[2] = (i >> 16) & 0xff; pnt[3] = (i >> 24) & 0xff;}voidset_732(pnt, i) char *pnt; unsigned int i;{ pnt[3] = i & 0xff; pnt[2] = (i >> 8) & 0xff; pnt[1] = (i >> 16) & 0xff; pnt[0] = (i >> 24) & 0xff;}voidset_733(pnt, i) 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;}intget_731(p) char *p;{ return ((p[0] & 0xff) | ((p[1] & 0xff) << 8) | ((p[2] & 0xff) << 16) | ((p[3] & 0xff) << 24));}intget_732(p) char *p;{ return ((p[3] & 0xff) | ((p[2] & 0xff) << 8) | ((p[1] & 0xff) << 16) | ((p[0] & 0xff) << 24));}intget_733(p) char *p;{ return ((p[0] & 0xff) | ((p[1] & 0xff) << 8) | ((p[2] & 0xff) << 16) | ((p[3] & 0xff) << 24));}voidxfwrite(buffer, count, size, file) 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*%d\n", size, count);#else fprintf(stderr, "cannot fwrite %d*%d\n", size, count); exit(1);#endif } count -= got, *(char **) &buffer += size * got; }}#ifdef APPLE_HYB/* * use the deferred_write struct to store info about the hfs_boot_file */static struct deferred_write mac_boot;#endif /* APPLE_HYB */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 intassign_directory_addresses(node) 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 += ISO_ROUND_UP(dpnt->ce_bytes) >> 11; } } if (dpnt->subdir) { assign_directory_addresses(dpnt->subdir); } dpnt = dpnt->next; } return 0;}#ifdef APPLE_HYBstatic voidwrite_one_file(filename, size, outfile, off) char *filename; unsigned int size; FILE *outfile; unsigned int off;#elsestatic voidwrite_one_file(filename, size, outfile) char *filename; unsigned int size; FILE *outfile;#endif /* APPLE_HYB */{ /* * It seems that there are still stone age C-compilers * around. * The Metrowerks C found on BeOS/PPC does not allow * more than 32kB of local vars. * As we do not need to call write_one_file() recursively * we make buffer static. */static 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: %s\n", filename, strerror(errno));#endif exit(1);#endif }#ifdef APPLE_HYB fseek(infile, off, SEEK_SET);#endif /* APPLE_HYB */ remain = size; while (remain > 0) { use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT * SECTOR_SIZE : remain); use = ISO_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 %s\n", filename);#else fprintf(stderr, "cannot read from %s\n", 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 / (1.0 * last_extent); the_end = begun + (now - begun) / frac;#ifndef NO_FLOATINGPOINT fprintf(stderr, "%6.2f%% done, estimate finish %s", frac * 100., ctime(&the_end));#else fprintf(stderr, "%3d.%-02d%% done, estimate finish %s", (int)(frac * 100.), (int)((frac+.00005) * 10000.)%100, ctime(&the_end));#endif fflush(stderr); }#endif remain -= use; } fclose(infile);}/* write_one_file(... */static voidwrite_files(outfile) FILE *outfile;{ struct deferred_write *dwpnt, *dwnext; dwpnt = dw_head; while (dwpnt) { if (dwpnt->table) { xfwrite(dwpnt->table, 1, ISO_ROUND_UP(dwpnt->size), outfile); last_extent_written += ISO_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#ifdef APPLE_HYB write_one_file(dwpnt->name, dwpnt->size, outfile, dwpnt->off);#else write_one_file(dwpnt->name, dwpnt->size, outfile);#endif /* APPLE_HYB */#endif free(dwpnt->name); dwpnt->name = NULL; }#ifdef APPLE_HYB if (apple_hyb) { /* * we may have to pad out ISO files to work with HFS * clump sizes */ char blk[SECTOR_SIZE]; int i; for (i = 0; i < dwpnt->pad; i++) xfwrite(blk, 1, SECTOR_SIZE, outfile); last_extent_written += dwpnt->pad; }#endif /* APPLE_HYB */ dwnext = dwpnt; dwpnt = dwpnt->next; free(dwnext); dwnext = NULL; }}/* write_files(... */#if 0static voiddump_filelist(){ struct deferred_write *dwpnt; dwpnt = dw_head; while (dwpnt) { fprintf(stderr, "File %s\n", dwpnt->name); dwpnt = dwpnt->next; } fprintf(stderr, "\n");}#endifstatic intcompare_dirs(rr, ll) 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;#ifdef APPLE_HYB /* * resource fork MUST (not sure if this is true for HFS volumes) be * before the data fork - so force it here */ if ((*r)->assoc && (*r)->assoc == (*l)) return 1; if ((*l)->assoc && (*l)->assoc == (*r)) return -1;#endif /* APPLE_HYB */ /* 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 name\n", (*r)->whole_name, (*l)->whole_name);#else fprintf(stderr, "Error: %s and %s have the same ISO9660 name\n", (*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 name\n", (*r)->whole_name, (*l)->whole_name);#else fprintf(stderr, "Error: %s and %s have the same Rock Ridge name\n", (*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 that 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -