📄 tree.c
字号:
/* * File tree.c - scan directory tree and build memory structures 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: tree.c,v 1.29 1999/03/07 17:41:19 eric Exp $";/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */#include "config.h"#include <stdlib.h>#include <string.h>#include <time.h>#include <errno.h>#include <unixstd.h>#include <fctldefs.h>#include <device.h>#ifdef VMS#include <sys/file.h>#include <vms/fabdef.h>#include "vms.h"extern char * strdup(const char *);#endif/* * Autoconf should be able to figure this one out for us and let us know * whether the system has memmove or not. */# ifndef HAVE_MEMMOVE# define memmove(d, s, n) bcopy ((s), (d), (n))# endif#include "mkisofs.h"#include "iso9660.h"#include "match.h"#include <sys/stat.h>#include "exclude.h"#ifdef DOESNT_WORK/* * This is the dead code */#ifdef NON_UNIXFS#define S_ISLNK(m) (0)#define S_ISSOCK(m) (0)#define S_ISFIFO(m) (0)#else#ifndef S_ISLNK#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)#endif#ifndef S_ISSOCK# ifdef S_IFSOCK# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)# else# define S_ISSOCK(m) (0)# endif#endif#endif#else/* * This is the new code */#include <statdefs.h>#endif#ifdef USE_LIBSCHILY#include <standard.h>#endif#ifdef __SVR4extern char * strdup(const char *);#endifstatic unsigned char symlink_buff[256];static char * filetype __PR((int t));static char * rstr __PR((char *s1, char *s2));static void stat_fix __PR((struct stat * st));static void generate_reloc_directory __PR((void));static void DECL(attach_dot_entries, (struct directory * dirnode, struct stat * parent_stat));static void DECL(delete_directory, (struct directory * parent, struct directory * child));extern int verbose;struct stat fstatbuf = {0,}; /* We use this for the artificial entries we create */struct stat root_statbuf = {0, }; /* Stat buffer for root directory */struct directory * reloc_dir = NULL;static char *filetype(t) int t;{ if ((t & S_IFMT) == 0) /* 0 (unallocated) */ return ("unallocated"); if (S_ISFIFO(t)) /* 1 */ return ("fifo"); if (S_ISCHR(t)) /* 2 */ return ("chr"); if ((t & S_IFMT) == 3) /* 3 (multiplexed chr) */ return ("multiplexed chr"); if (S_ISDIR(t)) /* 4 */ return ("dir"); if ((t & S_IFMT) == 5) /* 5 (named file) */ return ("named file"); if (S_ISBLK(t)) /* 6 */ return ("blk"); if ((t & S_IFMT) == 7) /* 7 (multiplexed blk) */ return ("multiplexed blk"); if (S_ISREG(t)) /* 8 */ return ("regular file"); if (S_ISCNT(t)) /* 9 */ return ("contiguous file"); if (S_ISLNK(t)) /* 10 */ return ("symlink"); if ((t & S_IFMT) == 11) /* 11 (Solaris shadow inode) */ return ("Solaris shadow inode"); if (S_ISSOCK(t)) /* 12 */ return ("socket"); if (S_ISDOOR(t)) /* 13 */ return ("door"); if ((t & S_IFMT) == 14) /* 14 (CPIO acl) */ return ("CPIO acl"); if ((t & S_IFMT) == 15) /* 15 (unused) */ return ("unused 15"); return ("BLETCH");}/* * Check if s1 ends in strings s2 */static char *rstr(s1, s2) char *s1; char *s2;{ int l1; int l2; l1 = strlen(s1); l2 = strlen(s2); if (l2 > l1) return ((char *)NULL); if (strcmp(&s1[l1 - l2], s2) == 0) return (&s1[l1 - l2]); return ((char *)NULL);}static voidFDECL1(stat_fix, struct stat *, st){ /* Remove the uid and gid, they will only be useful on the author's system. */ st->st_uid = 0; st->st_gid = 0; /* * Make sure the file modes make sense. Turn on all read bits. Turn * on all exec/search bits if any exec/search bit is set. Turn off * all write bits, and all special mode bits (on a r/o fs lock bits * are useless, and with uid+gid 0 don't want set-id bits, either). */ st->st_mode |= 0444;#ifndef _WIN32 /* make all file "executable" */ if (st->st_mode & 0111)#endif /* _WIN32 */ st->st_mode |= 0111; st->st_mode &= ~07222;}intFDECL2(stat_filter, char *, path, struct stat *, st){ int result = stat(path, st); if (result >= 0 && rationalize) stat_fix(st); return result;}intFDECL2(lstat_filter, char *, path, struct stat *, st){ int result = lstat(path, st); if (result >= 0 && rationalize) stat_fix(st); return result;}static int FDECL1(sort_n_finish, struct directory *, this_dir){ struct directory_entry * s_entry; struct directory_entry * s_entry1; struct directory_entry * table; int count; int d1; int d2; int d3; int new_reclen; char * c; int status = 0; int tablesize = 0; char newname[34]; char rootname[34]; /* Here we can take the opportunity to toss duplicate entries from the directory. */ /* ignore if it's hidden */ if(this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) { return 0; } table = NULL; init_fstatbuf(); /* * If we had artificially created this directory, then we might be * missing the required '.' entries. Create these now if we need * them. */ if( (this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) != (DIR_HAS_DOT | DIR_HAS_DOTDOT) ) { attach_dot_entries(this_dir, &fstatbuf); } flush_file_hash(); s_entry = this_dir->contents; while(s_entry) { /* ignore if it's hidden */ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) { s_entry = s_entry->next; continue; } /* * First assume no conflict, and handle this case */ if(!(s_entry1 = find_file_hash(s_entry->isorec.name))) { add_file_hash(s_entry); s_entry = s_entry->next; continue; } if(s_entry1 == s_entry) {#ifdef USE_LIBSCHILY comerrno(EX_BAD, "Fatal goof, file '%s' already in hash table.\n", s_entry->isorec.name);#else fprintf(stderr, "Fatal goof, file '%s' already in hash table.\n", s_entry->isorec.name); exit(1);#endif } /* * OK, handle the conflicts. Try substitute names until we come * up with a winner */ strcpy(rootname, s_entry->isorec.name); if(full_iso9660_filenames) { /* * 27 is 30 chars minus the 3 characters we are * appending below to create unique filenames. */ if(strlen(rootname) > 27) rootname[27] = 0; } /* * Strip off the non-significant part of the name so that we are left * with a sensible root filename. If we don't find a '.', then try * a ';'. */ c = strchr(rootname, '.'); /* * In case we ever allow more than on dot, only modify the section * past the last dot if the file name starts with a dot. */ if (c != NULL && c == rootname && c != strrchr(rootname, '.')) c = strrchr(rootname, '.'); if (c) *c = 0; else { c = strchr(rootname, ';'); if (c) *c = 0; } for(d1 = 0; d1 < 36; d1++) { for(d2 = 0; d2 < 36; d2++) { for(d3 = 0; d3 < 36; d3++) { sprintf(newname,"%s.%c%c%c%s", rootname, (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10), (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10), (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10), (s_entry->isorec.flags[0] == 2 || omit_version_number ? "" : ";1")); #ifdef VMS /* Sigh. VAXCRTL seems to be broken here */ { int ijk = 0; while(newname[ijk]) { if(newname[ijk] == ' ') newname[ijk] = '0'; ijk++; } }#endif if(!find_file_hash(newname)) goto got_valid_name; } } } /* * If we fell off the bottom here, we were in real trouble. */#ifdef USE_LIBSCHILY comerrno(EX_BAD, "Unable to generate unique name for file %s\n", s_entry->name);#else fprintf(stderr,"Unable to generate unique name for file %s\n", s_entry->name); exit(1);#endifgot_valid_name: /* * OK, now we have a good replacement name. Now decide which one * of these two beasts should get the name changed */ if(s_entry->priority < s_entry1->priority) { if( verbose > 0 ) { fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry->name, s_entry1->name); } s_entry->isorec.name_len[0] = strlen(newname); new_reclen = offsetof(struct iso_directory_record, name[0]) + strlen(newname); if(use_RockRidge) { if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ new_reclen += s_entry->rr_attr_size; } if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ s_entry->isorec.length[0] = new_reclen; strcpy(s_entry->isorec.name, newname); } else { delete_file_hash(s_entry1); if( verbose > 0 ) { fprintf(stderr,"Using %s for %s%s%s (%s)\n", newname, this_dir->whole_name, SPATH_SEPARATOR, s_entry1->name, s_entry->name); } s_entry1->isorec.name_len[0] = strlen(newname); new_reclen = offsetof(struct iso_directory_record, name[0]) + strlen(newname); if(use_RockRidge) { if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ new_reclen += s_entry1->rr_attr_size; } if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ s_entry1->isorec.length[0] = new_reclen; strcpy(s_entry1->isorec.name, newname); add_file_hash(s_entry1); } add_file_hash(s_entry); s_entry = s_entry->next; } if(generate_tables && !find_file_hash(trans_tbl) && (reloc_dir != this_dir) && (this_dir->extent == 0) ) { /* * First we need to figure out how big this table is */ for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) { if(strcmp(s_entry->name, ".") == 0 || strcmp(s_entry->name, "..") == 0) continue; if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) continue; if(s_entry->table) tablesize += 35 + strlen(s_entry->table); } } if( tablesize > 0 ) { table = (struct directory_entry *) e_malloc(sizeof (struct directory_entry)); memset(table, 0, sizeof(struct directory_entry)); table->table = NULL; table->next = this_dir->contents; this_dir->contents = table; table->filedir = root; table->isorec.flags[0] = 0; table->priority = 32768; iso9660_date(table->isorec.date, fstatbuf.st_mtime); table->inode = TABLE_INODE; table->dev = (dev_t) UNCACHED_DEVICE; set_723(table->isorec.volume_sequence_number, volume_sequence_number); set_733((char *) table->isorec.size, tablesize); table->size = tablesize; table->filedir = this_dir; if (jhide_trans_tbl) table->de_flags |= INHIBIT_JOLIET_ENTRY;/* table->name = strdup("<translation table>");*/ table->name = strdup(trans_tbl); table->table = (char *) e_malloc(ROUND_UP(tablesize)); memset(table->table, 0, ROUND_UP(tablesize)); iso9660_file_length (trans_tbl, table, 0); if(use_RockRidge) { fstatbuf.st_mode = 0444 | S_IFREG; fstatbuf.st_nlink = 1; generate_rock_ridge_attributes("", trans_tbl, table, &fstatbuf, &fstatbuf, 0); } } /* * We have now chosen the 8.3 names and we should now know the length * of every entry in the directory. */ for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) { /* skip if it's hidden */ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) { continue; } new_reclen = strlen(s_entry->isorec.name); /* * First update the path table sizes for directories. */ if(s_entry->isorec.flags[0] == 2) { if (strcmp(s_entry->name,".") != 0 && strcmp(s_entry->name,"..") != 0) { path_table_size += new_reclen + offsetof(struct iso_path_table, name[0]); if (new_reclen & 1) path_table_size++; } else { new_reclen = 1; if (this_dir == root && strlen(s_entry->name) == 1) { path_table_size += new_reclen + offsetof(struct iso_path_table, name[0]); } } } if(path_table_size & 1) path_table_size++; /* For odd lengths we pad */ s_entry->isorec.name_len[0] = new_reclen; new_reclen += offsetof(struct iso_directory_record, name[0]); if (new_reclen & 1) new_reclen++; new_reclen += s_entry->rr_attr_size; if (new_reclen & 1) new_reclen++; if(new_reclen > 0xff) {#ifdef USE_LIBSCHILY comerrno(EX_BAD, "Fatal error - RR overflow for file %s\n", s_entry->name);#else fprintf(stderr,"Fatal error - RR overflow for file %s\n", s_entry->name); exit(1);#endif } s_entry->isorec.length[0] = new_reclen; } status = sort_directory(&this_dir->contents, (reloc_dir == this_dir)); if( status > 0 ) {#ifdef USE_LIBSCHILY comerrno(EX_BAD, "Unable to sort directory %s\n", this_dir->whole_name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -