diff options
Diffstat (limited to 'gnu/usr.sbin/mkisofs')
34 files changed, 10794 insertions, 0 deletions
diff --git a/gnu/usr.sbin/mkisofs/COPYING b/gnu/usr.sbin/mkisofs/COPYING new file mode 100644 index 00000000000..946cb19c31a --- /dev/null +++ b/gnu/usr.sbin/mkisofs/COPYING @@ -0,0 +1,345 @@ + The GPL below is copyrighted by the Free Software + Foundation, but the instance of code that it refers to (the mkisofs + utility is copyrighted by Yggdrasil Computing, Incorporated). + +---------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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 of the License, 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.sbin/mkisofs/ChangeLog b/gnu/usr.sbin/mkisofs/ChangeLog new file mode 100644 index 00000000000..62d713abcff --- /dev/null +++ b/gnu/usr.sbin/mkisofs/ChangeLog @@ -0,0 +1,840 @@ +Wed Mar 19 16:50:17 1997 Fred Fish <fnf@ninemoons.com> + + * Makefile.in (CFLAGS): Let configure set basic flags. Move + compilation option -c to actual CC commands. + (LDFLAGS): Let configure set basic flags. + (Makefile): Depends upon config.status, not configure. + Regenerate if necessary from Makefile.in using config.status. + (configure): Cd to srcdir before running autoconf. + * acconfig.h: New file to hold nonstandard entries used in + config.h.in. Used by autoheader to generate config.h.in. + * config.h.in: Regenerated with autoheader. + * configure.in: Check for existance of sbrk() function. + * configure: Regenerated with autoconf 2.12. + * fnmatch.c (FMN_FILE_NAME): Define if not already defined. + (FNM_LEADING_DIR): Ditto. + (FNM_CASEFOLD): Ditto. + * mkisofs.c (main): Only use sbrk() if system supports it. + +Fri Mar 14 21:54:37 1997 Eric Youngdale <eric@andante.jic.com> + + * Bump version number to 1.10, public release. + + * Put entire thing under RCS. History is buried there now. + + * Fix bug involving empty directories, translation tables and + malloc(0). + +Mon Feb 17 12:44:03 1997 Eric Youngdale <eric@andante.jic.com> + + * Bump version number to 1.10b7. + + * Makefile.in, configure.in, config.in: Change to use GNU autoconf. + + * Configure: Delete old configuration script. + + * tree.c: Fix bug where we had a rename limit of 1000 files + instead of 0x1000. + + * mkisofs.c: Fix sign of timezone offset. Linux iso filesystem + also need to be fixed, unfortunately. + +Tue Dec 3 22:21:21 1996 Eric Youngdale <eric@sub2317.jic.com> + + Fixed a couple of multi-session bugs. Discs now seem to + work on both Solaris and Windows-NT. + + * Bump version number to 1.10b6. + +Tue Dec 3 22:21:21 1996 Eric Youngdale <eric@sub2317.jic.com> + + Multi-session stuff *almost* there. Discs seem to work + under Linux without any problem, but under DOS only + the first session is seen. The patch to write.c + inspired by disc written by Windows generated multi-session + disc, which will hopefully make the discs usable under + DOS as well. + + * Bump version number to 1.10b5. + + * write.c: use size of new session, not total of all sessions + in volume_space_size field. + + * mkisofs.8: Update with current location of cdwrite. + +Mon Nov 4 23:45:01 1996 Eric Youngdale <eric@sub2317.jic.com> + + * Bump version number to 1.10b4. + + * Add cdwrite.c.diff file, which provides a very crude, minimal + interface between mkisofs and cdwrite. It should be enough to + generate a multi-session disc, but it hasn't been tested yet. + +Thu Oct 17 00:39:52 1996 Eric Youngdale <eric@sub2317.jic.com> + + * Bump version number to 1.10b3. + +Wed Oct 16 23:40:44 1996 Michael Fulbright <msf@redhat.com> + + Add support for 'El Torito' specification which allows for bootable + cdroms. + + * Makefile.in: Add eltorito.[c,o]. + + * defaults.h: Add default settings for El Torito related things. + + * iso9660.h: Add structure definitions for El Torito. + + * mkisofs.8: Document new options. + + * mkisofs.c: Add support for new options related to El Torito. + + * mkisofs.h: Add definitions, prototypes as required. + + * tree.c: Add search_tree_file function to search for a specified + file. + + * write.c: Add support for writing special records for El Torito. + + * eltorito.c: New file. + + +Wed Oct 16 23:40:44 1996 Eric Youngdale <eric@sub2317.jic.com> + + * rock.c: Fix bug whereby we made assumptions about how + dev_t was split into major/minor. Use major() and minor() + macros to do this for us, since each system should + do this correctly. + + * write.c: Fix bug whereby abstract, copyright and appid + strings were not properly filled if application ID weren't + in use. + +Sun Sep 29 10:05:10 1996 Eric Youngdale <eric@sub2317.jic.com> + + * Bump version number to 1.10b2. Minor bug fixes here + and there. + +Sun Sep 15 18:54:05 1996 Eric Youngdale <eric@sub2317.jic.com> + + * Bump version number to 1.10b1. Major new functionality is + support for multi-session. Still a bit preliminary, but + most of the pieces are there now. + +Wed Dec 20 16:44:44 1995 Eric Youngdale (eric@andante.aib.com) + + * mkisofs.c, mkisofs.8, Makefile (version_string): Bump to 1.05. + + * rock.c: Bugfix for cases where sizeof(int) == 4 and + sizeof(dev_t) > 4. + + * rock.c: Bugfix for long symbolic links ('/' characters were + being dropped). + + Patches from Peter Miller <pmiller@agso.gov.au>: + + * mkisofs.8: Documentation fix (some versions of nroff don't + like '.' in column 1 if it is not a nroff command). + + * mkisofs.c: Add support for 'rationalize' option. + Similar to rock ridge, except echos of development environment + are removed. + + * write.c Status indicator now indicates percent finished, and + estimated time of completion. + +Sun Feb 26 01:52:06 1995 Eric Youngdale (eric@largo) + + * Add patches from Ross Biro to allow you to merge arbitrary + trees into the image. This is not compiled in by default but + you need to add -DADD_FILES when compiling. + +Fri Feb 17 02:29:03 1995 Paul Eggert <eggert@twinsun.com> + + * tree.c: Port to Solaris 2.4. Prefer <sys/mkdev.h> if + HASMKDEV. Cast unknown integer types to unsigned long and + print them with %lu or %lx. + +Thu Jan 26 15:25:00 1995 H. Peter Anvin (hpa@yggdrasil.com) + + * mkisofs.c: Substitute underscore for leading dot in non-Rock + Ridge filenames, since MS-DOS cannot read files whose names + begin with a period. + +Mon Jan 16 18:31:41 1995 Eric Youngdale (eric@aib.com) + + * rock.c (generate_rock_ridge_attributes): Only use ROOT + record for symlinks if we are at the start of the symlink. + Otherwise just generate an empty entry. + +Mon Jan 16 16:19:50 1995 Eric Youngdale (eric@aib.com) + + * diag/isodump.c: Use isonum_733 instead of trying to dereference + pointers when trying to decode 733 numbers in the iso9660 image. + + * diag/isovfy.c: Likewise. + + * write.c: Always assign an extent number, even for zero length + files. A zero length file with a NULL extent is apparently dropped + by many readers. + +Wed Jan 11 13:46:50 1995 Eric Youngdale (eric@aib.com) + + * mkisofs.c: Modify extension record to conform to IEEE P1282 + specifications. This is commented out right now, but a trivial + change to a #define enables this. I need to see the specs + to see whether anything else changed before this becomes final. + + * write.c (FDECL4): Fix so that we properly determine error + conditions. + + * mkisofs.h: Change rr_attributes to unsigned. + + * tree.c(increment_nlink): Change pnt since rr_attributes is now + unsigned. + + Ultrix patches from petav@argon.e20.physik.tu-muenchen.de (Peter Averkamp) + + * rock.c: Fix for ultrix systems, we have 64 bit device numbers. + Type cast when generating file size. Change rr_attributes to + unsigned. + + * mkisofs.c: For ultrix systems, define our own function + for strdup. + + * mkisofs.c: Fix usage() since some compilers do not concatenate + strings properly (i.e. ultrix). + + Bugs found with Sentinel II: + + * write.c: Fix a couple of memory leaks. + + * mkisofs.c: Bugfix - always put a zero byte at end of name + for ".." entry. + + * tree.c: Set isorec.date from fstatbuf.st_ctime, not current_time, + since current_time might not be set. + +Sat Dec 3 14:55:42 1994 Eric Youngdale (eric@andante) + + * mkisofs.c: When returning entry for ".." file, set second byte + to 0. + + * write.c: Free name and rr_attributes fields when writing. + +Mon Nov 28 13:36:27 1994 Eric Youngdale (eric@andante) + + * mkisofs.h: Change rr_attributes to unsigned. + + * rock.c: Ditto. Work around >>32 bug in ultrix for 64 bit data types. + + * mkisofs.c (usage): Fix for ultrix - use continuation lines + instead of assuming that strings are catenated by the compiler. + +Mon Jun 20 20:25:26 1994 Eric Youngdale (eric@esp22) + + * mkisofs.c, mkisofs.8, Makefile (version_string): Bump to pre-1.02. + + * mkisofs.h: Fix declaration of e_malloc to use DECL macros. + + * tree.c: Fix bug in previous change. + + * diag/*.c: Add appropriate copyright notices. + +Sat Apr 9 13:30:46 1994 Eric Youngdale (ericy@cais.com) + + * Configure: New file - shell script that determines a bunch of + things to properly build mkisofs. + + * Makefile.in: New file - copy of Makefile, but Configure sets a + few things up for it. + + * tree.c: Do not depend upon opendir to return NULL if we cannot + open a directory - actually try and read the first entry. The + foibles of NFS seem to require this. + + * write.c: Fix definition of xfwrite (Use FDECL4) + + Add some changes to allow more configurability of some of the + volume header fields: + + * mkisofs.8: Document new configuration options. + + * mkisofs.c: Add variables to hold new fields. Add function to + read .mkisofsrc files. + + * defaults.h: Another way of configuring the same things. + + Add some changes from Leo Weppelman leo@ahwau.ahold.nl. + + * mkisofs.c: Allow -A to specify application ID. Fix usage(), + getopt and add case switch. + + * rock.c: Fix handling of device numbers (dev_t high should only + be used when sizeof(dev_t) > 32 bits). + + Add a bunch of changes from Manuel Bouyer. + + * diag/Makefile: New file. + + * diag/dump.c, diag/isodump.c: Use termios if system supports it. + + * (throughout): Replace all occurences of "malloc" with e_malloc. + + * mkisofs.c: For NetBSD, attempt to increase the rlimit for + the size of the data segment to about 33 Mb. + + * mkisofs.c (e_malloc): New function. Calls malloc, and prints + nice error message and exits if NULL is returned. + +Sun Jan 23 19:23:57 1994 Eric Youngdale (eric@esp22) + + * mkisofs.c, mkisofs.8, Makefile (version_string): Bump to 1.01. + + Add a bunch of stuff so that mkisofs will work on a VMS system. + + * (ALL): Change any direct use of the "st_ino" field from + the statbuf to use a macro. + + * mkisofs.h: Define appropriate macros for both VMS and unix. + + * (ALL): Add type casts whenever we use the UNCACHED_DEV macro. + + * rock.c: Wrap a #ifndef VMS around block and character device + stuff. + + * write.c: Add prototype for strdup if VMS is defined. + + * make.com: Script for building mkisofs on a VMS system. + + * Makefile: Include make.com in the distribution. + + * mkisofs.c: Include <sys/type.h> on VMS systems. + + * tree.c: Include <sys/file.h> and "vms.h" on VMS systems. + + * mkisofs.h (PATH_SEPARATOR, SPATH_SEPARATOR): New macros + that define the ascii character that separates the last directory + component from the filename. + + * tree.c, mkisofs.c: Use them. + + * vms.c: New file. Contains version of getopt, strdup, opendir, + readdir and closedir. + + * vms.h: New file. Defines S_IS* macros. Define gmtime as + localtime, since gmtime under VMS returns NULL. + +Sat Jan 15 13:57:42 1994 Eric Youngdale (eric@esp22) + + * mkisofs.h (transparent_compression): New prototype. + + * mkisofs.c (transparent_compression): Declare, use + '-z' option to turn on. + + * tree.c: Change TRANS.TBL;1 to TRANS.TBL (version gets + added later, if required). + + * rock.c: If transparent compression requested, verify + file is really suitable (check magic numbers), and extract + correct file length to store in SUSP record. + +Sat Jan 15 01:57:42 1994 Eric Youngdale (eric@esp22) + + * write.c (compare_dirs): Bugfix for patch from Jan 6. + + * mkisofs.h (struct directory_entry): Add element total_rr_attr_size. + (struct file_hash): Add element ce_bytes. + + * write.c (iso_write): Update last_extent_written, as required, + and check it against last_extent as a sanity check. + (generate_one_directory): If ce_bytes is non-zero, allocate + a buffer and fill it with the CE records. Also, update + the extent and offset entries in the CE SUSP field and + output after directory is written. + (assign_directory_addresses): Allow for CE sectors after each + directory. + + * tree.c (sort_n_finish): Set field ce_bytes by summing + the sizes of all CE blocks in each files RR attributes. + Do not count these bytes for main directory. + + * rock.c (generate_rock_ridge_attributes): Generate + CE entries to break up large records into manageable sizes. + Allow long names to be split, and allow long symlinks to be split. + Allow splitting before each SUSP field as well, to make + sure we do not screw outselves. + +Thu Jan 6 21:47:43 1994 Eric Youngdale (eric@esp22) + + Bugfix. + + * write.c (compare_dirs): Only compare directory names up to + the ';' for the version number. + + Add four new options: (1) Full 31 character filenames, + (2) Omit version number, (3) Omit trailing period from filenames, + (4) Skip deep directory relocation. + + * iso9660.h: Allow 34 characters for filename. + + * mkisofs.8: Update for new options. + + * mkisofs.c: Add flag variables for new options. + Mention new options in usage(), tell getopt about + new options, and set appropriate flags when + new options are specified. + + * mkisofs.c (iso9660_file_length): Implement new options. + + * mkisofs.h: Declare flag variables for new options. + + * tree.c (sort_n_finish): Increase declaration of newname and + rootname to 34 characters. If full_iso9660_filenames in effect, + use different rules for making unique names. + + * tree.c (scan_directory_tree): Use RR_relocation_depth instead of + constant for threshold for starting deep directory relocation. + +Wed Jan 5 01:32:34 1994 John Brezak (brezak@ch.hp.com) + + * Makefile.bsd: New file. For NetBSD. + + * rock.c, tree.c: Do not include sys/sysmacros.h for NetBSD. + +Fri Dec 31 13:22:52 1993 Eric Youngdale (eric@esp22) + + * mkisofs.c, mkisofs.8, Makefile (version_string): Bump to 1.00. + + * tree.c (scan_directory_tree): Handle case where we do not + have permissions to open a directory. + + * write.c (xfwrite): New function - wrapper for fwrite, + except that we print message and punt if write fails. + + * write.c: Move include of mkisofs.h and iso9660.h until after + string.h and stdlib.h is included. + + * write.c: Do not attempt to use strerror on sun systems. + +Thu Dec 9 13:17:28 1993 R.-D. Marzusch (marzusch@odiehh.hanse.de) + + * exclude.c, exclude.h: New files. Contains list of files to + exclude from consideration. + + * Makefile: Compile exclude.c, add dependencies to other files. + + * mkisofs.8: Describe -x option. + + * mkisofs.c: Include exclude.h, handle -x option. + + +Fri Dec 10 01:07:43 1993 Peter van der Veen (peterv@qnx.com) + + * mkisofs.c, mkisofs.h: Moved declaration of root_record. + + * mkisofs.h: Added prototype for get_733(). + + * write.c(iso_write), tree.c, rock.c(generate_rock_ridge_attributes): + Added defines for QNX operation system + + * rock.c(generate_rock_ridge_attributes): symbolic links should + not have CONTINUE component flag set unless there are multiple + component records, and mkisofs does not generate these. + st_ctime was stored as the creation time, changed to attribute time. + QNX has a creation time, so that is stored as well under QNX. + +Thu Oct 28 19:54:38 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.99. + + * write.c(iso_write): Put hour, minute, second into date fields in + volume descriptor. + + * write.c (iso_write): Set file_structure_version to 1, instead of + ' ' (Seems to screw up Macs). + +Sun Oct 17 01:13:36 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.98. + + Increment nlink in root directory when rr_moved directory is present. + + * tree.c (increment_nlink): New function. + + * tree.c (finish_cl_pl_entries): Call increment_nlink for all + references to the root directory. + + * tree.c (root_statbuf): New variable. + + * tree.c (scan_directory_tree): Initialize root_statbuf when we + stat the root directory. + + * tree.c (generate_reloc_directory): Use root_statbuf when + generating the Rock Ridge stuff for the ".." entry in the + reloc_dir. + + * tree.c (scan_directory_tree): Use root_statbuf when generating + the ".." entry in the root directory. + +Sat Oct 16 10:28:30 1993 Eric Youngdale (eric@kafka) + + Fix path tables so that they are sorted. + + * tree.c (assign_directory_addresses): Move to write.c + + * write.c (generate_path_tables): Create an array of pointers to + the individual directories, and sort it based upon the name and + the parent path table index. Then update all of the indexes and + repeat the sort until the path table indexes no longer need to be + changed, and then write the path table. + + Fix problem where hard links were throwing off the total extent count. + + * write.c (iso_write): Call assign_file_addresses, and then + use last_extent to determine how big the volume is. + + * write.c (generate_one_directory): Decrement n_data_extents + for hard links to non-directories so that the expected number + of extents is written correctly. + + * write.c(assign_file_addresses): New function. + +Fri Oct 15 22:35:43 1993 Eric Youngdale (eric@kafka) + + The standard says we should do these things: + + * tree.c (generate_reloc_directory): Add RR attributes to + the rr_moved directory. + + * mkisofs.c(main): Change ER text strings back to recommended + values. + +Tue Oct 12 21:07:38 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.97. + + * tree.c (scan_directory_tree): Do not insert PL entry into + root directory record (i.e. !parent) + + * tree.c (finish_cl_pl_entries): Do not rely upon name + comparison to locate parent - use d_entry->self instead, + which is guaranteed to be correct. + + * mkisofs.h: New variable n_data_extents. + + * tree.c: Declare and initialize n_data_extents to 0. + (scan_directory_tree) for non-directories, add + ROUND_UP(statbuf.st_size) to n_data_extents. + (sort_n_finish): Increment n_data_extents for translation tables, + as appropriate. + + * write.c(iso_write): Add n_data_extents to the + volume_space_size field. + + * hash.c(add_hash): If size != 0 and extent == 0, or + if size == 0 and extent != 0, then complain about + inserting this into the hash table. Kind of a sanity check. + +Sat Oct 9 16:39:15 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.96. + + Numerous bugfixes, thanks to a one-off disc from rab@cdrom.com. + + * write.c(generate_one_directory): Wait until after we have + filled in the starting_extent field to s_entry before calling + add_hash. This fixes a problem where the hash table gets an + extent of 0 for all regular files, and this turns up when you have + hard links on the disc. (The hash table allows us to have each + hard link point to the same extent on the cdrom, thereby saving + some space). + + * tree.c(scan_directory_tree): Set statbuf.st_dev and + statbuf.st_ino to the UNCACHED numbers for symlinks that we + are not following. This prevents the function find_hash from + returning an inode that cooresponds to the file the symlink points + to, which in turn prevents generate_one_directory from filling in + a bogus file length (should be zero for symlinks). + + * tree.c(scan_directory_tree): Always call lstat for the file + so that non-RockRidge discs get correct treatment of symlinks. + Improve error message when we ignore a symlink on a non-RR disc. + + * write.c(generate_one_directory): Set fields for starting_extent + and size in the "." and ".." entries before we add them to the + file hash. Fixes problems with incorrect backlinks for second + level directories. + +Wed Oct 6 19:53:40 1993 Eric Youngdale (eric@kafka) + + * write.c (write_one_file): Print message and punt if we are + unable to open the file. + + * tree.c(scan_directory_tree): For regular files, use the access + function to verify that the file is readable in the first place. + If not, issue a warning and skip it. For directories, it probably + does not matter, since we would not be able to descend into them + in the first place. + +Wed Sep 29 00:02:47 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.95. + + * write.c, tree.c: Cosmetic changes to printed information. + + * tree.c(scan_directory_tree): Set size to zero for + special stub entries that correspond to the + relocated directories. Hopefully last big bug. + + * mkisofs.h: Change TABLE_INODE, UNCACHED_* macros + to be 0x7fff... to be compatible with signed datatypes. + +Mon Sep 27 20:14:49 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.94. + + * write.c (write_path_tables): Actually search the + directory for the matching entry in case we renamed + the directory because of a name conflict. + + * tree.c(scan_directory_tree): Take directory_entry pointer + as second argument so that we can create a backpointer + in the directory structure that points back to the original + dir. + + * mkisofs.c: Fix call to scan_directory_tree to use new calling + sequence. + + * write.c(generate_one_directory): Punt if the last_extent counter + ever exceeds 700Mb/2048. Print name of responsible file, + extent counter, and starting extent. Perhaps we can catch it in + the act. + +Sun Sep 26 20:58:05 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.93. + + * tree.c(scan_directory_tree): Handle symlinks better. Either + leave them as symlinks, or erase any trace that they were a + symlink but do not do it 1/2 way as before. Also, watch for + directory loops created with symlinks. + + * mkisofs.h: Add new flag follow_links. + + * mkisofs.c: Add command line switch "-f" to toggle follow_links. + + * mkisofs.8: Document new switch. + + * tree.c: Add code to handle symlinks using new flag. + + * hash.c: Add add_directory_hash, find_directory_hash functions. + + * mkisofs.h: Add prototypes. + +Sat Sep 25 14:26:31 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.92. + + * mkisofs.c: Make sure path is an actual directory before trying + to scan it. + + * mkisofs.h: Add DECL and FDECL? macros for sparc like systems. + Do proper define of optind and optarg under SVr4. + + * tree.c: Change translation table name from YMTRANS.TBL to TRANS.TBL. + + * mkisofs.c: Neaten up message in extension record when RRIP is + in use. + + * Throughout - change all function declarations so that + traditional C compilers (i.e. sparc) will work. + + * Makefile: Change to use system default C compiler. + + * mkisofs.c: Add some stuff so that this will compile under VMS. + Many things missing for VMS still. + + * iso9660.h: Do not use zero length array in struct definition. + + * tree.c (sort_n_finish): Account for this. + + * Change copyright notice. + + +Wed Aug 25 08:06:51 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.91. + + * mkisofs.h: Only include sys/dir.h for linux. Other systems + will need other things. + + * mkisofs.c, tree.c: Include unistd.h. + + * Makefile: Use OBJS to define list of object files. + +Sun Aug 22 20:55:17 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.9. + + * write.c (iso_7*): Fix so that they work properly on Motorola + systems. + +Fri Aug 20 00:14:36 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.8. + + * rock.c: Do not mask off write permissions from posix file modes. + +Wed Aug 18 09:02:12 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.7. + + * rock.c: Do not write NM field for . and .. (redundant and a + waste of space). + + * mkisofs.c: Take -P and -p options for publisher and preparer id + fields. + + * write.c: Store publisher and preparer id in volume + descriptor. + + * rock.c: Write optional SP field to identify SUSP. Write + optional CE field to point to the extension header. + + * tree.c: Request SP and CE fields be added to root directory. + + * tree.c: Fix bug in name conflict resolution. + + * write.c: Fill in date fields in the colume descriptor. + + * write.c (write_one_file): If the file is large enough, write in + chunks of 16 sectors to improve performance. + + * hash.c (add_hash, find_hash, etc): Do not hash s_entry, instead + store relevant info in hash structure (we free s_entry structs as + we write files, and we need to have access to the hash table the + whole way through. + + * write.c: Add a few statistics about directory sizes, RR sizes, + translation table sizes, etc. + + * tree.c: Use major, not MAJOR. Same for minor. Define S_ISSOCK + and S_ISLNK if not defined. + + * rock.c: Define S_ISLNK if not defined. + + * mkisofs.c: Print out max memory usage. Fix bug in call to getopt. + + * mkisofs.c, Makefile (version_string): Bump to 0.6. + + * tree.c: Simplify the calculation of isorec.len, isorec.name_len + and the calculation of the path table sizes by doing it all at + one point after conflict resolution is done. + + * tree.c: scan_directory_tree is now responsible for generating + the line that goes into the YMTRANS.TBL file. These lines are + collected later on into something that will be dumped to the + file. Correctly handle all of the special file types. + +Mon Aug 16 21:59:47 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.5. + + * mkisofs.c: Add -a option (to force all files to be + transferred). Remove find_file_hash stuff. + + * write.c: Pad length even if Rock Ridge is not in use. + + * hash.c: Rewrite hash_file_* stuff so that it can be used to + easily detect (and look up) filenames that have been accepted + for use in this directory. Used for name collision detection. + + * tree.c (sort_n_finish): If two names collide, generate a unique + one (verified with the hash routines). Change the lower priority + name if there is a difference. + + + +Sat Aug 14 13:18:21 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c, Makefile (version_string): Bump to 0.4. + + * tree.c (load_translation_table): New function - read + YMTRANS.TBL. (scan_directory_tree) Call it. + + * mkisofs.c (iso9660_file_length): Call find_file_hash to see + if translated name is specified. If so, use it. + + * hash.c (name_hash, add_file_hash, find_file_hash, + flush_file_hash): New functions for hashing stuff from + YMTRANS.TBL. + + * mkisofs.h: Add a bunch of prototypes for the new functions. + + * mkisofs.8: Update. + + * mkisofs.c, Makefile (version_string): Bump to 0.3. + + * Makefile: Add version number to tar file in dist target. + + * mkisofs.c: Call finish_cl_pl_entries() after directories have + been generated, and extent numbers assigned. + + * write.c (generate_one_directory): Update s_entry->size for + directories (as well as isorec.size). + + * rock.c: Add code to generate CL, PL, and RE entries. The + extent numbers for the CL and PL entries are NULL, and these + are filled in later once we know where they actually belong. + + * mkisofs.h: Add parent_rec to directory_entry. Used to fix CL/PL + stuff. + + * tree.c (scan_directory_tree): Set flag to generate CL/PL/RE + entries as required, update sizes as well. + +Fri Aug 13 19:49:30 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c (version_string): Bump to 0.2. + + * hash.c: Do not use entries with inode == 0xffffffff or dev == + 0xffff. + + * write.c (write_path_tables): Strip leading directory specifications. + + * mkisofs.h: Add definition for reloc_dir symbol. Add prototype + for sort_n_finish, add third parameter to scan_directory_tree + (for true parent, when directories are relocated). + + * mkisofs.c (main): Modify call to scan_directory_tree. Call + sort_n_finish for reloc_dir. + + * tree.c (sort_n_finish): New function - moved code from + scan_directory_tree. + + * tree.c (generate_reloc_directory): New function. Generate + directory to hold relocated directories. + + * tree.c (scan_directory_tree): Strip leading directories when + generating this_dir->name. If depth is too great, then move + directory to reloc_dir (creating if it does not exist, and leave + a dummy (non-directory) entry in the regular directory so that + we can eventually add the required Rock Ridge record. + + * tree.c (scan_directory_tree): Use s_entry instead of sort_dir, + assign to this_dir->contents sooner. + +Thu Aug 12 22:38:17 1993 Eric Youngdale (eric@kafka) + + * mkisofs.c (usage): Fix syntax. + + * mkisofs.c (main): Add new argument to scan_directory_tree + + * tree.c (scan_directory_tree): If directory is at depth 8 or + more, create rr_moved directory in main directory. + +Mon Jul 26 19:45:47 1993 Eric Youngdale (eric@kafka) + + * mkisofs v 0.1 released. + diff --git a/gnu/usr.sbin/mkisofs/Makefile b/gnu/usr.sbin/mkisofs/Makefile new file mode 100644 index 00000000000..9979bfbe608 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 1997/09/15 06:01:53 downsj Exp $ + +PROG= mkisofs +MAN= mkisofs.8 + +SRCS= mkisofs.c tree.c write.c hash.c rock.c exclude.c multi.c \ + files.c fnmatch.c match.c name.c eltorito.c + +CFLAGS+=-DSYSTEM_ID_DEFAULT=\"OpenBSD\" -I${.CURDIR} + +.include <bsd.prog.mk> diff --git a/gnu/usr.sbin/mkisofs/README b/gnu/usr.sbin/mkisofs/README new file mode 100644 index 00000000000..4c1c8c7d351 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/README @@ -0,0 +1,125 @@ +# $OpenBSD: README,v 1.1 1997/09/15 06:01:52 downsj Exp $ +# $From: README,v 1.2 1997/02/23 15:42:18 eric Rel $ +Note: + There is a feature which can be optionally compiled into +mkisofs that allows you to merge arbitrary directory trees into the +image you are creating. You need to compile with -DADD_FILES for my +changes to take effect. Thanks to Ross Biro biro@yggdrasil.com. + + This program requires a lot of virtual memory to run since it +builds all of the directories in memory. The exact requirements +depend upon a lot of things, but for Rock Ridge discs 12Mb would not +be unreasonable. Without RockRidge and without the translation +tables, the requirements would be considerably less. + + The cdwrite utility is maintained separately from mkisofs by +yggdrasil.com. It is enclosed here as a convenience, since the two programs +are often useful together. + +***************************** +Notes for version 1.10b1 + + Big news is that multi-session capability is very close to being + done. There is still a missing interface to cdwrite that is + used to determine the next writable address and the sector number + of the last existing session. Until we get the interface to cdwrite + done, this is a beta version. + + Bug involving DST fixed (dates are always calculated, since some + files may be DST and other ones would not be). + + Unfortunately the notes on some of the small patches got lost. + +***************************** +Notes for version 1.06 + + Jan-Piet Mens <jpm@mens.de> added support for the '-m' switch. This + allows exclusion of shell-style globs from the CDROM. + See manual mkisofs.8 for more information. + +***************************** +Notes for version 1.05 + + Added support for '-r' switch. This is very similar to -R for +Rock Ridge, but echos of the development environment are removed +(i.e. uid/gid set to 0, and permissions of the files are canonicalized). +Useful in applications where a distribution medium is being produced. + +***************************** +Notes for version 1.04 + + No notes for 1.04. + +***************************** +Notes for version 1.03 + + No notes for 1.03. + +***************************** +Notes for version 1.02. + + Minor bugfixes here and there. Support for compiled in +defaults for many of the text fields in the volume header are now +present, and there is also support for a file ".mkisofsrc" that can +also read settings for these parameters. + + A short script "Configure" was added to allow us to set up special +compile options that depend upon the system that we are running on. +This should help stamp out the sphaghetti-isms that were starting to grow +up in various places in the code. + + You should get more meaningful error messages if you run out of +memory. + +***************************** +Notes for version 1.1. + + The big news is that SUSP CE entries are now generated for +extremely long filenames and symlink names. This virtually guarantees +that there is no limit (OK, well, about 600Mb) for file name lengths. +I have tested this as well as I can, and it seems to work with linux. +This would only be used very rarely I suspect. + + Also, I believe that support for VMS is done. You must be +careful, because only Stream-LF and FIxed length record files can be +recorded. The rest are rejected with error messages. Perhaps I am +being too severe here. + + There is a bugfix in the sorting of entries on the disc - we +need to stop comparing once we reach the ';' character. + + There are four new options -z -d -D -l -V. Some of these tell +mkisofs to relax some of the iso9660 restrictions, and many systems +apparently do not really seem to mind. Use these with caution. + + Some diagnostic programs to scan disc images are in the diag +directory. These are not as portable as mkisofs, and may have some +bugs. Still they are useful because they can check for bugs that I might +have introduced as I add new features. + +***************************** +Notes for version 1.0. + + In version 1.0, the date fields in the TF fields were fixed - +previously I was storing st_ctime as the file creation time instead of +the file attribute change time. Thanks to Peter van der Veen for +pointing this out. I have one slight concern with this change, +however. The Young Minds software is definitely supplying 3 dates +(creation, modification and access), and I would strongly suspect that +they are incorrectly putting the file attribute change time in the +file creation slot. I would be curious to see how the different RRIP +filesystems treat this. Anyway, this is something to keep in the back +of your mind. + + The symlink handling was not quite correct in 0.99 - this is +now fixed. Only some systems seemed to have been affected by this bug. + + A command line option is now present to allow you to +specifically exclude certain files from the distribution. + + The case where you do not have permissions to read a directory +is now handled better by mkisofs. The directory that cannot be opened +is converted into a zero-length file, and processing continues normally. + + A few portability things have been fixed (hopefully). + diff --git a/gnu/usr.sbin/mkisofs/README.eltorito b/gnu/usr.sbin/mkisofs/README.eltorito new file mode 100644 index 00000000000..4e78f10ef88 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/README.eltorito @@ -0,0 +1,98 @@ +# $OpenBSD: README.eltorito,v 1.1 1997/09/15 06:01:52 downsj Exp $ +# $From: README.eltorito,v 1.2 1997/02/23 15:44:59 eric Rel $ +What is El Torito? +------------------ +Simply put, El Torito is a specification that says how a cdrom should +be formatted such that you can directly boot from it. + +The "El Torito" spec says that ANY cdrom drive should work (scsi/eide) +as long as the BIOS supports El Torito. So far this has only been +tested with EIDE drives because none of the scsi controllers that has +been tested so far appears to support El Torito. The motherboard +definately has to support El Torito. The ones that do let you choose +booting from HD, Floppy, Network or CDROM. + +How To Make Bootable CDs +------------------------ + +For the x86 platform, many BIOS's have begun to support bootable CDs. +The standard my patches for mkisofs is based on is called "El Torito". + +The "El Torito" standard works by making the CD drive appear, through BIOS +calls, to be a normal floppy drive. This way you simply put an floppy +size image (exactly 1440k for a 1.44 meg floppy) somewhere in the +iso fs. In the headers of the iso fs you place a pointer to this image. +The BIOS will then grab this image from the CD and for all purposes it +acts as if it were booting from the floppy drive. This allows a working +LILO boot disk, for example, to simply be used as is. + +It is simple then to make a bootable CD. First create a file, say "boot.img" +which is an exact image of the boot floppu currently in use. There is +at least one HOWTO on making bootable floppies. If you have a bootable +floppy handy, you can make a boot image with the command + +dd if=/dev/fd0 of=boot.img bs=10k count=144 + +assuming the floppy is in the A: drive. + +Place this image somewhere in the hierarchy which will be the source +for the iso9660 filesystem. It is a good idea to put all boot related +files in their own directory ("boot/" under the root of the iso9660 fs, +for example), but this is not necessary. + +One caveat - Your boot floppy MUST load any initial ramdisk via LILO, +not the kernel ramdisk driver! This is because once the linux kernel +starts up, the BIOS emulation of the CD as a floppy disk is circumvented +and will fail miserably. LILO will load the initial ramdisk using BIOS +disk calls, so the emulation works as designed. + +The "El Torito" specification requires a "boot catalog" to be created as +ll. +This is a 2048 byte file which is of no interest except it is required. +My patches to mkisofs will cause it to automatically create the +boot catalog. You must specify where the boot catalog will go in the +iso9660 filesystem. Usually it is a good idea to put it the same place +as the boot image, and a name like "boot.catalog" seems appropriate. + + +So we have our boot image in the file "boot.image", and we are going to +put it in the directory "boot/" under the root of the iso9660 filesystem. +We will have the boot catalog go in the same directory with the name +"boot.catalog". The command to create the iso9660 fs in the file +bootcd.iso is then + +mkisofs -b boot/boot.imh -c boot/boot.catalog -o bootcd.iso . + +The -b option specifies the boot image to be used (note the path is +relative to the root of the iso9660 disc), and the -c option is +for the boot catalog file. + +Now burn the CD and its ready to boot! + +CAVEATS +------- + +I don't think this will work with multisession CDs. + +If your bootable floppy image needs to access the boot floppy, it has +to do so through BIOS calls. This is because if your O/S tries to talk to +the floppy directly it will bypass the "floppy emulation" the El Torito spec +creates through BIOS. For example, under Linux it is possible to +have an initial RAM disk loaded when the kernel starts up. If you let the +kernel try to read in the initial RAM disk from floppy, it will fail +miserably because Linux is not using BIOS calls to access the floppy drive. +Instead of seeing the floppy image on the CD, Linux will be looking at +the actually floppy drive. + +The solution is to have the initial boot loader, called LILO, load your +initial RAM disk for you. LILO uses BIOS calls entirely for these +operations, so it can grab it from the emulated floppy image. + +I don't think making a CD bootable renders it unreadable by non-El Torito +machines. The El Torito spec uses parts of the iso9660 filesystem which +were reserved for future use, so no existing code should care what it does. + +Mkisofs currently stores identification records in the iso9660 filesystem +saying that the system is a x86 system. The El Torito spec also allows +one to write PowerPC or Mac id's instead. If you look at the code in write.c +you could figure out how to change what is written. diff --git a/gnu/usr.sbin/mkisofs/README.session b/gnu/usr.sbin/mkisofs/README.session new file mode 100644 index 00000000000..a519f019cbe --- /dev/null +++ b/gnu/usr.sbin/mkisofs/README.session @@ -0,0 +1,42 @@ +# $OpenBSD: README.session,v 1.1 1997/09/15 06:01:53 downsj Exp $ +# $From: README.session,v 1.2 1997/02/23 15:45:50 eric Rel $ + + This release of mkisofs has basic support completed for +multiple sessions. At this point, it hasn't been tested thoroughly at all - +we still need some interaction between cdwrite and mkisofs for this to work +correctly. + + There are a few new options to mkisofs to allow for this. +The first one is "-M /dev/scd0", and is used so that mkisofs can examine +the entirety of the previous image so that it can figure out what additional +files need to be written in the new session. + + There is also a temporary hack in mkisofs in the form of a '-C' option. +The -C option takes two numbers as input, which are delimited by commas. +For example, you could specify "-C 1000,1020", but you should never just +make up numbers to use here. These numbers are determined from cdwrite. + + There are patches to cdwrite in the file cdwrite.c.diff, which add +a new information gathering option. To use this, you specify '-m', and +instead of actually writing any data, cdwrite dumps two numbers to stdout +which are comma delimited. These are the same numbers that mkisofs uses +with the -C option. + + Thus in practice you should in principle be able to do something like: + +mkisofs [other options] -C `cdwrite --device /dev/sgX --multi` \ + -M /dev/cdblkdev + +to tie these things together. Admittedly this is a very crude +interface between the two programs right now, and this will be cleaned +up later. For now, it provides the minimal functionality required to write +multiple session discs. + +Note: As of the 1.10b4 release, nobody has actually tried to burn any +discs with this. It is entirely possible that bugs exists, or that +further tweaks will be required somewhere along the way to get things +working correctly. The data gathering mode of cdwrite has been +tested, and I believe it works correctly. Caveat Emptor. + +[Nov 4, 1996]. + diff --git a/gnu/usr.sbin/mkisofs/TODO b/gnu/usr.sbin/mkisofs/TODO new file mode 100644 index 00000000000..b8f377c0d49 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/TODO @@ -0,0 +1,17 @@ +# $OpenBSD: TODO,v 1.1 1997/09/15 06:01:52 downsj Exp $ +# $From: TODO,v 1.2 1997/02/23 15:46:38 eric Rel $ + 1) Allow multiple input paths to be concatenated together. + This is a little tricky, because the directory entries need to be + correctly sorted as per iso9660 specifications. It would be better to + force the user to add hard links or copies of the files rather than do + the wrong thing. Leave alone for the time being, I am not sure that + this feature is really needed. + + 2) For symlinks, we may need to strip out the leading path + information if the link is to an absolute file, and the absolute + address is in the space that we are dumping to the CDROM. Who the + hell knows what we should really do with this, actually. Leave it + for now and see if anyone squalks. + + 3) Find out if output needs to be written at a particular + blocksize or not. diff --git a/gnu/usr.sbin/mkisofs/config.h b/gnu/usr.sbin/mkisofs/config.h new file mode 100644 index 00000000000..3fccfd7a7b9 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/config.h @@ -0,0 +1,54 @@ +/* $OpenBSD: config.h,v 1.1 1997/09/15 06:01:52 downsj Exp $ */ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define if major, minor, and makedev are declared in <mkdev.h>. */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define if major, minor, and makedev are declared in <sysmacros.h>. */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* #undef NODIR */ /* none -- don't make numbered backup files */ + +/* This shows us where to find the major()/minor() macros */ +/* #undef MAJOR_IN_MKDEV */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the sbrk function. */ +#define HAVE_SBRK 1 + +/* Define if you have the <dirent.h> header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the <malloc.h> header file. */ +/* #undef HAVE_MALLOC_H */ + +/* Define if you have the <ndir.h> header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the <sys/dir.h> header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the <sys/mkdev.h> header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define if you have the <sys/ndir.h> header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the <sys/sysmacros.h> header file. */ +/* #undef HAVE_SYS_SYSMACROS_H */ + +/* Define if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the <termios.h> header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 diff --git a/gnu/usr.sbin/mkisofs/defaults.h b/gnu/usr.sbin/mkisofs/defaults.h new file mode 100644 index 00000000000..db740d3771e --- /dev/null +++ b/gnu/usr.sbin/mkisofs/defaults.h @@ -0,0 +1,45 @@ +/* $OpenBSD: defaults.h,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * Header file defaults.h - assorted default values for character strings in + * the volume descriptor. + * + * $From: defaults.h,v 1.4 1997/04/10 03:31:53 eric Rel $ + */ + +#define PREPARER_DEFAULT NULL +#define PUBLISHER_DEFAULT NULL +#define APPID_DEFAULT NULL +#define COPYRIGHT_DEFAULT NULL +#define BIBLIO_DEFAULT NULL +#define ABSTRACT_DEFAULT NULL +#define VOLSET_ID_DEFAULT NULL +#define VOLUME_ID_DEFAULT "CDROM" +#define BOOT_CATALOG_DEFAULT "boot.catalog" +#define BOOT_IMAGE_DEFAULT NULL +#ifdef __QNX__ +#define SYSTEM_ID_DEFAULT "QNX" +#endif + +#ifdef __osf__ +#define SYSTEM_ID_DEFAULT "OSF" +#endif + +#ifdef __sun +#define SYSTEM_ID_DEFAULT "Solaris" +#endif + +#ifdef __hpux +#define SYSTEM_ID_DEFAULT "HP-UX" +#endif + +#ifdef __sgi +#define SYSTEM_ID_DEFAULT "SGI" +#endif + +#ifdef _AIX +#define SYSTEM_ID_DEFAULT "AIX" +#endif + +#ifndef SYSTEM_ID_DEFAULT +#define SYSTEM_ID_DEFAULT "LINUX" +#endif diff --git a/gnu/usr.sbin/mkisofs/diag/README b/gnu/usr.sbin/mkisofs/diag/README new file mode 100644 index 00000000000..92315118f7a --- /dev/null +++ b/gnu/usr.sbin/mkisofs/diag/README @@ -0,0 +1,78 @@ +# $OpenBSD: README,v 1.1 1997/09/15 06:01:53 downsj Exp $ +# +# $From: README,v 1.1 1997/02/23 16:14:56 eric Rel $ +# + I am enclosing 3 test programs that I use to verify the +integrity of an iso9660 disc. The first one (isodump) is pretty +simple - it dumps to the screen the contents of the various +directories. The second one (isovfy) goes through and looks for +problems of one kind or another. + + To use, type something like "./isodump /dev/ramdisk" or +"./isodump /dev/scd0", depending upon where the iso9660 disc is. It +starts by displaying the files in the first sector of the root +directory. It has some pretty simple one letter commands that you +can use to traverse the directory tree. + + a - move back one sector. + b - move forward one sector. + g - go to new logical sector. + q - quit + +The a and b commands do not try and stop you from going past the +beginning or end of a sector, and the g command does not have any way +of knowing whether the sector you request is actually a directory or +not. + + The output is displayed in several columns. The first column +is the total length of the directory record for the file. The second +column (in [] brackets) is the volume number. Next comes the starting +extent number (in hex), and then comes the file size in bytes. Then +cones the filename (not the Rock Ridge version), and this is preceeded +by an "*" if the file is a directory. After this is a summary of the +Rock Ridge fields present along with a display of the translation of +the symbolic link name if the SL Rock Ridge record is present. + + I tailored this program for debugging some of the problems +that I was having earlier. The idea is that you can tailor it +to test for problems that you might be having, so it is not intended +as a be-all and end-all dump program. + + If you move to a sector that does not contain directory +information, the results are unpredictable. + + The second program, isovfy, is run in the same way as isodump, +except that you do not have to do much except let it run. I have it +written to verify all kinds of different things, and as people find +other sorts of problems other tests could be added. + + The third program, dump.c, basically does a hexdump of the cd. +This is screen oriented, and there are some simple commands: + + a - move back one sector. + b - move forward one sector. + f - enter new search string. + + - search forward for search string. + g - go to new logical sector. + q - quit + + + Note that with the 'g' command, sectors are always given in +hex, and represent 2048 byte sectors (as on the cdrom). If you know +how to decode a raw iso9660 directory, you can pick out the starting +extent number from the hexdump and know where to go from there. The +starting extent appears something like 30 bytes prior to the start of +the iso9660 (not Rock Ridge) filename, and it appears in a 7.3.3 +format (meaning that it occupies 8 bytes, 4 in little endian format, +and 4 in big endian format). Thus you should see a mirror image of +the bytes when looking at the extent number. + + The isovfy program can also dump the contents of the path +tables, but this capability is commented out right now. Feel free +to enable this to see what is in the tables. Ultimately I may fix +it so that this checks the integrity of the tables as well. + + The isovfy program gives warnings about things like files that +have a size of 0 but have an extent number assigned. The mkisofs program +should never do this, but the YM software does leave these around. +I think it is probably harmless in the YM case.~ diff --git a/gnu/usr.sbin/mkisofs/diag/dump.c b/gnu/usr.sbin/mkisofs/diag/dump.c new file mode 100644 index 00000000000..be97d711482 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/diag/dump.c @@ -0,0 +1,205 @@ +/* $OpenBSD: dump.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * File dump.c - dump a file/device both in hex and in ASCII. + + 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[] ="$From: dump.c,v 1.2 1997/02/23 19:10:49 eric Rel $"; + +#include "../config.h" + +#include <stdio.h> +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#include <sys/ioctl.h> +#else +#include <termio.h> +#endif +#include <signal.h> + +FILE * infile; +int file_addr; +unsigned char buffer[256]; +unsigned char search[64]; + +#define PAGE 256 + +#ifdef HAVE_TERMIOS_H +struct termios savetty; +struct termios newtty; +#else +struct termio savetty; +struct termio newtty; +#endif + +reset_tty(){ +#ifdef HAVE_TERMIOS_H + if(tcsetattr(0, TCSANOW, &savetty) == -1) +#else + if(ioctl(0, TCSETAF, &savetty)==-1) +#endif + { + printf("cannot put tty into normal mode\n"); + exit(1); + } +} + +set_tty(){ +#ifdef HAVE_TERMIOS_H + if(tcsetattr(0, TCSANOW, &newtty) == -1) +#else + if(ioctl(0, TCSETAF, &newtty)==-1) +#endif + { + printf("cannot put tty into raw mode\n"); + exit(1); + } +} + + +/* Come here when we get a suspend signal from the terminal */ + +void +onsusp (int sig) +{ + /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ + signal(SIGTTOU, SIG_IGN); + reset_tty (); + fflush (stdout); + signal(SIGTTOU, SIG_DFL); + /* Send the TSTP signal to suspend our process group */ + signal(SIGTSTP, SIG_DFL); +/* sigsetmask(0);*/ + kill (0, SIGTSTP); + /* Pause for station break */ + + /* We're back */ + signal (SIGTSTP, onsusp); + set_tty (); +} + + + +crsr2(int row, int col){ + printf("\033[%d;%dH",row,col); +} + +showblock(int flag){ + unsigned int k; + int i, j; + lseek(fileno(infile), file_addr, 0); + read(fileno(infile), buffer, sizeof(buffer)); + if(flag) { + for(i=0;i<16;i++){ + crsr2(i+3,1); + printf("%8.8x ",file_addr+(i<<4)); + for(j=15;j>=0;j--){ + printf("%2.2x",buffer[(i<<4)+j]); + if(!(j & 0x3)) printf(" "); + }; + for(j=0;j< 16;j++){ + k = buffer[(i << 4) + j]; + if(k >= ' ' && k < 0x80) printf("%c",k); + else printf("."); + }; + } + }; + crsr2(20,1); + printf(" Zone, zone offset: %6x %4.4x ",file_addr>>11, file_addr & 0x7ff); + fflush(stdout); +} + +getbyte() +{ + char c1; + c1 = buffer[file_addr & (PAGE-1)]; + file_addr++; + if ((file_addr & (PAGE-1)) == 0) showblock(0); + return c1; +} + +main(int argc, char * argv[]){ + char c; + int nbyte; + int i,j; + if(argc < 2) return 0; + infile = fopen(argv[1],"rb"); + for(i=0;i<30;i++) printf("\n"); + file_addr = 0; +/* Now setup the keyboard for single character input. */ +#ifdef HAVE_TERMIOS_H + if(tcgetattr(0, &savetty) == -1) +#else + if(ioctl(0, TCGETA, &savetty) == -1) +#endif + { + printf("stdin must be a tty\n"); + exit(1); + } + newtty=savetty; + newtty.c_lflag&=~ICANON; + newtty.c_lflag&=~ECHO; + newtty.c_cc[VMIN]=1; + set_tty(); + signal(SIGTSTP, onsusp); + + do{ + if(file_addr < 0) file_addr = 0; + showblock(1); + read (0, &c, 1); + if (c == 'a') file_addr -= PAGE; + if (c == 'b') file_addr += PAGE; + if (c == 'g') { + crsr2(20,1); + printf("Enter new starting block (in hex):"); + scanf("%x",&file_addr); + file_addr = file_addr << 11; + crsr2(20,1); + printf(" "); + }; + if (c == 'f') { + crsr2(20,1); + printf("Enter new search string:"); + fgets(search,sizeof(search),stdin); + while(search[strlen(search)-1] == '\n') search[strlen(search)-1] = 0; + crsr2(20,1); + printf(" "); + }; + if (c == '+') { + while(1==1){ + while(1==1){ + c = getbyte(&file_addr); + if (c == search[0]) break; + }; + for (j=1;j<strlen(search);j++) + if(search[j] != getbyte()) break; + if(j==strlen(search)) break; + }; + file_addr &= ~(PAGE-1); + showblock(1); + }; + if (c == 'q') break; + } while(1==1); + reset_tty(); + fclose(infile); +} + + + + diff --git a/gnu/usr.sbin/mkisofs/diag/isodump.c b/gnu/usr.sbin/mkisofs/diag/isodump.c new file mode 100644 index 00000000000..f15dae69b64 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/diag/isodump.c @@ -0,0 +1,478 @@ +/* $OpenBSD: isodump.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * File isodump.c - dump iso9660 directory information. + * + + 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[] ="$From: isodump.c,v 1.2 1997/02/23 19:11:24 eric Rel $"; + +#include "../config.h" + +#include <stdio.h> +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#include <sys/ioctl.h> +#else +#include <termio.h> +#endif +#include <signal.h> + +FILE * infile; +int file_addr; +unsigned char buffer[2048]; +unsigned char search[64]; +int blocksize; + +#define PAGE sizeof(buffer) + +#define ISODCL(from, to) (to - from + 1) + + +int +isonum_731 (char * p) +{ + return ((p[0] & 0xff) + | ((p[1] & 0xff) << 8) + | ((p[2] & 0xff) << 16) + | ((p[3] & 0xff) << 24)); +} + +int +isonum_721 (char * p) +{ + return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); +} + +int +isonum_723 (char * p) +{ +#if 0 + if (p[0] != p[3] || p[1] != p[2]) { + fprintf (stderr, "invalid format 7.2.3 number\n"); + exit (1); + } +#endif + return (isonum_721 (p)); +} + + +int +isonum_733 (unsigned char * p) +{ + return (isonum_731 (p)); +} + +struct iso_primary_descriptor { + unsigned char type [ISODCL ( 1, 1)]; /* 711 */ + unsigned char id [ISODCL ( 2, 6)]; + unsigned char version [ISODCL ( 7, 7)]; /* 711 */ + unsigned char unused1 [ISODCL ( 8, 8)]; + unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */ + unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */ + unsigned char unused2 [ISODCL ( 73, 80)]; + unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + unsigned char unused3 [ISODCL ( 89, 120)]; + unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */ + unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */ + unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */ + unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */ + unsigned char publisher_id [ISODCL (319, 446)]; /* achars */ + unsigned char preparer_id [ISODCL (447, 574)]; /* achars */ + unsigned char application_id [ISODCL (575, 702)]; /* achars */ + unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */ + unsigned char unused4 [ISODCL (883, 883)]; + unsigned char application_data [ISODCL (884, 1395)]; + unsigned char unused5 [ISODCL (1396, 2048)]; +}; + +struct iso_directory_record { + unsigned char length [ISODCL (1, 1)]; /* 711 */ + unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + unsigned char extent [ISODCL (3, 10)]; /* 733 */ + unsigned char size [ISODCL (11, 18)]; /* 733 */ + unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */ + unsigned char flags [ISODCL (26, 26)]; + unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */ + unsigned char interleave [ISODCL (28, 28)]; /* 711 */ + unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + unsigned char name [1]; +}; + +#ifdef HAVE_TERMIOS_H +struct termios savetty; +struct termios newtty; +#else +struct termio savetty; +struct termio newtty; +#endif + +reset_tty(){ +#ifdef HAVE_TERMIOS_H + if(tcsetattr(0, TCSANOW, &savetty) == -1) +#else + if(ioctl(0, TCSETAF, &savetty)==-1) +#endif + { + printf("cannot put tty into normal mode\n"); + exit(1); + } +} + +set_tty(){ +#ifdef HAVE_TERMIOS_H + if(tcsetattr(0, TCSANOW, &newtty) == -1) +#else + if(ioctl(0, TCSETAF, &newtty)==-1) +#endif + { + printf("cannot put tty into raw mode\n"); + exit(1); + } +} + +/* Come here when we get a suspend signal from the terminal */ + +void +onsusp (int signo) +{ + /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ + signal(SIGTTOU, SIG_IGN); + reset_tty (); + fflush (stdout); + signal(SIGTTOU, SIG_DFL); + /* Send the TSTP signal to suspend our process group */ + signal(SIGTSTP, SIG_DFL); +/* sigsetmask(0);*/ + kill (0, SIGTSTP); + /* Pause for station break */ + + /* We're back */ + signal (SIGTSTP, onsusp); + set_tty (); +} + + + +crsr2(int row, int col){ + printf("\033[%d;%dH",row,col); +} + +int parse_rr(unsigned char * pnt, int len, int cont_flag) +{ + int slen; + int ncount; + int extent; + int cont_extent, cont_offset, cont_size; + int flag1, flag2; + unsigned char *pnts; + char symlink[1024]; + char name[1024]; + int goof; +/* printf(" RRlen=%d ", len); */ + + symlink[0] = 0; + + cont_extent = cont_offset = cont_size = 0; + + ncount = 0; + flag1 = flag2 = 0; + while(len >= 4){ + if(ncount) printf(","); + else printf("["); + printf("%c%c", pnt[0], pnt[1]); + if(pnt[3] != 1) { + printf("**BAD RRVERSION"); + return; + }; + ncount++; + if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff; + if(strncmp(pnt, "PX", 2) == 0) flag2 |= 1; + if(strncmp(pnt, "PN", 2) == 0) flag2 |= 2; + if(strncmp(pnt, "SL", 2) == 0) flag2 |= 4; + if(strncmp(pnt, "NM", 2) == 0) { + slen = pnt[2] - 5; + pnts = pnt+5; + if( (pnt[4] & 6) != 0 ) + { + printf("*"); + } + memset(name, 0, sizeof(name)); + memcpy(name, pnts, slen); + printf("=%s", name); + flag2 |= 8; + } + if(strncmp(pnt, "CL", 2) == 0) flag2 |= 16; + if(strncmp(pnt, "PL", 2) == 0) flag2 |= 32; + if(strncmp(pnt, "RE", 2) == 0) flag2 |= 64; + if(strncmp(pnt, "TF", 2) == 0) flag2 |= 128; + + if(strncmp(pnt, "PX", 2) == 0) { + extent = isonum_733(pnt+12); + printf("=%x", extent); + }; + + if(strncmp(pnt, "CE", 2) == 0) { + cont_extent = isonum_733(pnt+4); + cont_offset = isonum_733(pnt+12); + cont_size = isonum_733(pnt+20); + printf("=[%x,%x,%d]", cont_extent, cont_offset, + cont_size); + }; + + if(strncmp(pnt, "PL", 2) == 0 || strncmp(pnt, "CL", 2) == 0) { + extent = isonum_733(pnt+4); + printf("=%x", extent); + }; + + if(strncmp(pnt, "SL", 2) == 0) { + int cflag; + + cflag = pnt[4]; + pnts = pnt+5; + slen = pnt[2] - 5; + while(slen >= 1){ + switch(pnts[0] & 0xfe){ + case 0: + strncat(symlink, pnts+2, pnts[1]); + break; + case 2: + strcat (symlink, "."); + break; + case 4: + strcat (symlink, ".."); + break; + case 8: + if((pnts[0] & 1) == 0)strcat (symlink, "/"); + break; + case 16: + strcat(symlink,"/mnt"); + printf("Warning - mount point requested"); + break; + case 32: + strcat(symlink,"kafka"); + printf("Warning - host_name requested"); + break; + default: + printf("Reserved bit setting in symlink", goof++); + break; + }; + if((pnts[0] & 0xfe) && pnts[1] != 0) { + printf("Incorrect length in symlink component"); + }; + if((pnts[0] & 1) == 0) strcat(symlink,"/"); + + slen -= (pnts[1] + 2); + pnts += (pnts[1] + 2); + + }; + if(cflag) strcat(symlink, "+"); + printf("=%s", symlink); + symlink[0] = 0; + }; + + len -= pnt[2]; + pnt += pnt[2]; + if(len <= 3 && cont_extent) { + unsigned char sector[2048]; + lseek(fileno(infile), cont_extent * blocksize, 0); + read(fileno(infile), sector, sizeof(sector)); + flag2 |= parse_rr(§or[cont_offset], cont_size, 1); + }; + }; + if(ncount) printf("]"); + if (!cont_flag && flag1 != flag2) + printf("Flag %x != %x", flag1, flag2, goof++); + return flag2; +} + +int +dump_rr(struct iso_directory_record * idr) +{ + int len; + unsigned char * pnt; + + len = idr->length[0] & 0xff; + len -= sizeof(struct iso_directory_record); + len += sizeof(idr->name); + len -= idr->name_len[0]; + pnt = (unsigned char *) idr; + pnt += sizeof(struct iso_directory_record); + pnt -= sizeof(idr->name); + pnt += idr->name_len[0]; + if((idr->name_len[0] & 1) == 0){ + pnt++; + len--; + }; + parse_rr(pnt, len, 0); +} + + +showblock(int flag){ + unsigned int k; + int i, j; + int line; + struct iso_directory_record * idr; + lseek(fileno(infile), file_addr, 0); + read(fileno(infile), buffer, sizeof(buffer)); + for(i=0;i<60;i++) printf("\n"); + fflush(stdout); + i = line = 0; + if(flag) { + while(1==1){ + crsr2(line+3,1); + idr = (struct iso_directory_record *) &buffer[i]; + if(idr->length[0] == 0) break; + printf("%3d ", idr->length[0]); + printf("[%2d] ", idr->volume_sequence_number[0]); + printf("%5x ", isonum_733(idr->extent)); + printf("%8d ", isonum_733(idr->size)); + printf ((idr->flags[0] & 2) ? "*" : " "); + if(idr->name_len[0] == 1 && idr->name[0] == 0) + printf(". "); + else if(idr->name_len[0] == 1 && idr->name[0] == 1) + printf(".. "); + else { + for(j=0; j<idr->name_len[0]; j++) printf("%c", idr->name[j]); + for(j=0; j<14 -idr->name_len[0]; j++) printf(" "); + }; + dump_rr(idr); + printf("\n"); + i += buffer[i]; + if (i > 2048 - sizeof(struct iso_directory_record)) break; + line++; + }; + }; + printf("\n"); + printf(" Zone, zone offset: %6x %4.4x ",file_addr / blocksize, + file_addr & (blocksize - 1)); + fflush(stdout); +} + +getbyte() +{ + char c1; + c1 = buffer[file_addr & (blocksize-1)]; + file_addr++; + if ((file_addr & (blocksize-1)) == 0) showblock(0); + return c1; +} + +main(int argc, char * argv[]){ + char c; + char buffer[2048]; + int nbyte; + int i,j; + struct iso_primary_descriptor ipd; + struct iso_directory_record * idr; + + if(argc < 2) return 0; + infile = fopen(argv[1],"rb"); + + file_addr = 16 << 11; + lseek(fileno(infile), file_addr, 0); + read(fileno(infile), &ipd, sizeof(ipd)); + + idr = (struct iso_directory_record *) &ipd.root_directory_record; + + blocksize = isonum_723(ipd.logical_block_size); + if( blocksize != 512 && blocksize != 1024 && blocksize != 2048 ) + { + blocksize = 2048; + } + + file_addr = isonum_733(idr->extent); + + file_addr = file_addr * blocksize; + +/* Now setup the keyboard for single character input. */ +#ifdef HAVE_TERMIOS_H + if(tcgetattr(0, &savetty) == -1) +#else + if(ioctl(0, TCGETA, &savetty) == -1) +#endif + { + printf("stdin must be a tty\n"); + exit(1); + } + newtty=savetty; + newtty.c_lflag&=~ICANON; + newtty.c_lflag&=~ECHO; + newtty.c_cc[VMIN]=1; + set_tty(); + signal(SIGTSTP, onsusp); + + do{ + if(file_addr < 0) file_addr = 0; + showblock(1); + read (0, &c, 1); + if (c == 'a') file_addr -= blocksize; + if (c == 'b') file_addr += blocksize; + if (c == 'g') { + crsr2(20,1); + printf("Enter new starting block (in hex):"); + scanf("%x",&file_addr); + file_addr = file_addr * blocksize; + crsr2(20,1); + printf(" "); + }; + if (c == 'f') { + crsr2(20,1); + printf("Enter new search string:"); + fgets(search,sizeof(search),stdin); + while(search[strlen(search)-1] == '\n') search[strlen(search)-1] = 0; + crsr2(20,1); + printf(" "); + }; + if (c == '+') { + while(1==1){ + while(1==1){ + c = getbyte(&file_addr); + if (c == search[0]) break; + }; + for (j=1;j<strlen(search);j++) + if(search[j] != getbyte()) break; + if(j==strlen(search)) break; + }; + file_addr &= ~(blocksize-1); + showblock(1); + }; + if (c == 'q') break; + } while(1==1); + reset_tty(); + fclose(infile); +} + + + + diff --git a/gnu/usr.sbin/mkisofs/diag/isoinfo.8 b/gnu/usr.sbin/mkisofs/diag/isoinfo.8 new file mode 100644 index 00000000000..041e5d2af42 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/diag/isoinfo.8 @@ -0,0 +1,125 @@ +.\" $OpenBSD: isoinfo.8,v 1.1 1997/09/15 06:01:53 downsj Exp $ +.\" +.\" $From: isoinfo.8,v 1.1 1997/02/23 19:08:53 eric Rel $ +.\" +.\" -*- nroff -*- +.TH ISOINFO 8 "23 Feb 1997" "Version 1.10b8" +.SH NAME +isoinfo, isovfy, inodump \- Utility programs for dumping and verifying iso9660 +images. +.SH SYNOPSIS +.B isodump +.I isoimage +.PP +.B isoinfo +[ +.B \-R +] +[ +.B \-f +] +[ +.B \-l +] +[ +.B \-T +] +[ +.B \-N +] +[ +.B \-i +.I isoimage +] +[ +.B \-x +.I path +] +.PP +.B isovfy +.I isoimage +.SH DESCRIPTION +.B isodump +is a crude utility to interactively display the contents of iso9660 images +in order to verify directory integrity. The initial screen is a display +of the first part of the root directory, and the prompt shows you the +extent number and offset in the extent. You can use the 'a' and 'b' +commands to move backwards and forwards within the image. The 'g' command +allows you to goto an arbitrary extent, and the 'f' command specifies +a search string to be used. The '+' command searches forward for the next +instance of the search string, and the 'q' command exits +.B isodump. +.PP +.B isoinfo +is a utility to perform directory like listings of iso9660 images. +.PP +.B isovfy +is a utility to verify the integrity of an iso9660 image. Most of the tests +in +.B isovfy +were added after bugs were discovered in early versions of +.B mkisofs. +It isn't all that clear how useful this is anymore, but it doesn't hurt to +have this around. + +.SH OPTIONS +Only the +.B isoinfo +program has any command line options. These are: +.TP +.I -f +generate output as if a 'find . -print' command had been run on the iso9660 +image. You should not use the +.B -l +image with the +.B -f +option. +.TP +.I -i iso_image +Specifies the path of the iso9660 image that we wish to examine. +.TP +.I -l +generate output as if a 'ls -lR' command had been run on the iso9660 image. +You should not use the +.B -f +image with the +.B -l +option. +.TP +.I -N sector +Quick hack to help examine single session disc files that are to be written to +a multi-session disc. The sector number specified is the sector number at +which the iso9660 image should be written when send to the cd-writer. Not +used for the first session on the disc. +.TP +.I \-R +Extract information from Rock Ridge extensions (if present) for permissions, +file names and ownerships. +.TP +.I -T sector +Quick hack to help examine multi-session images that have already been burned +to a multi-session disc. The sector number specified is the sector number for +the start of the session we wish to display. +.TP +.I -x pathname +Extract specified file to stdout. +.SH AUTHOR +Eric Youngdale <ericy@gnu.ai.mit.edu> or <eric@andante.jic.com> is to blame +for these shoddy hacks. Patches to improve general usability would be +gladly accepted. +.SH BUGS +The user interface really sucks. +.SH FUTURE IMPROVEMENTS +These utilities are really quick hacks, which are very useful for debugging +problems in mkisofs or in an iso9660 filesystem. In the long run, it would +be nice to have a daemon that would NFS export a iso9660 image. +.PP +The isoinfo program is probably the program that is of the most use to +the general user. +.SH AVAILABILITY +These utilities come with the mkisofs package, and the primary ftp site +is tsx-11.mit.edu in /pub/linux/BETA/cdrom/mkisofs and many other mirror +sites. Despite the name, the software is not beta. +.SH SEE ALSO +mkisofs(8) + diff --git a/gnu/usr.sbin/mkisofs/diag/isoinfo.c b/gnu/usr.sbin/mkisofs/diag/isoinfo.c new file mode 100644 index 00000000000..f0bc41798d2 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/diag/isoinfo.c @@ -0,0 +1,554 @@ +/* $OpenBSD: isoinfo.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * File isodump.c - dump iso9660 directory information. + * + + 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[] ="$From: isoinfo.c,v 1.2 1997/03/22 02:20:28 eric Rel $"; + +/* + * Simple program to dump contents of iso9660 image in more usable format. + * + * Usage: + * To list contents of image (with or without RR): + * isoinfo -l [-R] -i imagefile + * To extract file from image: + * isoinfo -i imagefile -x xtractfile > outfile + * To generate a "find" like list of files: + * isoinfo -f -i imagefile + */ + +#include "../config.h" + +#include <stdio.h> +#include <signal.h> +#include <sys/stat.h> + +#ifdef __svr4__ +#include <stdlib.h> +#else +extern int optind; +extern char *optarg; +/* extern int getopt (int __argc, char **__argv, char *__optstring); */ +#endif + +FILE * infile; +int use_rock = 0; +int do_listing = 0; +int do_find = 0; +char * xtract = 0; + +struct stat fstat_buf; +char name_buf[256]; +char xname[256]; +unsigned char date_buf[9]; +unsigned int sector_offset = 0; + +unsigned char buffer[2048]; + +#define PAGE sizeof(buffer) + +#define ISODCL(from, to) (to - from + 1) + + +int +isonum_731 (char * p) +{ + return ((p[0] & 0xff) + | ((p[1] & 0xff) << 8) + | ((p[2] & 0xff) << 16) + | ((p[3] & 0xff) << 24)); +} + + +int +isonum_733 (unsigned char * p) +{ + return (isonum_731 (p)); +} + +struct iso_primary_descriptor { + unsigned char type [ISODCL ( 1, 1)]; /* 711 */ + unsigned char id [ISODCL ( 2, 6)]; + unsigned char version [ISODCL ( 7, 7)]; /* 711 */ + unsigned char unused1 [ISODCL ( 8, 8)]; + unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */ + unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */ + unsigned char unused2 [ISODCL ( 73, 80)]; + unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + unsigned char unused3 [ISODCL ( 89, 120)]; + unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */ + unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */ + unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */ + unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */ + unsigned char publisher_id [ISODCL (319, 446)]; /* achars */ + unsigned char preparer_id [ISODCL (447, 574)]; /* achars */ + unsigned char application_id [ISODCL (575, 702)]; /* achars */ + unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */ + unsigned char unused4 [ISODCL (883, 883)]; + unsigned char application_data [ISODCL (884, 1395)]; + unsigned char unused5 [ISODCL (1396, 2048)]; +}; + +struct iso_directory_record { + unsigned char length [ISODCL (1, 1)]; /* 711 */ + unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + unsigned char extent [ISODCL (3, 10)]; /* 733 */ + unsigned char size [ISODCL (11, 18)]; /* 733 */ + unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */ + unsigned char flags [ISODCL (26, 26)]; + unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */ + unsigned char interleave [ISODCL (28, 28)]; /* 711 */ + unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + unsigned char name [1]; +}; + + +int parse_rr(unsigned char * pnt, int len, int cont_flag) +{ + int slen; + int ncount; + int extent; + int cont_extent, cont_offset, cont_size; + int flag1, flag2; + unsigned char *pnts; + char symlink[1024]; + int goof; + + symlink[0] = 0; + + cont_extent = cont_offset = cont_size = 0; + + ncount = 0; + flag1 = flag2 = 0; + while(len >= 4){ + if(pnt[3] != 1) { + printf("**BAD RRVERSION"); + return; + }; + ncount++; + if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff; + if(strncmp(pnt, "PX", 2) == 0) flag2 |= 1; + if(strncmp(pnt, "PN", 2) == 0) flag2 |= 2; + if(strncmp(pnt, "SL", 2) == 0) flag2 |= 4; + if(strncmp(pnt, "NM", 2) == 0) flag2 |= 8; + if(strncmp(pnt, "CL", 2) == 0) flag2 |= 16; + if(strncmp(pnt, "PL", 2) == 0) flag2 |= 32; + if(strncmp(pnt, "RE", 2) == 0) flag2 |= 64; + if(strncmp(pnt, "TF", 2) == 0) flag2 |= 128; + + if(strncmp(pnt, "PX", 2) == 0) { + fstat_buf.st_mode = isonum_733(pnt+4); + fstat_buf.st_nlink = isonum_733(pnt+12); + fstat_buf.st_uid = isonum_733(pnt+20); + fstat_buf.st_gid = isonum_733(pnt+28); + }; + + if(strncmp(pnt, "NM", 2) == 0) { + strncpy(name_buf, pnt+5, pnt[2] - 5); + name_buf[pnt[2] - 5] = 0; + } + + if(strncmp(pnt, "CE", 2) == 0) { + cont_extent = isonum_733(pnt+4); + cont_offset = isonum_733(pnt+12); + cont_size = isonum_733(pnt+20); + }; + + if(strncmp(pnt, "PL", 2) == 0 || strncmp(pnt, "CL", 2) == 0) { + extent = isonum_733(pnt+4); + }; + + if(strncmp(pnt, "SL", 2) == 0) { + int cflag; + + cflag = pnt[4]; + pnts = pnt+5; + slen = pnt[2] - 5; + while(slen >= 1){ + switch(pnts[0] & 0xfe){ + case 0: + strncat(symlink, pnts+2, pnts[1]); + break; + case 2: + strcat (symlink, "."); + break; + case 4: + strcat (symlink, ".."); + break; + case 8: + if((pnts[0] & 1) == 0)strcat (symlink, "/"); + break; + case 16: + strcat(symlink,"/mnt"); + printf("Warning - mount point requested"); + break; + case 32: + strcat(symlink,"kafka"); + printf("Warning - host_name requested"); + break; + default: + printf("Reserved bit setting in symlink", goof++); + break; + }; + if((pnts[0] & 0xfe) && pnts[1] != 0) { + printf("Incorrect length in symlink component"); + }; + if((pnts[0] & 1) == 0) strcat(symlink,"/"); + + slen -= (pnts[1] + 2); + pnts += (pnts[1] + 2); + if(xname[0] == 0) strcpy(xname, "-> "); + strcat(xname, symlink); + }; + symlink[0] = 0; + }; + + len -= pnt[2]; + pnt += pnt[2]; + if(len <= 3 && cont_extent) { + unsigned char sector[2048]; + lseek(fileno(infile), (cont_extent - sector_offset) << 11, 0); + read(fileno(infile), sector, sizeof(sector)); + flag2 |= parse_rr(§or[cont_offset], cont_size, 1); + }; + }; + return flag2; +} + +int +dump_rr(struct iso_directory_record * idr) +{ + int len; + unsigned char * pnt; + + len = idr->length[0] & 0xff; + len -= sizeof(struct iso_directory_record); + len += sizeof(idr->name); + len -= idr->name_len[0]; + pnt = (unsigned char *) idr; + pnt += sizeof(struct iso_directory_record); + pnt -= sizeof(idr->name); + pnt += idr->name_len[0]; + if((idr->name_len[0] & 1) == 0){ + pnt++; + len--; + }; + parse_rr(pnt, len, 0); +} + +struct todo +{ + struct todo * next; + char * name; + int extent; + int length; +}; + +struct todo * todo_idr = NULL; + +char * months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", + "Aug", "Sep", "Oct", "Nov", "Dec"}; + +dump_stat(int extent) +{ + int i; + char outline[80]; + + memset(outline, ' ', sizeof(outline)); + + if(S_ISREG(fstat_buf.st_mode)) + outline[0] = '-'; + else if(S_ISDIR(fstat_buf.st_mode)) + outline[0] = 'd'; + else if(S_ISLNK(fstat_buf.st_mode)) + outline[0] = 'l'; + else if(S_ISCHR(fstat_buf.st_mode)) + outline[0] = 'c'; + else if(S_ISBLK(fstat_buf.st_mode)) + outline[0] = 'b'; + else if(S_ISFIFO(fstat_buf.st_mode)) + outline[0] = 'f'; + else if(S_ISSOCK(fstat_buf.st_mode)) + outline[0] = 's'; + else + outline[0] = '?'; + + memset(outline+1, '-', 9); + if( fstat_buf.st_mode & S_IRUSR ) + outline[1] = 'r'; + if( fstat_buf.st_mode & S_IWUSR ) + outline[2] = 'w'; + if( fstat_buf.st_mode & S_IXUSR ) + outline[3] = 'x'; + + if( fstat_buf.st_mode & S_IRGRP ) + outline[4] = 'r'; + if( fstat_buf.st_mode & S_IWGRP ) + outline[5] = 'w'; + if( fstat_buf.st_mode & S_IXGRP ) + outline[6] = 'x'; + + if( fstat_buf.st_mode & S_IROTH ) + outline[7] = 'r'; + if( fstat_buf.st_mode & S_IWOTH ) + outline[8] = 'w'; + if( fstat_buf.st_mode & S_IXOTH ) + outline[9] = 'x'; + + sprintf(outline+11, "%3d", fstat_buf.st_nlink); + sprintf(outline+15, "%4o", fstat_buf.st_uid); + sprintf(outline+20, "%4o", fstat_buf.st_gid); + sprintf(outline+33, "%8d", fstat_buf.st_size); + + if( date_buf[1] >= 1 && date_buf[1] <= 12 ) + { + memcpy(outline+42, months[date_buf[1]-1], 3); + } + + sprintf(outline+46, "%2d", date_buf[2]); + sprintf(outline+49, "%4d", date_buf[0]+1900); + + sprintf(outline+54, "[%6d]", extent); + + for(i=0; i<63; i++) + if(outline[i] == 0) outline[i] = ' '; + outline[63] = 0; + + printf("%s %s %s\n", outline, name_buf, xname); +} + +extract_file(struct iso_directory_record * idr) +{ + int extent, len, tlen; + unsigned char buff[2048]; + + extent = isonum_733(idr->extent); + len = isonum_733(idr->size); + + while(len > 0) + { + lseek(fileno(infile), (extent - sector_offset) << 11, 0); + tlen = (len > sizeof(buff) ? sizeof(buff) : len); + read(fileno(infile), buff, tlen); + len -= tlen; + extent++; + write(1, buff, tlen); + } +} + +parse_dir(char * rootname, int extent, int len){ + unsigned int k; + char testname[256]; + struct todo * td; + int i, j; + struct iso_directory_record * idr; + + + if( do_listing) + printf("\nDirectory listing of %s\n", rootname); + + while(len > 0 ) + { + lseek(fileno(infile), (extent - sector_offset) << 11, 0); + read(fileno(infile), buffer, sizeof(buffer)); + len -= sizeof(buffer); + extent++; + i = 0; + while(1==1){ + idr = (struct iso_directory_record *) &buffer[i]; + if(idr->length[0] == 0) break; + memset(&fstat_buf, 0, sizeof(fstat_buf)); + name_buf[0] = xname[0] = 0; + fstat_buf.st_size = isonum_733(idr->size); + if( idr->flags[0] & 2) + fstat_buf.st_mode |= S_IFDIR; + else + fstat_buf.st_mode |= S_IFREG; + if(idr->name_len[0] == 1 && idr->name[0] == 0) + strcpy(name_buf, "."); + else if(idr->name_len[0] == 1 && idr->name[0] == 1) + strcpy(name_buf, ".."); + else { + strncpy(name_buf, idr->name, idr->name_len[0]); + name_buf[idr->name_len[0]] = 0; + }; + memcpy(date_buf, idr->date, 9); + if(use_rock) dump_rr(idr); + if( (idr->flags[0] & 2) != 0 + && (idr->name_len[0] != 1 + || (idr->name[0] != 0 && idr->name[0] != 1))) + { + /* + * Add this directory to the todo list. + */ + td = todo_idr; + if( td != NULL ) + { + while(td->next != NULL) td = td->next; + td->next = (struct todo *) malloc(sizeof(*td)); + td = td->next; + } + else + { + todo_idr = td = (struct todo *) malloc(sizeof(*td)); + } + td->next = NULL; + td->extent = isonum_733(idr->extent); + td->length = isonum_733(idr->size); + td->name = (char *) malloc(strlen(rootname) + + strlen(name_buf) + 2); + strcpy(td->name, rootname); + strcat(td->name, name_buf); + strcat(td->name, "/"); + } + else + { + strcpy(testname, rootname); + strcat(testname, name_buf); + if(xtract && strcmp(xtract, testname) == 0) + { + extract_file(idr); + } + } + if( do_find + && (idr->name_len[0] != 1 + || (idr->name[0] != 0 && idr->name[0] != 1))) + { + strcpy(testname, rootname); + strcat(testname, name_buf); + printf("%s\n", testname); + } + if(do_listing) + dump_stat(isonum_733(idr->extent)); + i += buffer[i]; + if (i > 2048 - sizeof(struct iso_directory_record)) break; + } + } +} + +usage() +{ + fprintf(stderr, "isoinfo -i filename [-l] [-R] [-x filename] [-f] [-N nsect]\n"); +} + +main(int argc, char * argv[]){ + int c; + char buffer[2048]; + int nbyte; + char * filename = NULL; + int i,j; + int toc_offset = 0; + struct todo * td; + struct iso_primary_descriptor ipd; + struct iso_directory_record * idr; + + if(argc < 2) return 0; + while ((c = getopt(argc, argv, "i:Rlx:fN:T:")) != EOF) + switch (c) + { + case 'f': + do_find++; + break; + case 'R': + use_rock++; + break; + case 'l': + do_listing++; + break; + case 'T': + /* + * This is used if we have a complete multi-session + * disc that we want/need to play with. + * Here we specify the offset where we want to + * start searching for the TOC. + */ + toc_offset = atol(optarg); + break; + case 'N': + /* + * Use this if we have an image of a single session + * and we need to list the directory contents. + * This is the session block number of the start + * of the session. + */ + sector_offset = atol(optarg); + break; + case 'i': + filename = optarg; + break; + case 'x': + xtract = optarg; + break; + default: + usage(); + exit(1); + } + + if( filename == NULL ) + { + fprintf(stderr, "Error - file not specified\n"); + exit(1); + } + + infile = fopen(filename,"rb"); + + if( infile == NULL ) + { + fprintf(stderr,"Unable to open file %s\n", filename); + exit(1); + } + + /* + * Absolute sector offset, so don't subtract sector_offset here. + */ + lseek(fileno(infile), (16 + toc_offset) <<11, 0); + read(fileno(infile), &ipd, sizeof(ipd)); + + idr = (struct iso_directory_record *) &ipd.root_directory_record; + + parse_dir("/", isonum_733(idr->extent), isonum_733(idr->size)); + td = todo_idr; + while(td) + { + parse_dir(td->name, td->extent, td->length); + td = td->next; + } + + fclose(infile); +} + + + + diff --git a/gnu/usr.sbin/mkisofs/diag/isovfy.c b/gnu/usr.sbin/mkisofs/diag/isovfy.c new file mode 100644 index 00000000000..f10447889f3 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/diag/isovfy.c @@ -0,0 +1,514 @@ +/* $OpenBSD: isovfy.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * File isovfy.c - verify consistency of 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[] ="$From: isovfy.c,v 1.2 1997/02/23 19:13:23 eric Rel $"; + +#include <stdio.h> +#include <signal.h> + +FILE * infile; +int blocksize; + +#define PAGE sizeof(buffer) + +#define ISODCL(from, to) (to - from + 1) + +struct iso_primary_descriptor { + unsigned char type [ISODCL ( 1, 1)]; /* 711 */ + unsigned char id [ISODCL ( 2, 6)]; + unsigned char version [ISODCL ( 7, 7)]; /* 711 */ + unsigned char unused1 [ISODCL ( 8, 8)]; + unsigned char system_id [ISODCL ( 9, 40)]; /* aunsigned chars */ + unsigned char volume_id [ISODCL ( 41, 72)]; /* dunsigned chars */ + unsigned char unused2 [ISODCL ( 73, 80)]; + unsigned char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + unsigned char unused3 [ISODCL ( 89, 120)]; + unsigned char volume_set_size [ISODCL (121, 124)]; /* 723 */ + unsigned char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + unsigned char logical_block_size [ISODCL (129, 132)]; /* 723 */ + unsigned char path_table_size [ISODCL (133, 140)]; /* 733 */ + unsigned char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + unsigned char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + unsigned char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + unsigned char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + unsigned char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + unsigned char volume_set_id [ISODCL (191, 318)]; /* dunsigned chars */ + unsigned char publisher_id [ISODCL (319, 446)]; /* achars */ + unsigned char preparer_id [ISODCL (447, 574)]; /* achars */ + unsigned char application_id [ISODCL (575, 702)]; /* achars */ + unsigned char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + unsigned char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + unsigned char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + unsigned char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + unsigned char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + unsigned char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + unsigned char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + unsigned char file_structure_version [ISODCL (882, 882)]; /* 711 */ + unsigned char unused4 [ISODCL (883, 883)]; + unsigned char application_data [ISODCL (884, 1395)]; + unsigned char unused5 [ISODCL (1396, 2048)]; +}; + +struct iso_directory_record { + unsigned char length [ISODCL (1, 1)]; /* 711 */ + unsigned char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + unsigned char extent [ISODCL (3, 10)]; /* 733 */ + unsigned char size [ISODCL (11, 18)]; /* 733 */ + unsigned char date [ISODCL (19, 25)]; /* 7 by 711 */ + unsigned char flags [ISODCL (26, 26)]; + unsigned char file_unit_size [ISODCL (27, 27)]; /* 711 */ + unsigned char interleave [ISODCL (28, 28)]; /* 711 */ + unsigned char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + unsigned char name [38]; +}; + +int +isonum_723 (char * p) +{ +#if 0 + if (p[0] != p[3] || p[1] != p[2]) { + fprintf (stderr, "invalid format 7.2.3 number\n"); + exit (1); + } +#endif + return (isonum_721 (p)); +} + +int +isonum_721 (char * p) +{ + return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); +} + +int +isonum_711 (char * p) +{ + return (*p & 0xff); +} + +int +isonum_731 (char * p) +{ + return ((p[0] & 0xff) + | ((p[1] & 0xff) << 8) + | ((p[2] & 0xff) << 16) + | ((p[3] & 0xff) << 24)); +} + +int +isonum_722 (char * p) +{ + return ((p[1] & 0xff) + | ((p[0] & 0xff) << 8)); +} + +int +isonum_732 (char * p) +{ + return ((p[3] & 0xff) + | ((p[2] & 0xff) << 8) + | ((p[1] & 0xff) << 16) + | ((p[0] & 0xff) << 24)); +} + +int +isonum_733 (unsigned char * p) +{ + return (isonum_731 (p)); +} + +char lbuffer[1024]; +int iline; +int rr_goof; + + +int +dump_rr(struct iso_directory_record * idr){ + int len; + char * pnt; + + len = idr->length[0] & 0xff; + len -= (sizeof(struct iso_directory_record) - sizeof(idr->name)); + len -= idr->name_len[0]; + pnt = (char *) idr; + pnt += (sizeof(struct iso_directory_record) - sizeof(idr->name)); + pnt += idr->name_len[0]; + + if((idr->name_len[0] & 1) == 0){ + pnt++; + len--; + }; + + rr_goof = 0; + parse_rr(pnt, len, 0); + return rr_goof; +} + +int parse_rr(unsigned char * pnt, int len, int cont_flag) +{ + int slen; + int ncount; + int flag1, flag2; + int extent; + unsigned char *pnts; + int cont_extent, cont_offset, cont_size; + char symlink[1024]; + iline += sprintf(lbuffer+iline," RRlen=%d ", len); + + cont_extent = cont_offset = cont_size = 0; + + symlink[0] = 0; + + ncount = 0; + flag1 = flag2 = 0; + while(len >= 4){ + if(ncount) iline += sprintf(lbuffer+iline,","); + else iline += sprintf(lbuffer+iline,"["); + iline += sprintf(lbuffer+iline,"%c%c", pnt[0], pnt[1]); + + if(pnt[0] < 'A' || pnt[0] > 'Z' || pnt[1] < 'A' || + pnt[1] > 'Z') { + iline += sprintf(lbuffer+iline,"**BAD SUSP %d %d]", + pnt[0], pnt[1], rr_goof++); + return flag2; + }; + + if(pnt[3] != 1) { + iline += sprintf(lbuffer+iline,"**BAD RRVERSION", rr_goof++); + return flag2; + }; + ncount++; + if(pnt[0] == 'R' && pnt[1] == 'R') flag1 = pnt[4] & 0xff; + if(strncmp(pnt, "PX", 2) == 0) flag2 |= 1; + if(strncmp(pnt, "PN", 2) == 0) flag2 |= 2; + if(strncmp(pnt, "SL", 2) == 0) flag2 |= 4; + if(strncmp(pnt, "NM", 2) == 0) flag2 |= 8; + if(strncmp(pnt, "CL", 2) == 0) flag2 |= 16; + if(strncmp(pnt, "PL", 2) == 0) flag2 |= 32; + if(strncmp(pnt, "RE", 2) == 0) flag2 |= 64; + if(strncmp(pnt, "TF", 2) == 0) flag2 |= 128; + + if(strncmp(pnt, "CE", 2) == 0) { + cont_extent = isonum_733(pnt+4); + cont_offset = isonum_733(pnt+12); + cont_size = isonum_733(pnt+20); + iline += sprintf(lbuffer+iline, "=[%x,%x,%d]", + cont_extent, cont_offset, cont_size); + }; + + if(strncmp(pnt, "PL", 2) == 0 || strncmp(pnt, "CL", 2) == 0) { + extent = isonum_733(pnt+4); + iline += sprintf(lbuffer+iline,"=%x", extent); + if(extent == 0) rr_goof++; + }; + if(strncmp(pnt, "SL", 2) == 0) { + pnts = pnt+5; + slen = pnt[2] - 5; + while(slen >= 1){ + switch(pnts[0] & 0xfe){ + case 0: + strncat(symlink, pnts+2, pnts[1]); + break; + case 2: + strcat (symlink, "."); + break; + case 4: + strcat (symlink, ".."); + break; + case 8: + strcat (symlink, "/"); + break; + case 16: + strcat(symlink,"/mnt"); + iline += sprintf(lbuffer+iline,"Warning - mount point requested"); + break; + case 32: + strcat(symlink,"kafka"); + iline += sprintf(lbuffer+iline,"Warning - host_name requested"); + break; + default: + iline += sprintf(lbuffer+iline,"Reserved bit setting in symlink", rr_goof++); + break; + }; + if((pnts[0] & 0xfe) && pnts[1] != 0) { + iline += sprintf(lbuffer+iline,"Incorrect length in symlink component"); + }; + if((pnts[0] & 1) == 0) + strcat(symlink,"/"); + slen -= (pnts[1] + 2); + pnts += (pnts[1] + 2); + + }; + if(symlink[0] != 0) { + iline += sprintf(lbuffer+iline,"=%s", symlink); + symlink[0] = 0; + } + }; + + len -= pnt[2]; + pnt += pnt[2]; + if(len <= 3 && cont_extent) { + unsigned char sector[2048]; + lseek(fileno(infile), cont_extent * blocksize, 0); + read(fileno(infile), sector, sizeof(sector)); + flag2 |= parse_rr(§or[cont_offset], cont_size, 1); + }; + }; + if(ncount) iline += sprintf(lbuffer+iline,"]"); + if (!cont_flag && flag1 && flag1 != flag2) + iline += sprintf(lbuffer+iline,"Flag %x != %x", flag1, flag2, rr_goof++); + return flag2; +} + + +int dir_count = 0; +int dir_size_count = 0; +int ngoof = 0; + + +check_tree(int file_addr, int file_size, int parent_addr){ + unsigned char buffer[2048]; + unsigned int k; + int rflag; + int i, i1, j, goof; + int extent, size; + int line; + int orig_file_addr, parent_file_addr; + struct iso_directory_record * idr; + + i1 = 0; + + orig_file_addr = file_addr / blocksize; /* Actual extent of this directory */ + parent_file_addr = parent_addr / blocksize; + + if((dir_count % 100) == 0) printf("[%d %d]\n", dir_count, dir_size_count); +#if 0 + printf("Starting directory %d %d %d\n", file_addr, file_size, parent_addr); +#endif + + dir_count++; + dir_size_count += file_size / blocksize; + + if(file_size & 0x3ff) printf("********Directory has unusual size\n"); + + for(k=0; k < (file_size / sizeof(buffer)); k++){ + lseek(fileno(infile), file_addr, 0); + read(fileno(infile), buffer, sizeof(buffer)); + i = 0; + while(1==1){ + goof = iline=0; + idr = (struct iso_directory_record *) &buffer[i]; + if(idr->length[0] == 0) break; + iline += sprintf(&lbuffer[iline],"%3d ", idr->length[0]); + extent = isonum_733(idr->extent); + size = isonum_733(idr->size); + iline += sprintf(&lbuffer[iline],"%5x ", extent); + iline += sprintf(&lbuffer[iline],"%8d ", size); + iline += sprintf (&lbuffer[iline], "%c", (idr->flags[0] & 2) ? '*' : ' '); + + if(idr->name_len[0] > 33) + iline += sprintf(&lbuffer[iline],"File name length=(%d)", + idr->name_len[0], goof++); + else if(idr->name_len[0] == 1 && idr->name[0] == 0) { + iline += sprintf(&lbuffer[iline],". "); + rflag = 0; + if(orig_file_addr !=isonum_733(idr->extent) + isonum_711(idr->ext_attr_length)) + iline += sprintf(&lbuffer[iline],"***** Directory has null extent.", goof++); + if(i1) + iline += sprintf(&lbuffer[iline],"***** . not first entry.", rr_goof++); + } else if(idr->name_len[0] == 1 && idr->name[0] == 1) { + iline += sprintf(&lbuffer[iline],".. "); + rflag = 0; + if(parent_file_addr !=isonum_733(idr->extent) + isonum_711(idr->ext_attr_length)) + iline += sprintf(&lbuffer[iline],"***** Directory has null extent.", goof++); + if(i1 != 1) + iline += sprintf(&lbuffer[iline],"***** .. not second entry.", rr_goof++); + + } else { + if(i1 < 2) iline += sprintf(&lbuffer[iline]," Improper sorting.", rr_goof++); + for(j=0; j<idr->name_len[0]; j++) iline += sprintf(&lbuffer[iline],"%c", idr->name[j]); + for(j=0; j<14 -idr->name_len[0]; j++) iline += sprintf(&lbuffer[iline]," "); + rflag = 1; + }; + + if(size && extent == 0) iline += sprintf(&lbuffer[iline],"****Extent==0, size != 0", goof++); +#if 0 + /* This is apparently legal. */ + if(size == 0 && extent) iline += sprintf(&lbuffer[iline],"****Extent!=0, size == 0", goof++); +#endif + + if(idr->flags[0] & 0xf5) + iline += sprintf(&lbuffer[iline],"Flags=(%x) ", idr->flags[0], goof++); + + if(idr->interleave[0]) + iline += sprintf(&lbuffer[iline],"Interleave=(%d) ", idr->interleave[0], goof++); + + if(idr->file_unit_size[0]) + iline += sprintf(&lbuffer[iline],"File unit size=(%d) ", idr->file_unit_size[0], goof++); + + if(idr->volume_sequence_number[0] != 1) + iline += sprintf(&lbuffer[iline],"Volume sequence number=(%d) ", idr->volume_sequence_number[0], goof++); + + goof += dump_rr(idr); + iline += sprintf(&lbuffer[iline],"\n"); + + + if(goof){ + ngoof++; + lbuffer[iline++] = 0; + printf("%x: %s", orig_file_addr, lbuffer); + }; + + + + if(rflag && (idr->flags[0] & 2)) check_tree((isonum_733(idr->extent) + isonum_711(idr->ext_attr_length)) * blocksize, + isonum_733(idr->size), + orig_file_addr * blocksize); + i += buffer[i]; + i1++; + if (i > 2048 - sizeof(struct iso_directory_record)) break; + }; + file_addr += sizeof(buffer); + }; + fflush(stdout); +} + + +/* This function simply dumps the contents of the path tables. No + consistency checking takes place, although this would proably be a good + idea. */ + +struct path_table_info{ + char * name; + unsigned int extent; + unsigned short index; + unsigned short parent; +}; + + +check_path_tables(int typel_extent, int typem_extent, int path_table_size){ + int file_addr; + int count; + int j; + char * pnt; + char * typel, *typem; + + /* Now read in the path tables */ + + typel = (char *) malloc(path_table_size); + lseek(fileno(infile), typel_extent * blocksize, 0); + read(fileno(infile), typel, path_table_size); + + typem = (char *) malloc(path_table_size); + lseek(fileno(infile), typem_extent * blocksize, 0); + read(fileno(infile), typem, path_table_size); + + j = path_table_size; + pnt = typel; + count = 1; + while(j){ + int namelen, extent, index; + char name[32]; + namelen = *pnt++; pnt++; + extent = isonum_731(pnt); pnt += 4; + index = isonum_721(pnt); pnt+= 2; + j -= 8+namelen; + memset(name, 0, sizeof(name)); + + strncpy(name, pnt, namelen); + pnt += namelen; + if(j & 1) { j--; pnt++;}; + printf("%4.4d %4.4d %8.8x %s\n",count++, index, extent, name); + }; + + j = path_table_size; + pnt = typem; + count = 1; + while(j){ + int namelen, extent, index; + char name[32]; + namelen = *pnt++; pnt++; + extent = isonum_732(pnt); pnt += 4; + index = isonum_722(pnt); pnt+= 2; + j -= 8+namelen; + memset(name, 0, sizeof(name)); + + strncpy(name, pnt, namelen); + pnt += namelen; + if(j & 1) { j--; pnt++;}; + printf("%4.4d %4.4d %8.8x %s\n", count++, index, extent, name); + }; + +} + +main(int argc, char * argv[]){ + int file_addr, file_size; + char c; + int nbyte; + struct iso_primary_descriptor ipd; + struct iso_directory_record * idr; + int typel_extent, typem_extent; + int path_table_size; + int i,j; + if(argc < 2) return 0; + infile = fopen(argv[1],"rb"); + + + file_addr = 32768; + lseek(fileno(infile), file_addr, 0); + read(fileno(infile), &ipd, sizeof(ipd)); + + idr = (struct iso_directory_record *) &ipd.root_directory_record; + + blocksize = isonum_723(ipd.logical_block_size); + if( blocksize != 512 && blocksize != 1024 && blocksize != 2048 ) + { + blocksize = 2048; + } + + file_addr = isonum_733(idr->extent) + isonum_711(idr->ext_attr_length); + file_size = isonum_733(idr->size); + + printf("Root at extent %x, %d bytes\n", file_addr, file_size); + file_addr = file_addr * blocksize; + + check_tree(file_addr, file_size, file_addr); + + typel_extent = isonum_731(ipd.type_l_path_table); + typem_extent = isonum_732(ipd.type_m_path_table); + path_table_size = isonum_733(ipd.path_table_size); + + /* Enable this to get the dump of the path tables */ +#if 0 + check_path_tables(typel_extent, typem_extent, path_table_size); +#endif + + fclose(infile); + + if(!ngoof) printf("No errors found\n"); +} + + + + diff --git a/gnu/usr.sbin/mkisofs/eltorito.c b/gnu/usr.sbin/mkisofs/eltorito.c new file mode 100644 index 00000000000..1f91eb8d1c7 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/eltorito.c @@ -0,0 +1,262 @@ +/* $OpenBSD: eltorito.c,v 1.1 1997/09/15 06:01:52 downsj Exp $ */ +/* + * Program eltorito.c - Handle El Torito specific extensions to iso9660. + * + + Written by Michael Fulbright <msf@redhat.com> (1996). + + Copyright 1996 RedHat Software, 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[] ="$From: eltorito.c,v 1.5 1997/03/08 17:27:01 eric Rel $"; + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +#include "mkisofs.h" +#include "iso9660.h" + +static struct eltorito_validation_entry valid_desc; +static struct eltorito_defaultboot_entry default_desc; + +/* + * Check for presence of boot catalog. If it does not exist then make it + */ +void FDECL1(init_boot_catalog, const char *, path) +{ + + int bcat; + char * bootpath; /* filename of boot catalog */ + char * buf; + struct stat statbuf; + + bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2); + strcpy(bootpath, path); + if (bootpath[strlen(bootpath)-1] != '/') + { + strcat(bootpath,"/"); + } + + strcat(bootpath, boot_catalog); + + /* + * check for the file existing + */ +#ifdef DEBUG_TORITO + printf("Looking for boot catalog file %s\n",bootpath); +#endif + + if (!stat_filter(bootpath, &statbuf)) + { + /* + * make sure its big enough to hold what we want + */ + if (statbuf.st_size == 2048) + { + /* + * printf("Boot catalog exists, so we do nothing\n"); + */ + free(bootpath); + return; + } + else + { + fprintf(stderr, "A boot catalog exists and appears corrupted.\n"); + fprintf(stderr, "Please check the following file: %s.\n",bootpath); + fprintf(stderr, "This file must be removed before a bootable CD can be done.\n"); + free(bootpath); + exit(1); + } + } + + /* + * file does not exist, so we create it + * make it one CD sector long + */ + bcat = open(bootpath, O_WRONLY | O_CREAT, S_IROTH | S_IRGRP | S_IRWXU ); + if (bcat == -1) + { + fprintf(stderr, "Error creating boot catalog, exiting...\n"); + perror(""); + exit(1); + } + + buf = (char *) e_malloc( 2048 ); + write(bcat, buf, 2048); + close(bcat); + free(bootpath); +} /* init_boot_catalog(... */ + +void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) +{ + int bootcat; + int checksum; + unsigned char * checksum_ptr; + struct directory_entry * de; + struct directory_entry * de2; + int i; + int nsectors; + + memset(boot_desc, 0, sizeof(*boot_desc)); + boot_desc->id[0] = 0; + memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); + boot_desc->version[0] = 1; + + memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID)); + + /* + * search from root of iso fs to find boot catalog + */ + de2 = search_tree_file(root, boot_catalog); + if (!de2) + { + fprintf(stderr,"Uh oh, I cant find the boot catalog!\n"); + exit(1); + } + + set_731(boot_desc->bootcat_ptr, + (unsigned int) get_733(de2->isorec.extent)); + + /* + * now adjust boot catalog + * lets find boot image first + */ + de=search_tree_file(root, boot_image); + if (!de) + { + fprintf(stderr,"Uh oh, I cant find the boot image!\n"); + exit(1); + } + + /* + * we have the boot image, so write boot catalog information + * Next we write out the primary descriptor for the disc + */ + memset(&valid_desc, 0, sizeof(valid_desc)); + valid_desc.headerid[0] = 1; + valid_desc.arch[0] = EL_TORITO_ARCH_x86; + + /* + * we'll shove start of publisher id into id field, may get truncated + * but who really reads this stuff! + */ + if (publisher) + memcpy_max(valid_desc.id, publisher, strlen(publisher)); + + valid_desc.key1[0] = 0x55; + valid_desc.key2[0] = 0xAA; + + /* + * compute the checksum + */ + checksum=0; + checksum_ptr = (unsigned char *) &valid_desc; + for (i=0; i<sizeof(valid_desc); i+=2) + { + /* + * skip adding in ckecksum word, since we dont have it yet! + */ + if (i == 28) + { + continue; + } + checksum += (unsigned int)checksum_ptr[i]; + checksum += ((unsigned int)checksum_ptr[i+1])*256; + } + + /* + * now find out the real checksum + */ + checksum = -checksum; + set_721(valid_desc.cksum, (unsigned int) checksum); + + /* + * now make the initial/default entry for boot catalog + */ + memset(&default_desc, 0, sizeof(default_desc)); + default_desc.boot_id[0] = EL_TORITO_BOOTABLE; + + /* + * use default BIOS loadpnt + */ + set_721(default_desc.loadseg, 0); + default_desc.arch[0] = EL_TORITO_ARCH_x86; + + /* + * figure out size of boot image in sectors, for now hard code to + * assume 512 bytes/sector on a bootable floppy + */ + nsectors = ((de->size + 511) & ~(511))/512; + printf("\nSize of boot image is %d sectors -> ", nsectors); + + /* + * choose size of emulated floppy based on boot image size + */ + if (nsectors == 2880 ) + { + default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP; + printf("Emulating a 1.44 meg floppy\n"); + } + else if (nsectors == 5760 ) + { + default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP; + printf("Emulating a 2.88 meg floppy\n"); + } + else if (nsectors == 2400 ) + { + default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP; + printf("Emulating a 1.2 meg floppy\n"); + } + else + { + fprintf(stderr,"\nError - boot image is not the an allowable size.\n"); + exit(1); + } + + + /* + * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT!!! + */ + nsectors = 1; + set_721(default_desc.nsect, (unsigned int) nsectors ); +#ifdef DEBUG_TORITO + printf("Extent of boot images is %d\n",get_733(de->isorec.extent)); +#endif + set_731(default_desc.bootoff, + (unsigned int) get_733(de->isorec.extent)); + + /* + * now write it to disk + */ + bootcat = open(de2->whole_name, O_RDWR); + if (bootcat == -1) + { + fprintf(stderr,"Error opening boot catalog for update.\n"); + perror(""); + exit(1); + } + + /* + * write out + */ + write(bootcat, &valid_desc, 32); + write(bootcat, &default_desc, 32); + close(bootcat); +} /* get_torito_desc(... */ diff --git a/gnu/usr.sbin/mkisofs/exclude.c b/gnu/usr.sbin/mkisofs/exclude.c new file mode 100644 index 00000000000..0ce5a79a250 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/exclude.c @@ -0,0 +1,57 @@ +/* $OpenBSD: exclude.c,v 1.1 1997/09/15 06:01:52 downsj Exp $ */ +/* + * 9-Dec-93 R.-D. Marzusch, marzusch@odiehh.hanse.de: + * added 'exclude' option (-x) to specify pathnames NOT to be included in + * CD image. + */ + +static char rcsid[] ="$From: exclude.c,v 1.2 1997/02/23 16:12:34 eric Rel $"; + +#include <stdio.h> +#ifndef VMS +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#else +#include <stdlib.h> +#endif +#endif +#include <string.h> + +/* this allows for 1000 entries to be excluded ... */ +#define MAXEXCL 1000 +static char * excl[MAXEXCL]; + +void exclude(fn) +char * fn; +{ + register int i; + + for (i=0; excl[i] && i<MAXEXCL; i++); + if (i == MAXEXCL) { + fprintf(stderr,"Can't exclude '%s' - too many entries in table\n",fn); + return; + } + + + excl[i] = (char *) malloc(strlen(fn)+1); + if (! excl[i]) { + fprintf(stderr,"Can't allocate memory for excluded filename\n"); + return; + } + + strcpy(excl[i],fn); +} + +int is_excluded(fn) +char * fn; +{ + /* very dumb search method ... */ + register int i; + + for (i=0; excl[i] && i<MAXEXCL; i++) { + if (strcmp(excl[i],fn) == 0) { + return 1; /* found -> excluded filenmae */ + } + } + return 0; /* not found -> not excluded */ +} diff --git a/gnu/usr.sbin/mkisofs/exclude.h b/gnu/usr.sbin/mkisofs/exclude.h new file mode 100644 index 00000000000..3488b55c7cb --- /dev/null +++ b/gnu/usr.sbin/mkisofs/exclude.h @@ -0,0 +1,11 @@ +/* $OpenBSD: exclude.h,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * 9-Dec-93 R.-D. Marzusch, marzusch@odiehh.hanse.de: + * added 'exclude' option (-x) to specify pathnames NOT to be included in + * CD image. + * + * $From: exclude.h,v 1.1 1997/02/23 15:53:19 eric Rel $ + */ + +void exclude(); +int is_excluded(); diff --git a/gnu/usr.sbin/mkisofs/files.c b/gnu/usr.sbin/mkisofs/files.c new file mode 100644 index 00000000000..4026ab8dcbb --- /dev/null +++ b/gnu/usr.sbin/mkisofs/files.c @@ -0,0 +1,363 @@ +/* $OpenBSD: files.c,v 1.1 1997/09/15 06:01:52 downsj Exp $ */ +/* + * File files.c - Handle ADD_FILES related stuff. + + 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. */ + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +static char rcsid[] ="$From: files.c,v 1.5 1997/04/10 03:32:24 eric Rel $"; + +#include <errno.h> +#include "mkisofs.h" + +#include <stdlib.h> +#include <ctype.h> + +#ifdef ADD_FILES + +struct file_adds { + char *name; + struct file_adds *child; + struct file_adds *next; + int add_count; + int used; + union diru { + /* + * XXX Struct dirent is not guaranteed to be any size on a POSIX + * XXX compliant system. + * XXX We need to allocate enough space here, to allow the hacky + * XXX code in tree.c made by Ross Biro biro@yggdrasil.com + * XXX to work on operating systems other than Linux :-( + * XXX Changes made by Joerg Schilling joerg@schily.isdn.cs.tu-berlin.de + * XXX to prevent core dumps on Solaris. + * XXX Space allocated: + * XXX 1024 bytes == NAME_MAX + * XXX + 2 bytes for directory record length + * XXX + 2*8 bytes for inode number & offset (64 for future exp) + */ + struct dirent de; + char dspace[NAME_MAX+2+2*8]; + } du; + struct { + char *path; + char *name; + } *adds; +}; +extern struct file_adds *root_file_adds; + +/* + * FIXME(eric) - the file adding code really doesn't work very well + * at all. We should differentiate between adding directories, and adding + * single files, as adding a full directory affects how we should be + * searching for things. Ideally what we should do is make two passes + * through the local filesystem - one to figure out what trees we need + * to scan (and merge in any additions at that point), and the second to + * actually fill out each structure with the appropriate contents. + * + * + */ + +struct file_adds *root_file_adds = NULL; + +void +FDECL2(add_one_file, char *, addpath, char *, path ) +{ + char *cp; + char *name; + struct file_adds *f; + struct file_adds *tmp; + + f = root_file_adds; + tmp = NULL; + + name = strrchr (addpath, PATH_SEPARATOR); + if (name == NULL) { + name = addpath; + } else { + name++; + } + + cp = strtok (addpath, SPATH_SEPARATOR); + + while (cp != NULL && strcmp (name, cp)) { + if (f == NULL) { + root_file_adds = e_malloc (sizeof *root_file_adds); + f=root_file_adds; + f->name = NULL; + f->child = NULL; + f->next = NULL; + f->add_count = 0; + f->adds = NULL; + f->used = 0; + } + if (f->child) { + for (tmp = f->child; tmp->next != NULL; tmp =tmp->next) { + if (strcmp (tmp->name, cp) == 0) { + f = tmp; + goto next; + } + } + if (strcmp (tmp->name, cp) == 0) { + f=tmp; + goto next; + } + /* add a new node. */ + tmp->next = e_malloc (sizeof (*tmp->next)); + f=tmp->next; + f->name = strdup (cp); + f->child = NULL; + f->next = NULL; + f->add_count = 0; + f->adds = NULL; + f->used = 0; + } else { + /* no children. */ + f->child = e_malloc (sizeof (*f->child)); + f = f->child; + f->name = strdup (cp); + f->child = NULL; + f->next = NULL; + f->add_count = 0; + f->adds = NULL; + f->used = 0; + + } + next: + cp = strtok (NULL, SPATH_SEPARATOR); + } + /* Now f if non-null points to where we should add things */ + if (f == NULL) { + root_file_adds = e_malloc (sizeof *root_file_adds); + f=root_file_adds; + f->name = NULL; + f->child = NULL; + f->next = NULL; + f->add_count = 0; + f->adds = NULL; + } + + /* Now f really points to where we should add this name. */ + f->add_count++; + f->adds = realloc (f->adds, sizeof (*f->adds)*f->add_count); + f->adds[f->add_count-1].path = strdup (path); + f->adds[f->add_count-1].name = strdup (name); +} + +/* + * Function: add_file_list + * + * Purpose: Register an add-in file. + * + * Arguments: + */ +void +FDECL3(add_file_list, int, argc, char **,argv, int, ind) +{ + char *ptr; + char *dup_arg; + + while (ind < argc) { + dup_arg = strdup (argv[ind]); + ptr = strchr (dup_arg,'='); + if (ptr == NULL) { + free (dup_arg); + return; + } + *ptr = 0; + ptr++; + add_one_file (dup_arg, ptr); + free (dup_arg); + ind++; + } +} +void +FDECL1(add_file, char *, filename) +{ + char buff[1024]; + FILE *f; + char *ptr; + char *p2; + int count=0; + + if (strcmp (filename, "-") == 0) { + f = stdin; + } else { + f = fopen (filename, "r"); + if (f == NULL) { + perror ("fopen"); + exit (1); + } + } + while (fgets (buff, 1024, f)) { + count++; + ptr = buff; + while (isspace (*ptr)) ptr++; + if (*ptr==0) continue; + if (*ptr=='#') continue; + + if (ptr[strlen(ptr)-1]== '\n') ptr[strlen(ptr)-1]=0; + p2 = strchr (ptr, '='); + if (p2 == NULL) { + fprintf (stderr, "Error in line %d: %s\n", count, buff); + exit (1); + } + *p2 = 0; + p2++; + add_one_file (ptr, p2); + } + if (f != stdin) fclose (f); +} + +/* This function looks up additions. */ +char * +FDECL3(look_up_addition,char **, newpath, char *,path, struct dirent **,de) +{ + char *dup_path; + char *cp; + struct file_adds *f; + struct file_adds *tmp = NULL; + + f=root_file_adds; + if (!f) return NULL; + + /* I don't trust strtok */ + dup_path = strdup (path); + + cp = strtok (dup_path, SPATH_SEPARATOR); + while (cp != NULL) { + for (tmp = f->child; tmp != NULL; tmp=tmp->next) { + if (strcmp (tmp->name, cp) == 0) break; + } + if (tmp == NULL) { + /* no match */ + free (dup_path); + return (NULL); + } + f = tmp; + cp = strtok(NULL, SPATH_SEPARATOR); + } + free (dup_path); + + /* + * If nothing, then return. + */ + if (tmp == NULL) + { + /* no match */ + return (NULL); + } + + /* looks like we found something. */ + if (tmp->used >= tmp->add_count) return (NULL); + + *newpath = tmp->adds[tmp->used].path; + tmp->used++; + *de = &(tmp->du.de); + return (tmp->adds[tmp->used-1].name); + +} + +/* This function looks up additions. */ +void +FDECL2(nuke_duplicates, char *, path, struct dirent **,de) +{ + char *dup_path; + char *cp; + struct file_adds *f; + struct file_adds *tmp; + + f=root_file_adds; + if (!f) return; + + /* I don't trust strtok */ + dup_path = strdup (path); + + cp = strtok (dup_path, SPATH_SEPARATOR); + while (cp != NULL) { + for (tmp = f->child; tmp != NULL; tmp=tmp->next) { + if (strcmp (tmp->name, cp) == 0) break; + } + if (tmp == NULL) { + /* no match */ + free (dup_path); + return; + } + f = tmp; + cp = strtok(NULL, SPATH_SEPARATOR); + } + free (dup_path); + +#if 0 + /* looks like we found something. */ + if (tmp->used >= tmp->add_count) return; + + *newpath = tmp->adds[tmp->used].path; + tmp->used++; + *de = &(tmp->du.de); + return (tmp->adds[tmp->used-1].name); +#endif + return; +} + +/* This function lets us add files from outside the standard file tree. + It is useful if we want to duplicate a cd, but add/replace things. + We should note that the real path will be used for exclusions. */ + +struct dirent * +FDECL3(readdir_add_files, char **, pathp, char *,path, DIR *, dir){ + struct dirent *de; + + char *addpath; + char *name; + + de = readdir (dir); + if (de) { + nuke_duplicates(path, &de); + return (de); + } + + name=look_up_addition (&addpath, path, &de); + + if (!name) { + return NULL; + } + + *pathp=addpath; + + /* Now we must create the directory entry. */ + /* fortuneately only the name seems to matter. */ + /* + de->d_ino = -1; + de->d_off = 0; + de->d_reclen = strlen (name); + */ + strncpy (de->d_name, name, NAME_MAX); + de->d_name[NAME_MAX]=0; + nuke_duplicates(path, &de); + return (de); + +} + +#else +struct dirent * +FDECL3(readdir_add_files, char **, pathp, char *,path, DIR *, dir){ + return (readdir (dir)); +} +#endif diff --git a/gnu/usr.sbin/mkisofs/fnmatch.c b/gnu/usr.sbin/mkisofs/fnmatch.c new file mode 100644 index 00000000000..6e7c110e047 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/fnmatch.c @@ -0,0 +1,227 @@ +/* $OpenBSD: fnmatch.c,v 1.1 1997/09/15 06:01:52 downsj Exp $ */ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +static char rcsid[] ="$From: fnmatch.c,v 1.3 1997/03/22 02:53:13 eric Rel $"; + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <fnmatch.h> + +#ifndef FNM_FILE_NAME +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#endif + +#ifndef FNM_LEADING_DIR +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#endif + +#ifndef FNM_CASEFOLD +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + + +#include <ctype.h> + +#if defined (STDC_HEADERS) || !defined (isascii) +#define ISASCII(c) 1 +#else +#define ISASCII(c) isascii(c) +#endif + +#define ISUPPER(c) (ISASCII (c) && isupper (c)) + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/gnu/usr.sbin/mkisofs/fnmatch.h b/gnu/usr.sbin/mkisofs/fnmatch.h new file mode 100644 index 00000000000..ffca8351d27 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/fnmatch.h @@ -0,0 +1,81 @@ +/* $OpenBSD: fnmatch.h,v 1.1 1997/09/15 06:01:52 downsj Exp $ */ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * $From: fnmatch.h,v 1.1 1997/02/23 15:54:20 eric Rel $ + */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(protos) protos +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in <unistd.h>. */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +#ifndef FNM_FILE_NAME + /* + * Apparently GNU libc doesn't define this thing. + */ +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/gnu/usr.sbin/mkisofs/hash.c b/gnu/usr.sbin/mkisofs/hash.c new file mode 100644 index 00000000000..c5051378514 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/hash.c @@ -0,0 +1,227 @@ +/* $OpenBSD: hash.c,v 1.1 1997/09/15 06:01:52 downsj Exp $ */ +/* + * File hash.c - generate hash tables 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[] ="$From: hash.c,v 1.2 1997/02/23 16:11:15 eric Rel $"; + +#include <stdlib.h> +#include "mkisofs.h" + +#define NR_HASH 1024 + +#define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH) + +static struct file_hash * hash_table[NR_HASH] = {0,}; + +void FDECL1(add_hash, struct directory_entry *, spnt){ + struct file_hash * s_hash; + unsigned int hash_number; + + if(spnt->size == 0 || spnt->starting_block == 0) + if(spnt->size != 0 || spnt->starting_block != 0) { + fprintf(stderr,"Non zero-length file assigned zero extent.\n"); + exit(1); + }; + + if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return; + hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode); + +#if 0 + if (verbose) fprintf(stderr,"%s ",spnt->name); +#endif + s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash)); + s_hash->next = hash_table[hash_number]; + s_hash->inode = spnt->inode; + s_hash->dev = spnt->dev; + s_hash->starting_block = spnt->starting_block; + s_hash->size = spnt->size; + hash_table[hash_number] = s_hash; +} + +struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){ + unsigned int hash_number; + struct file_hash * spnt; + hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); + if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL; + + spnt = hash_table[hash_number]; + while(spnt){ + if(spnt->inode == inode && spnt->dev == dev) return spnt; + spnt = spnt->next; + }; + return NULL; +} + + +static struct file_hash * directory_hash_table[NR_HASH] = {0,}; + +void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){ + struct file_hash * s_hash; + unsigned int hash_number; + + if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return; + hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); + + s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash)); + s_hash->next = directory_hash_table[hash_number]; + s_hash->inode = inode; + s_hash->dev = dev; + directory_hash_table[hash_number] = s_hash; +} + +struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){ + unsigned int hash_number; + struct file_hash * spnt; + hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); + if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL; + + spnt = directory_hash_table[hash_number]; + while(spnt){ + if(spnt->inode == inode && spnt->dev == dev) return spnt; + spnt = spnt->next; + }; + return NULL; +} + +struct name_hash +{ + struct name_hash * next; + struct directory_entry * de; +}; + +#define NR_NAME_HASH 128 + +static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,}; + +/* + * Find the hash bucket for this name. + */ +static unsigned int FDECL1(name_hash, const char *, name) +{ + unsigned int hash = 0; + const char * p; + + p = name; + + while (*p) + { + /* + * Don't hash the iso9660 version number. This way + * we can detect duplicates in cases where we have + * directories (i.e. foo) and non-directories + * (i.e. foo;1). + */ + if( *p == ';' ) + { + break; + } + hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++; + } + return hash % NR_NAME_HASH; +} + +void FDECL1(add_file_hash, struct directory_entry *, de){ + struct name_hash * new; + int hash; + + new = (struct name_hash *) e_malloc(sizeof(struct name_hash)); + new->de = de; + new->next = NULL; + hash = name_hash(de->isorec.name); + + /* Now insert into the hash table */ + new->next = name_hash_table[hash]; + name_hash_table[hash] = new; +} + +struct directory_entry * FDECL1(find_file_hash, char *, name) +{ + struct name_hash * nh; + char * p1; + char * p2; + + for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) + { + p1 = name; + p2 = nh->de->isorec.name; + + /* + * Look for end of string, or a mismatch. + */ + while(1==1) + { + if( (*p1 == '\0' || *p1 == ';') + || (*p2 == '\0' || *p2 == ';') + || (*p1 != *p2) ) + { + break; + } + p1++; + p2++; + } + + /* + * If we are at the end of both strings, then + * we have a match. + */ + if( (*p1 == '\0' || *p1 == ';') + && (*p2 == '\0' || *p2 == ';') ) + { + return nh->de; + } + } + return NULL; +} + +int FDECL1(delete_file_hash, struct directory_entry *, de){ + struct name_hash * nh, *prev; + int hash; + + prev = NULL; + hash = name_hash(de->isorec.name); + for(nh = name_hash_table[hash]; nh; nh = nh->next) { + if(nh->de == de) break; + prev = nh; + } + if(!nh) return 1; + if(!prev) + name_hash_table[hash] = nh->next; + else + prev->next = nh->next; + free(nh); + return 0; +} + +void flush_file_hash(){ + struct name_hash * nh, *nh1; + int i; + + for(i=0; i<NR_NAME_HASH; i++) { + nh = name_hash_table[i]; + while(nh) { + nh1 = nh->next; + free(nh); + nh = nh1; + } + name_hash_table[i] = NULL; + + } +} diff --git a/gnu/usr.sbin/mkisofs/iso9660.h b/gnu/usr.sbin/mkisofs/iso9660.h new file mode 100644 index 00000000000..0f98f83fba0 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/iso9660.h @@ -0,0 +1,158 @@ +/* $OpenBSD: iso9660.h,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * Header file iso9660.h - assorted structure definitions and typecasts. + * specific to 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. */ + +/* + * $From: iso9660.h,v 1.1 1997/02/23 15:55:25 eric Rel $ + */ + +#ifndef _ISOFS_FS_H +#define _ISOFS_FS_H + +/* + * The isofs filesystem constants/structures + */ + +/* This part borrowed from the bsd386 isofs */ +#define ISODCL(from, to) (to - from + 1) + +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +/* volume descriptor types */ +#define ISO_VD_PRIMARY 1 +#define ISO_VD_END 255 + +#define ISO_STANDARD_ID "CD001" + +#define EL_TORITO_ID "EL TORITO SPECIFICATION" +#define EL_TORITO_ARCH_x86 0 +#define EL_TORITO_ARCH_PPC 1 +#define EL_TORITO_ARCH_MAC 2 +#define EL_TORITO_BOOTABLE 0x88 +#define EL_TORITO_MEDIA_NOEMUL 0 +#define EL_TORITO_MEDIA_12FLOP 1 +#define EL_TORITO_MEDIA_144FLOP 2 +#define EL_TORITO_MEDIA_288FLOP 3 +#define EL_TORITO_MEDIA_HD 4 + +struct iso_primary_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char unused1 [ISODCL ( 8, 8)]; + char system_id [ISODCL ( 9, 40)]; /* achars */ + char volume_id [ISODCL ( 41, 72)]; /* dchars */ + char unused2 [ISODCL ( 73, 80)]; + char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + char unused3 [ISODCL ( 89, 120)]; + char volume_set_size [ISODCL (121, 124)]; /* 723 */ + char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + char logical_block_size [ISODCL (129, 132)]; /* 723 */ + char path_table_size [ISODCL (133, 140)]; /* 733 */ + char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + char volume_set_id [ISODCL (191, 318)]; /* dchars */ + char publisher_id [ISODCL (319, 446)]; /* achars */ + char preparer_id [ISODCL (447, 574)]; /* achars */ + char application_id [ISODCL (575, 702)]; /* achars */ + char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + char file_structure_version [ISODCL (882, 882)]; /* 711 */ + char unused4 [ISODCL (883, 883)]; + char application_data [ISODCL (884, 1395)]; + char unused5 [ISODCL (1396, 2048)]; +}; + +/* El Torito Boot Record Volume Descriptor */ +struct eltorito_boot_descriptor { + char id [ISODCL ( 1, 1)]; /* 711 */ + char id2 [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char system_id [ISODCL ( 8, 39)]; + char unused2 [ISODCL ( 40, 71)]; + char bootcat_ptr [ISODCL ( 72 , 75)]; + char unused5 [ISODCL ( 76, 2048)]; +}; + +/* Validation entry for El Torito */ +struct eltorito_validation_entry { + char headerid [ISODCL ( 1, 1)]; /* 711 */ + char arch [ISODCL ( 2, 2)]; + char pad1 [ISODCL ( 3, 4)]; /* 711 */ + char id [ISODCL ( 5, 28)]; + char cksum [ISODCL ( 29, 30)]; + char key1 [ISODCL ( 31, 31)]; + char key2 [ISODCL ( 32, 32)]; +}; + +/* El Torito initial/default entry in boot catalog */ +struct eltorito_defaultboot_entry { + char boot_id [ISODCL ( 1, 1)]; /* 711 */ + char boot_media [ISODCL ( 2, 2)]; + char loadseg [ISODCL ( 3, 4)]; /* 711 */ + char arch [ISODCL ( 5, 5)]; + char pad1 [ISODCL ( 6, 6)]; + char nsect [ISODCL ( 7, 8)]; + char bootoff [ISODCL ( 9, 12)]; + char pad2 [ISODCL ( 13, 32)]; +}; + + +/* We use this to help us look up the parent inode numbers. */ + +struct iso_path_table{ + unsigned char name_len[2]; /* 721 */ + char extent[4]; /* 731 */ + char parent[2]; /* 721 */ + char name[1]; +}; + +struct iso_directory_record { + unsigned char length [ISODCL (1, 1)]; /* 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + char extent [ISODCL (3, 10)]; /* 733 */ + char size [ISODCL (11, 18)]; /* 733 */ + char date [ISODCL (19, 25)]; /* 7 by 711 */ + char flags [ISODCL (26, 26)]; + char file_unit_size [ISODCL (27, 27)]; /* 711 */ + char interleave [ISODCL (28, 28)]; /* 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + char name [34]; /* Not really, but we need something here */ +}; +#endif + + + diff --git a/gnu/usr.sbin/mkisofs/match.c b/gnu/usr.sbin/mkisofs/match.c new file mode 100644 index 00000000000..5a5abb109b1 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/match.c @@ -0,0 +1,57 @@ +/* $OpenBSD: match.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * 27-Mar-96: Jan-Piet Mens <jpm@mens.de> + * added 'match' option (-m) to specify regular expressions NOT to be included + * in the CD image. + */ + +static char rcsid[] ="$From: match.c,v 1.2 1997/02/23 16:10:42 eric Rel $"; + +#include <stdio.h> +#ifndef VMS +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#else +#include <stdlib.h> +#endif +#endif +#include <string.h> +#include "match.h" + +#define MAXMATCH 1000 +static char *mat[MAXMATCH]; + +void add_match(fn) +char * fn; +{ + register int i; + + for (i=0; mat[i] && i<MAXMATCH; i++); + if (i == MAXMATCH) { + fprintf(stderr,"Can't exclude RE '%s' - too many entries in table\n",fn); + return; + } + + + mat[i] = (char *) malloc(strlen(fn)+1); + if (! mat[i]) { + fprintf(stderr,"Can't allocate memory for excluded filename\n"); + return; + } + + strcpy(mat[i],fn); +} + +int matches(fn) +char * fn; +{ + /* very dumb search method ... */ + register int i; + + for (i=0; mat[i] && i<MAXMATCH; i++) { + if (fnmatch(mat[i], fn, FNM_FILE_NAME) != FNM_NOMATCH) { + return 1; /* found -> excluded filenmae */ + } + } + return 0; /* not found -> not excluded */ +} diff --git a/gnu/usr.sbin/mkisofs/match.h b/gnu/usr.sbin/mkisofs/match.h new file mode 100644 index 00000000000..395d42d0144 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/match.h @@ -0,0 +1,15 @@ +/* $OpenBSD: match.h,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * 27th March 1996. Added by Jan-Piet Mens for matching regular expressions + * in paths. + * + */ + +/* + * $From: match.h,v 1.1 1997/02/23 15:56:12 eric Rel $ + */ + +#include "fnmatch.h" + +void add_match(); +int matches(); diff --git a/gnu/usr.sbin/mkisofs/mkisofs.8 b/gnu/usr.sbin/mkisofs/mkisofs.8 new file mode 100644 index 00000000000..a7d1a9fa20d --- /dev/null +++ b/gnu/usr.sbin/mkisofs/mkisofs.8 @@ -0,0 +1,428 @@ +.\" $OpenBSD: mkisofs.8,v 1.1 1997/09/15 06:01:52 downsj Exp $ +.\" $From: mkisofs.8,v 1.5 1997/04/10 02:45:50 eric Rel $ +.\" -*- nroff -*- +.TH MKISOFS 8 "9 Apr 1997" "Version 1.11" +.SH NAME +mkisofs \- create a iso9660 filesystem with optional Rock Ridge attributes. +.SH SYNOPSIS +.B mkisofs +[ +.B \-a +] +[ +.B \-b +.I boot_image +] +[ +.B \-c +.I boot_catalog +] +[ +.B \-A +.I application_id +] +[ +.B \-f +] +[ +.B \-d +] +[ +.B \-D +] +[ +.B \-i +.I include-list +] +[ +.B \-l +] +[ +.B \-L +] +[ +.B \-L +] +[ +.B \-p +.I preparer +] +[ +.B \-P +.I publisher +] +[ +.B \-r +] +[ +.B \-R +] +[ +.B \-T +] +[ +.B \-v +] +[ +.B \-V +] +[ +.B \-V +.I volid +] +[ +.B \-x +.I path +] +[ +.B \-z +] +[ +.B \-m +.I glob +] +.B \-o +.I filename +.I path +.SH DESCRIPTION +.B mkisofs +is effectively a pre-mastering program to generate the iso9660 filesystem - it +takes a snapshot of a given directory tree, and generates a binary image which +will correspond to an iso9660 filesystem when written to a block device. +.PP +.B mkisofs +is also capable of generating the System Use Sharing Protocol records specified +by the Rock Ridge Interchange Protocol. This is used to further describe the +files in the iso9660 filesystem to a unix host, and provides information such +as longer filenames, uid/gid, posix permissions, and block and character +devices. +.PP +Each file written to the iso9660 filesystem must have a filename in the 8.3 +format (8 characters, period, 3 characters, all upper case), even if Rock Ridge +is in use. This filename is used on systems that are not able to make use of +the Rock Ridge extensions (such as MS-DOS), and each filename in each directory +must be different from the other filenames in the same directory. +.B mkisofs +generally tries to form correct names by forcing the unix filename to upper +case and truncating as required, but often times this yields unsatisfactory +results when there are cases where the +truncated names are not all unique. +.B mkisofs +assigns weightings to each filename, and if two names that are otherwise the +same are found the name with the lower priority is renamed to have a 3 digit +number as an extension (where the number is guaranteed to be unique). An +example of this would be the files foo.bar and +foo.bar.~1~ - the file foo.bar.~1~ would be written as FOO.000;1 and the file +foo.bar would be written as FOO.BAR;1 +.PP +Note that +.B mkisofs +is not designed to communicate with the writer directly. Most writers +have proprietary command sets which vary from one manufacturer to +another, and you need a specialized tool to actually burn the disk. +The +.B cdwrite +utility is one such tool that runs under Linux and performs this task. +The latest version of +.B cdwrite +is capable of communicating with Phillips/IMS/Kodak, HP and Yamaha drives. +Most writers come with some version of DOS software that allows a direct image +copy of an iso9660 image to the writer. The current version of +.B cdwrite +is available from sunsite.unc.edu: /utils/disk-management/cdwrite-2.0.tar.gz +.PP +Also you should know that most cd writers are very particular about timing. +Once you start to burn a disc, you cannot let their buffer empty before you +are done, or you will end up with a corrupt disc. Thus it is critical +that you be able to maintain an uninterrupted data stream to the writer +for the entire time that the disc is being written. +.PP +.br +.B path +is the path of the directory tree to be copied into the iso9660 filesystem. +.SH OPTIONS +.TP +.I \-a +Include all files on the iso9660 filesystem. Normally files that contain the +characters '~' or '#' will not be included (these are typically backup files +for editors under unix). +.TP +.I \-A application_id +Specifies a text string that will be written into the volume header. +This should describe the application that will be on the disc. There +is space on the disc for 128 characters of information. This parameter can +also be set in the file +.I \&.mkisofsrc +with APPI=id. +If specified in both places, the command line version is used. +.TP +.I \-b boot_image +Specifies the path and filename of the boot image to be used when making +an "El Torito" bootable CD. The pathname must be relative to the source +path specified to +.B mkisofs. +This option is required to make a bootable CD. +The boot image must be exactly the size of either a 1.2, 1.44, or a 2.88 +meg floppy, and +.B mkisofs +will use this size when creating the output iso9660 +filesystem. It is assumed that the first 512 byte sector should be read +from the boot image (it is essentially emulating a normal floppy drive). +This will work, for example, if the boot image is a LILO based boot floppy. +.TP +.I \-c boot_catalog +Specifies the path and filename of the boot catalog to be used when making +an "El Torito" bootable CD. The pathname must be relative to the source +path specified to +.B mkisofs. +This option is required to make a bootable CD. +This file will be created by +.B mkisofs +in the source filesystem, so be +sure the specified filename does not conflict with an existing file, as +it will be quietly overwritten! Usually a name like "boot.catalog" is +chosen. +.TP +.I \-d +Omit trailing period from files that do not have a period. This violates the +ISO9660 standard, but it happens to work on many systems. Use with caution. +.TP +.I \-D +Do not use deep directory relocation, and instead just pack them in the +way we see them. This violates the ISO9660 standard, but it works on many +systems. Use with caution. +.TP +.I \-f +Follow symbolic links when generating the filesystem. When this option is not +in use, symbolic links will be entered using Rock Ridge if enabled, otherwise +the file will be ignored. +.TP +.I \-i include-list +Use the specified file as a list of files to add to the directory tree. +This is useful for quickly repacking a CD while adding files to it. +The format of this file is path1/file=path2 where path1 is the directory +in the ISO9660 file system where file should appear and path2 is the +where to find the file. NOTE: This option doesn't work well, and +needs to be compltely redone so that integration with the rest of mkisofs +is handled in a cleaner fashion. +.TP +.I \-l +Allow full 32 character filenames. Normally the ISO9660 filename will be in an +8.3 format which is compatible with MS-DOS, even though the ISO9660 standard +allows filenames of up to 32 characters. If you use this option, the disc may +be difficult to use on a MS-DOS system, but this comes in handy on some other +systems (such as the Amiga). Use with caution. +.TP +.I \-L +Allow filenames to begin with a period. Usually, a leading dot is +replaced with an underscore in order to maintain MS-DOS compatibility. +.TP +.I \-m glob +Exclude +.I glob +from being written to CDROM. +.I glob +is a shell wild-card-style pattern that must match part of the filename (not +the path as with option +.BR -x ). +Technically +.I glob +is matched against the +.I d->d_name +part of the directory entry. +Multiple globs may be excluded (up to 1000). +Example: + +mkisofs \-o rom \-m '*.o' \-m core \-m foobar + +would exclude all files ending in ".o", called "core" or "foobar" to be +copied to CDROM. Note that if you had a directory called "foobar" it too (and +of course all its descendants) would be excluded. +.TP +.I \-M path +Specifies path to existing iso9660 image to be merged. The output +of +.B mkisofs +will be a new session which should get written to the end of the +image specified in -M. Typically this requires multi-session capability +for the recorder and cdrom drive that you are attempting to write this +image to. Support for this is not yet 100% complete, because some handshaking +is required between mkisofs and cdwrite in order to determine the next +writable address on the cdrom. +.TP +.I \-N +Omit version numbers from ISO9660 file names. This may violate the ISO9660 +standard, but no one really uses the version numbers anyway. Use with caution. +.TP +.I \-o filename +is the name of the file to which the iso9660 filesystem image should be +written. This can be a disk file, a tape drive, or it can correspond directly +to the device name of the optical disc writer. If not specified, stdout is +used. Note that the output can also be a block special device for a regular +disk drive, in which case the disk partition can be mounted and examined to +ensure that the premastering was done correctly. +.TP +.I \-P publisher_id +Specifies a text string that will be written into the volume header. +This should describe the publisher of the CDROM, usually with a +mailing address and phone number. There is space on the disc for 128 +characters of information. This parameter can also be set in the file +.I \&.mkisofsrc +with PUBL=. +If specified in both places, the command line version is used. +.TP +.I \-p preparer_id +Specifies a text string that will be written into the volume header. +This should describe the preparer of the CDROM, usually with a mailing +address and phone number. There is space on the disc for 128 +characters of information. This parameter can also be set in the file +.I \&.mkisofsrc +with PREP=. +If specified in both places, the command line version is used. +.TP +.I \-R +Generate SUSP and RR records using the Rock Ridge protocol to further describe +the files on the iso9660 filesystem. +.TP +.I \-r +This is like the \-R option, but file ownership and modes are set to +more useful values. The uid and gid are set to zero, because they are +usually only useful on the author's system, and not useful to the +client. All the file read bits are set true, so that files and +directories are globally readable on the client. If any execute bit is +set for a file, set all of the execute bits, so that executables are +globally executable on the client. If any search bit is set for a +directory, set all of the search bits, so that directories are globally +searchable on the client. All write bits are cleared, because the +CD-Rom will be mounted read-only in any case. If any of the special +mode bits are set, clear them, because file locks are not useful on a +read-only file system, and set-id bits are not desirable for uid 0 or +gid 0. +.TP +.I \-T +Generate a file TRANS.TBL in each directory on the CDROM, which can be used +on non-Rock Ridge capable systems to help establish the correct file names. +There is also information present in the file that indicates the major and +minor numbers for block and character devices, and each symlink has the name of +the link file given. +.TP +.I \-V volid +Specifies the volume ID to be written into the master block. This +parameter can also be set in the file +.I \&.mkisofsrc +with VOLI=id. +If specified in both places, the command line version is used. +.TP +.I \-v +Verbose execution. +.TP +.I \-x path +Exclude +.I path +from being written to CDROM. +.I path +must be the complete pathname that results from concatenating the pathname +given as command line argument and the path relative to this directory. +Multiple paths may be excluded (up to 1000). +Example: + +mkisofs \-o cd \-x /local/dir1 \-x /local/dir2 /local +.TP +.I \-z +Generate special SUSP records for transparently compressed files. This is +only of use and interest for hosts that support transparent decompression. +This is an experimental feature, and no hosts yet support this, but there +are ALPHA patches for Linux that can make use of this feature. +.SH CONFIGURATION +.B mkisofs +looks for the +.IR \&.mkisofsrc +file, +first in the current working directory, +then in the user's home directory, +and then in the directory in which the +.B mkisofs +binary is stored. This file is assumed to contain a series of lines +of the form "TAG=value", and in this way you can specify certain +options. +The case of the tag is not significant. +Some fields in the volume header +are not settable on the command line, but can be altered through this +facility. +Comments may be placed in this file, +using lines which start with a hash (#) character. +.TP +APPI +The application identifier +should describe the application that will be on the disc. +There is space on the disc for 128 characters of information. +May be overridden using the \-A command line option. +.TP +COPY +The copyright information, +often the name of a file on the disc containing the copyright notice. +There is space in the disc for 37 characters of information. +.TP +ABST +The abstract information, +often the name of a file on the disc containing an abstract. +There is space in the disc for 37 characters of information. +.TP +BIBL +The bibliographic information, +often the name of a file on the disc containing a bibliography. +There is space in the disc for 37 characters of information. +.TP +PREP +This should describe the preparer of the CDROM, +usually with a mailing address and phone number. +There is space on the disc for 128 characters of information. +May be overridden using the \-p command line option. +.TP +PUBL +This should describe the publisher of the CDROM, +usually with a mailing address and phone number. +There is space on the disc for 128 characters of information. +May be overridden using the \-P command line option. +.TP +SYSI +The System Identifier. +There is space on the disc for 32 characters of information. +.TP +VOLI +The Volume Identifier. +There is space on the disc for 32 characters of information. +May be overridden using the \-V command line option. +.TP +VOLS +The Volume Set Name. +There is space on the disc for 278 characters of information. +.PP +.B mkisofs +can also be configured at compile time with defaults for many of these fields. +See the file defaults.h. +.SH AUTHOR +.B mkisofs +is not based on the standard mk*fs tools for unix, because we must generate +a complete copy of an existing filesystem on a disk in the iso9660 +filesystem. The name mkisofs is probably a bit of a misnomer, since it +not only creates the filesystem, but it also populates it as well. +.PP +.br +Eric Youngdale <ericy@gnu.ai.mit.edu> or <eric@andante.jic.com> wrote both the +Linux isofs9660 filesystem and the mkisofs utility, and is currently +maintaining them. The copyright for the mkisofs utility is held by +Yggdrasil Computing, Incorporated. +.SH BUGS +Any files that have hard links to files not in the tree being copied to the +iso9660 filessytem will have an incorrect file reference count. +.PP +There may be some other ones. Please, report them to the author. +.SH FUTURE IMPROVEMENTS +Allow specification of multiple paths on the command line to be included in +iso9660 filesystem. Can be tricky - directory entries in the root directory +need to be properly sorted. +.SH AVAILABILITY +.B mkisofs +is available for anonymous ftp from tsx-11.mit.edu in +/pub/linux/packages/mkisofs and many other mirror sites. diff --git a/gnu/usr.sbin/mkisofs/mkisofs.c b/gnu/usr.sbin/mkisofs/mkisofs.c new file mode 100644 index 00000000000..5c72ca8ceab --- /dev/null +++ b/gnu/usr.sbin/mkisofs/mkisofs.c @@ -0,0 +1,661 @@ +/* $OpenBSD: mkisofs.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * Program mkisofs.c - generate iso9660 filesystem based upon directory + * tree on hard disk. + + 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[] ="$From: mkisofs.c,v 1.9 1997/04/10 02:45:09 eric Rel $"; + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +#include <errno.h> +#include "mkisofs.h" +#include "config.h" + +#ifdef linux +#include <getopt.h> +#endif + +#include "iso9660.h" +#include <ctype.h> + +#ifndef VMS +#include <time.h> +#else +#include <sys/time.h> +#include "vms.h" +#endif + +#include <stdlib.h> +#include <sys/stat.h> + +#ifndef VMS +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#endif + +#include "exclude.h" + +#ifdef __NetBSD__ +#include <sys/time.h> +#include <sys/resource.h> +#endif + +struct directory * root = NULL; + +static char version_string[] = "mkisofs v1.11"; + +FILE * discimage; +unsigned int next_extent = 0; +unsigned int last_extent = 0; +unsigned int session_start = 0; +unsigned int path_table_size = 0; +unsigned int path_table[4] = {0,}; +unsigned int path_blocks = 0; +struct iso_directory_record root_record; +char * extension_record = NULL; +int extension_record_extent = 0; +static int extension_record_size = 0; + +/* These variables are associated with command line options */ +int use_eltorito = 0; +int use_RockRidge = 0; +int verbose = 0; +int all_files = 0; +int follow_links = 0; +int rationalize = 0; +int generate_tables = 0; +char * preparer = PREPARER_DEFAULT; +char * publisher = PUBLISHER_DEFAULT; +char * appid = APPID_DEFAULT; +char * copyright = COPYRIGHT_DEFAULT; +char * biblio = BIBLIO_DEFAULT; +char * abstract = ABSTRACT_DEFAULT; +char * volset_id = VOLSET_ID_DEFAULT; +char * volume_id = VOLUME_ID_DEFAULT; +char * system_id = SYSTEM_ID_DEFAULT; +char * boot_catalog = BOOT_CATALOG_DEFAULT; +char * boot_image = BOOT_IMAGE_DEFAULT; + +int omit_period = 0; /* Violates iso9660, but these are a pain */ +int transparent_compression = 0; /* So far only works with linux */ +int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/ +int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ +int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with + DOS */ +int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ + +struct rcopts{ + char * tag; + char ** variable; +}; + +struct rcopts rcopt[] = { + {"PREP", &preparer}, + {"PUBL", &publisher}, + {"APPI", &appid}, + {"COPY", ©right}, + {"BIBL", &biblio}, + {"ABST", &abstract}, + {"VOLS", &volset_id}, + {"VOLI", &volume_id}, + {"SYSI", &system_id}, + {NULL, NULL} +}; + +#if defined(ultrix) || defined(_AUX_SOURCE) +char *strdup(s) +char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} +#endif + +void FDECL1(read_rcfile, char *, appname) +{ + FILE * rcfile; + struct rcopts * rco; + char * pnt, *pnt1; + char linebuffer[256]; + static char rcfn[] = ".mkisofsrc"; + char filename[1000]; + int linum; + + strcpy(filename, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + + if (!rcfile) + { + pnt = getenv("MKISOFSRC"); + if (pnt && strlen(pnt) <= sizeof(filename)) + { + strcpy(filename, pnt); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + + if (!rcfile) + { + pnt = getenv("HOME"); + if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename)) + { + strcpy(filename, pnt); + strcat(filename, "/"); + strcat(filename, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename)) + { + strcpy(filename, appname); + pnt = strrchr(filename, '/'); + if (pnt) + { + strcpy(pnt + 1, rcfn); + rcfile = fopen(filename, "r"); + if (!rcfile && errno != ENOENT) + perror(filename); + } + } + if (!rcfile) + return; + fprintf(stderr, "Using \"%s\"\n", filename); + /* OK, we got it. Now read in the lines and parse them */ + linum = 0; + while (fgets(linebuffer, sizeof(linebuffer), rcfile)) + { + char *name; + char *name_end; + ++linum; + /* skip any leading white space */ + pnt = linebuffer; + while (*pnt == ' ' || *pnt == '\t') + ++pnt; + /* If we are looking at a # character, this line is a comment. */ + if (*pnt == '#') + continue; + /* The name should begin in the left margin. Make sure it is in + upper case. Stop when we see white space or a comment. */ + name = pnt; + while (*pnt && isalpha(*pnt)) + { + if(islower(*pnt)) + *pnt = toupper(*pnt); + pnt++; + } + if (name == pnt) + { + fprintf(stderr, "%s:%d: name required\n", filename, linum); + continue; + } + name_end = pnt; + /* Skip past white space after the name */ + while (*pnt == ' ' || *pnt == '\t') + pnt++; + /* silently ignore errors in the rc file. */ + if (*pnt != '=') + { + fprintf(stderr, "%s:%d: equals sign required\n", filename, linum); + continue; + } + /* Skip pas the = sign, and any white space following it */ + pnt++; /* Skip past '=' sign */ + while (*pnt == ' ' || *pnt == '\t') + pnt++; + + /* now it is safe to NUL terminate the name */ + + *name_end = 0; + + /* Now get rid of trailing newline */ + + pnt1 = pnt; + while (*pnt1) + { + if (*pnt1 == '\n') + { + *pnt1 = 0; + break; + } + pnt1++; + }; + /* OK, now figure out which option we have */ + for(rco = rcopt; rco->tag; rco++) { + if(strcmp(rco->tag, name) == 0) + { + *rco->variable = strdup(pnt); + break; + }; + } + if (rco->tag == NULL) + { + fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum, + name); + } + } + if (ferror(rcfile)) + perror(filename); + fclose(rcfile); +} + +char * path_table_l = NULL; +char * path_table_m = NULL; +int goof = 0; + +void usage(){ + fprintf(stderr,"Usage:\n"); + fprintf(stderr, +"mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \ +[-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]" +#ifdef ADD_FILES +"[-i file] \n" +#endif +"[-P publisher] [ -A app_id ] [-z] \n \ +[-b boot_image_name] [-c boot_catalog-name] \ +[-x path -x path ...] path\n"); + exit(1); +} + + +/* + * Fill in date in the iso9660 format + * + * The standards state that the timezone offset is in multiples of 15 + * minutes, and is what you add to GMT to get the localtime. The U.S. + * is always at a negative offset, from -5h to -8h (can vary a little + * with DST, I guess). The Linux iso9660 filesystem has had the sign + * of this wrong for ages (mkisofs had it wrong too for the longest time). + */ +int FDECL2(iso9660_date,char *, result, time_t, ctime){ + struct tm *local; + local = localtime(&ctime); + result[0] = local->tm_year; + result[1] = local->tm_mon + 1; + result[2] = local->tm_mday; + result[3] = local->tm_hour; + result[4] = local->tm_min; + result[5] = local->tm_sec; + + /* + * Must recalculate proper timezone offset each time, + * as some files use daylight savings time and some don't... + */ + result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ + local = gmtime(&ctime); + local->tm_year -= result[0]; + local->tm_yday -= result[6]; + local->tm_hour -= result[3]; + local->tm_min -= result[4]; + if (local->tm_year < 0) + { + local->tm_yday = -1; + } + else + { + if (local->tm_year > 0) local->tm_yday = 1; + } + + result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15; + + return 0; +} + + +extern char * cdwrite_data; + +int FDECL2(main, int, argc, char **, argv){ + char * outfile; + struct directory_entry de; + unsigned long mem_start; + struct stat statbuf; + char * scan_tree; + char * merge_image = NULL; + struct iso_directory_record * mrootp = NULL; + int c; +#ifdef ADD_FILES + char *add_file_file = NULL; +#endif + + if (argc < 2) + usage(); + + /* Get the defaults from the .mkisofsrc file */ + read_rcfile(argv[0]); + + outfile = NULL; + while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:b:c:x:dDlLNzA:M:m:C:")) != EOF) + switch (c) + { + case 'C': + /* + * This is a temporary hack until cdwrite gets the proper hooks in + * it. + */ + cdwrite_data = optarg; + break; + case 'a': + all_files++; + break; + case 'b': + use_eltorito++; + boot_image = optarg; /* pathname of the boot image on cd */ + if (boot_image == NULL) { + fprintf(stderr,"Required boot image pathname missing\n"); + exit(1); + } + break; + case 'c': + use_eltorito++; + boot_catalog = optarg; /* pathname of the boot image on cd */ + if (boot_catalog == NULL) { + fprintf(stderr,"Required boot catalog pathname missing\n"); + exit(1); + } + break; + case 'A': + appid = optarg; + if(strlen(appid) > 128) { + fprintf(stderr,"Application-id string too long\n"); + exit(1); + }; + break; + case 'd': + omit_period++; + break; + case 'D': + RR_relocation_depth = 32767; + break; + case 'f': + follow_links++; + break; + case 'i': +#ifdef ADD_FILES + add_file_file = optarg; + break; +#else + usage(); + exit(1); +#endif + case 'l': + full_iso9660_filenames++; + break; + case 'L': + allow_leading_dots++; + break; + case 'M': + merge_image = optarg; + break; + case 'N': + omit_version_number++; + break; + case 'o': + outfile = optarg; + break; + case 'p': + preparer = optarg; + if(strlen(preparer) > 128) { + fprintf(stderr,"Preparer string too long\n"); + exit(1); + }; + break; + case 'P': + publisher = optarg; + if(strlen(publisher) > 128) { + fprintf(stderr,"Publisher string too long\n"); + exit(1); + }; + break; + case 'R': + use_RockRidge++; + break; + case 'r': + rationalize++; + use_RockRidge++; + break; + case 'T': + generate_tables++; + break; + case 'V': + volume_id = optarg; + break; + case 'v': + verbose++; + break; + case 'z': +#ifdef VMS + fprintf(stderr,"Transparent compression not supported with VMS\n"); + exit(1); +#else + transparent_compression++; +#endif + break; + case 'm': + add_match(optarg); + break; + case 'x': + exclude(optarg); + break; + default: + usage(); + exit(1); + } +#ifdef __NetBSD__ + { + int resource; + struct rlimit rlp; + if (getrlimit(RLIMIT_DATA,&rlp) == -1) + perror("Warning: getrlimit"); + else { + rlp.rlim_cur=33554432; + if (setrlimit(RLIMIT_DATA,&rlp) == -1) + perror("Warning: setrlimit"); + } + } +#endif +#ifdef HAVE_SBRK + mem_start = (unsigned long) sbrk(0); +#endif + + if(verbose) fprintf(stderr,"%s\n", version_string); + + if( (cdwrite_data != NULL && merge_image == NULL) + || (cdwrite_data == NULL && merge_image != NULL) ) + { + fprintf(stderr,"Multisession usage bug - both -C and -M must be specified.\n"); + exit(0); + } + + /* The first step is to scan the directory tree, and take some notes */ + + scan_tree = argv[optind]; + +#ifdef ADD_FILES + if (add_file_file) { + add_file(add_file_file); + } + add_file_list (argc, argv, optind+1); +#endif + + if(!scan_tree){ + usage(); + exit(1); + }; + +#ifndef VMS + if(scan_tree[strlen(scan_tree)-1] != '/') { + scan_tree = (char *) e_malloc(strlen(argv[optind])+2); + strcpy(scan_tree, argv[optind]); + strcat(scan_tree, "/"); + }; +#endif + + if(use_RockRidge){ +#if 1 + extension_record = generate_rr_extension_record("RRIP_1991A", + "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", + "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size); +#else + extension_record = generate_rr_extension_record("IEEE_P1282", + "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", + "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size); +#endif + } + + /* + * See if boot catalog file exists in root directory, if not + * we will create it. + */ + if (use_eltorito) + init_boot_catalog(argv[optind]); + + /* + * Find the device and inode number of the root directory. + * Record this in the hash table so we don't scan it more than + * once. + */ + stat_filter(argv[optind], &statbuf); + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + + memset(&de, 0, sizeof(de)); + + de.filedir = root; /* We need this to bootstrap */ + + if( merge_image != NULL ) + { + mrootp = merge_isofs(merge_image); + if( mrootp == NULL ) + { + /* + * Complain and die. + */ + fprintf(stderr,"Unable to open previous session image %s\n", + merge_image); + exit(1); + } + + memcpy(&de.isorec.extent, mrootp->extent, 8); + } + + /* + * Scan the actual directory (and any we find below it) + * for files to write out to the output image. + */ + if (!scan_directory_tree(argv[optind], &de, mrootp)) + { + exit(1); + } + + /* + * Fix a couple of things in the root directory so that everything + * is self consistent. + */ + root->self = root->contents; /* Fix this up so that the path tables get done right */ + + if(reloc_dir) sort_n_finish(reloc_dir); + + if (goof) exit(1); + + /* + * OK, ready to write the file. Open it up, and generate the thing. + */ + if (outfile){ + discimage = fopen(outfile, "w"); + if (!discimage){ + fprintf(stderr,"Unable to open disc image file\n"); + exit(1); + + }; + } else + discimage = stdout; + + /* Now assign addresses on the disc for the path table. */ + + path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11; + if (path_blocks & 1) path_blocks++; + + path_table[0] = session_start + 0x14; + path_table[1] = 0; + path_table[2] = path_table[0] + path_blocks; + path_table[3] = 0; + + last_extent += path_table[2] - session_start + path_blocks; + /* The next free block */ + + /* The next step is to go through the directory tree and assign extent + numbers for all of the directories */ + + assign_directory_addresses(root); + + if(extension_record) { + struct directory_entry * s_entry; + extension_record_extent = last_extent++; + s_entry = root->contents; + set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24, + extension_record_extent); + set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8, + extension_record_size); + }; + + if (use_RockRidge && reloc_dir) + finish_cl_pl_entries(); + + /* Now we generate the path tables that are used by DOS to improve directory + access times. */ + generate_path_tables(); + + /* Generate root record for volume descriptor. */ + generate_root_record(); + + if (verbose) + dump_tree(root); + + if( in_image != NULL ) + { + fclose(in_image); + } + + iso_write(discimage); + +#ifdef HAVE_SBRK + fprintf(stderr,"Max brk space used %x\n", + (unsigned int)(((unsigned long)sbrk(0)) - mem_start)); +#endif + fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9); +#ifdef VMS + return 1; +#else + return 0; +#endif +} + +void * +FDECL1(e_malloc, size_t, size) +{ +void* pt = 0; + if( (size > 0) && ((pt=malloc(size))==NULL) ) { + fprintf(stderr, "Not enough memory\n"); + exit (1); + } +return pt; +} diff --git a/gnu/usr.sbin/mkisofs/mkisofs.h b/gnu/usr.sbin/mkisofs/mkisofs.h new file mode 100644 index 00000000000..983ccf57f5d --- /dev/null +++ b/gnu/usr.sbin/mkisofs/mkisofs.h @@ -0,0 +1,334 @@ +/* $OpenBSD: mkisofs.h,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * Header file mkisofs.h - assorted structure definitions and typecasts. + + 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. */ + +/* + * $From: mkisofs.h,v 1.4 1997/03/08 17:29:12 eric Rel $ + */ + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +#include <stdio.h> + +/* This symbol is used to indicate that we do not have things like + symlinks, devices, and so forth available. Just files and dirs */ + +#ifdef VMS +#define NON_UNIXFS +#endif + +#ifdef DJGPP +#define NON_UNIXFS +#endif + +#ifdef VMS +#include <sys/dir.h> +#define dirent direct +#else +#include <dirent.h> +#endif + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef linux +#include <sys/dir.h> +#endif + +#ifdef ultrix +extern char *strdup(); +#endif + +#ifdef __STDC__ +#define DECL(NAME,ARGS) NAME ARGS +#define FDECL1(NAME,TYPE0, ARG0) \ + NAME(TYPE0 ARG0) +#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) \ + NAME(TYPE0 ARG0, TYPE1 ARG1) +#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2) +#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3) +#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4) +#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \ + NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4, TYPE5 ARG5) +#else +#define DECL(NAME,ARGS) NAME() +#define FDECL1(NAME,TYPE0, ARG0) NAME(ARG0) TYPE0 ARG0; +#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) NAME(ARG0, ARG1) TYPE0 ARG0; TYPE1 ARG1; +#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \ + NAME(ARG0, ARG1, ARG2) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; +#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \ + NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; +#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \ + NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; +#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \ + NAME(ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; TYPE5 ARG5; +#define const +#endif + + +#ifdef __svr4__ +#include <stdlib.h> +#else +extern int optind; +extern char *optarg; +/* extern int getopt (int __argc, char **__argv, char *__optstring); */ +#endif + +#include "iso9660.h" +#include "defaults.h" + +struct directory_entry{ + struct directory_entry * next; + struct iso_directory_record isorec; + unsigned int starting_block; + unsigned int size; + unsigned int priority; + char * name; + char * table; + char * whole_name; + struct directory * filedir; + struct directory_entry * parent_rec; + unsigned int de_flags; + ino_t inode; /* Used in the hash table */ + dev_t dev; /* Used in the hash table */ + unsigned char * rr_attributes; + unsigned int rr_attr_size; + unsigned int total_rr_attr_size; +}; + +struct file_hash{ + struct file_hash * next; + ino_t inode; /* Used in the hash table */ + dev_t dev; /* Used in the hash table */ + unsigned int starting_block; + unsigned int size; +}; + +/* + * This structure describes one complete directory. It has pointers + * to other directories in the overall tree so that it is clear where + * this directory lives in the tree, and it also must contain pointers + * to the contents of the directory. Note that subdirectories of this + * directory exist twice in this stucture. Once in the subdir chain, + * and again in the contents chain. + */ +struct directory{ + struct directory * next; /* Next directory at same level as this one */ + struct directory * subdir; /* First subdirectory in this directory */ + struct directory * parent; + struct directory_entry * contents; + struct directory_entry * self; + char * whole_name; /* Entire path */ + char * de_name; /* Entire path */ + unsigned int ce_bytes; /* Number of bytes of CE entries reqd for this dir */ + unsigned int depth; + unsigned int size; + unsigned int extent; + unsigned short path_index; +}; + +struct deferred{ + struct deferred * next; + unsigned int starting_block; + char * name; + struct directory * filedir; + unsigned int flags; +}; + +extern int goof; +extern struct directory * root; +extern struct directory * reloc_dir; +extern unsigned int next_extent; +extern unsigned int last_extent; +extern unsigned int last_extent_written; +extern unsigned int session_start; +extern unsigned int path_table_size; +extern unsigned int path_table[4]; +extern unsigned int path_blocks; +extern char * path_table_l; +extern char * path_table_m; +extern struct iso_directory_record root_record; + +extern int use_eltorito; +extern int use_RockRidge; +extern int rationalize; +extern int follow_links; +extern int verbose; +extern int all_files; +extern int generate_tables; +extern int omit_period; +extern int omit_version_number; +extern int transparent_compression; +extern int RR_relocation_depth; +extern int full_iso9660_filenames; + +/* tree.c */ +extern int DECL(stat_filter, (char *, struct stat *)); +extern void DECL(sort_n_finish,(struct directory *)); +extern void finish_cl_pl_entries(); +extern int DECL(scan_directory_tree,(char * path, + struct directory_entry * self, + struct iso_directory_record *)); +extern void DECL(generate_iso9660_directories,(struct directory *, FILE*)); +extern void DECL(dump_tree,(struct directory * node)); +extern struct directory_entry * DECL(search_tree_file, (struct + directory * node,char * filename)); + +/* eltorito.c */ +extern void DECL(init_boot_catalog, (const char * path )); +extern void DECL(get_torito_desc, (struct eltorito_boot_descriptor * path )); + +/* write.c */ +extern void DECL(assign_directory_addresses,(struct directory * root)); +extern int DECL(get_733,(char *)); +extern int DECL(isonum_733,(unsigned char *)); +extern void DECL(set_723,(char *, unsigned int)); +extern void DECL(set_731,(char *, unsigned int)); +extern void DECL(set_721,(char *, unsigned int)); +extern void DECL(set_733,(char *, unsigned int)); +extern void DECL(sort_directory,(struct directory_entry **)); +extern void generate_root_record(); +extern void DECL(generate_one_directory,(struct directory *, FILE*)); +extern void generate_path_tables(); +extern int DECL(iso_write,(FILE * outfile)); +extern void DECL(memcpy_max, (char *, char *, int)); + + +/* multi.c */ + +extern FILE * in_image; +extern struct iso_directory_record * + DECL(merge_isofs,(char * path)); + +extern int DECL(free_mdinfo, (struct directory_entry **, int len)); + +extern struct directory_entry ** + DECL(read_merging_directory,(struct iso_directory_record *, int*)); +extern void + DECL(merge_remaining_entries, (struct directory *, + struct directory_entry **, int)); + +/* match.c */ +extern int DECL(matches, (char *)); +extern void DECL(add_match, (char *)); + +/* files.c */ +struct dirent * DECL(readdir_add_files, (char **, char *, DIR *)); + +/* */ + +extern int DECL(iso9660_file_length,(const char* name, + struct directory_entry * sresult, int flag)); +extern int DECL(iso9660_date,(char *, time_t)); +extern void DECL(add_hash,(struct directory_entry *)); +extern struct file_hash * DECL(find_hash,(dev_t, ino_t)); +extern void DECL(add_directory_hash,(dev_t, ino_t)); +extern struct file_hash * DECL(find_directory_hash,(dev_t, ino_t)); +extern void flush_file_hash(); +extern int DECL(delete_file_hash,(struct directory_entry *)); +extern struct directory_entry * DECL(find_file_hash,(char *)); +extern void DECL(add_file_hash,(struct directory_entry *)); +extern int DECL(generate_rock_ridge_attributes,(char *, char *, + struct directory_entry *, + struct stat *, struct stat *, + int deep_flag)); +extern char * DECL(generate_rr_extension_record,(char * id, char * descriptor, + char * source, int * size)); + +extern int DECL(check_prev_session, (struct directory_entry **, int len, + struct directory_entry *, + struct stat *, + struct stat *, + struct directory_entry **)); + +extern char * extension_record; +extern int extension_record_extent; +extern int n_data_extents; + +/* These are a few goodies that can be specified on the command line, and are + filled into the root record */ + +extern char * preparer; +extern char * publisher; +extern char * copyright; +extern char * biblio; +extern char * abstract; +extern char * appid; +extern char * volset_id; +extern char * system_id; +extern char * volume_id; +extern char * boot_catalog; +extern char * boot_image; + +extern void * DECL(e_malloc,(size_t)); + + +#define SECTOR_SIZE (2048) +#define ROUND_UP(X) ((X + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1)) + +#define NEED_RE 1 +#define NEED_PL 2 +#define NEED_CL 4 +#define NEED_CE 8 +#define NEED_SP 16 + +#define PREV_SESS_DEV (sizeof(dev_t) >= 4 ? 0x7ffffffd : 0x7ffd) +#define TABLE_INODE (sizeof(ino_t) >= 4 ? 0x7ffffffe : 0x7ffe) +#define UNCACHED_INODE (sizeof(ino_t) >= 4 ? 0x7fffffff : 0x7fff) +#define UNCACHED_DEVICE (sizeof(dev_t) >= 4 ? 0x7fffffff : 0x7fff) + +#ifdef VMS +#define STAT_INODE(X) (X.st_ino[0]) +#define PATH_SEPARATOR ']' +#define SPATH_SEPARATOR "" +#else +#define STAT_INODE(X) (X.st_ino) +#define PATH_SEPARATOR '/' +#define SPATH_SEPARATOR "/" +#endif + +/* + * When using multi-session, indicates that we can reuse the + * TRANS.TBL information for this directory entry. If this flag + * is set for all entries in a directory, it means we can just + * reuse the TRANS.TBL and not generate a new one. + */ +#define SAFE_TO_REUSE_TABLE_ENTRY 1 +/* + * Volume sequence number to use in all of the iso directory records. + */ +#define DEF_VSN 1 + +/* + * Make sure we have a definition for this. If not, take a very conservative + * guess. From what I can tell SunOS is the only one with this trouble. + */ +#ifndef NAME_MAX +#ifdef FILENAME_MAX +#define NAME_MAX FILENAME_MAX +#else +#define NAME_MAX 128 +#endif +#endif diff --git a/gnu/usr.sbin/mkisofs/mkisofs.spec b/gnu/usr.sbin/mkisofs/mkisofs.spec new file mode 100644 index 00000000000..3c9c8e18d5b --- /dev/null +++ b/gnu/usr.sbin/mkisofs/mkisofs.spec @@ -0,0 +1,45 @@ +# $OpenBSD: mkisofs.spec,v 1.1 1997/09/15 06:01:53 downsj Exp $ +# $From: mkisofs.spec,v 1.3 1997/04/10 02:46:57 eric Rel $ +Summary: Creates a ISO9660 filesystem image +Name: mkisofs +Version: 1.11 +Release: 1 +Copyright: GPL +Group: Utilities/System +Source: tsx-11.mit.edu:/pub/linux/packages/mkisofs/mkisofs-1.11.tar.gz + +%description +This is the mkisofs package. It is used to create ISO 9660 +file system images for creating CD-ROMs. Now includes support +for making bootable "El Torito" CD-ROMs. + +%prep +%setup + +%build +./configure --prefix=/usr +make + +%install +make install +strip /usr/bin/mkisofs + +%changelog + +* Tue Feb 25 1997 Michael Fulbright <msf@redhat.com> + + Updated to 1.10b7. + +* Wed Feb 12 1997 Michael Fulbright <msf@redhat.com> + + Updated to 1.10b3. + +* Wed Feb 12 1997 Michael Fulbright <msf@redhat.com> + + Added %doc line to spec file (was missing all docs before). + +%files +%doc COPYING ChangeLog README README.eltorito TODO +/usr/bin/mkisofs +/usr/man/man8/mkisofs.8 + diff --git a/gnu/usr.sbin/mkisofs/multi.c b/gnu/usr.sbin/mkisofs/multi.c new file mode 100644 index 00000000000..e7af4bba399 --- /dev/null +++ b/gnu/usr.sbin/mkisofs/multi.c @@ -0,0 +1,989 @@ +/* $OpenBSD: multi.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * File multi.c - scan existing iso9660 image and merge into + * iso9660 filesystem. Used for multisession support. + * + * Written by Eric Youngdale (1996). + * + * 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[] ="$From: multi.c,v 1.4 1997/03/08 17:08:53 eric Rel $"; + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <sys/stat.h> + +#include "config.h" + +#ifndef VMS + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#else +#include <sys/file.h> +#include <vms/fabdef.h> +#include "vms.h" +extern char * strdup(const char *); +#endif + +#include "mkisofs.h" +#include "iso9660.h" + +#define TF_CREATE 1 +#define TF_MODIFY 2 +#define TF_ACCESS 4 +#define TF_ATTRIBUTES 8 + +static int DECL(get_session_start, (int *)); +static int DECL(merge_old_directory_into_tree, (struct directory_entry *, + struct directory *)); + +static int +isonum_711 (unsigned char * p) +{ + return (*p & 0xff); +} + +int +isonum_721 (unsigned char * p) +{ + return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); +} + +static int +isonum_723 (unsigned char * p) +{ +#if 0 + if (p[0] != p[3] || p[1] != p[2]) { + fprintf (stderr, "invalid format 7.2.3 number\n"); + exit (1); + } +#endif + return (isonum_721 (p)); +} + +int +isonum_731 (unsigned char * p) +{ + return ((p[0] & 0xff) + | ((p[1] & 0xff) << 8) + | ((p[2] & 0xff) << 16) + | ((p[3] & 0xff) << 24)); +} + +int +isonum_733 (unsigned char * p) +{ + return (isonum_731 (p)); +} + +FILE * in_image = NULL; + +#ifndef USE_SCG +/* + * Don't define readsecs if mkisofs is linked with + * the SCSI library. + * readsecs() will be implemented as SCSI command in this case. + * + * Use global var in_image directly in readsecs() + * the SCSI equivalent will not use a FILE* for I/O. + * + * The main point of this pointless abstraction is that Solaris won't let + * you read 2K sectors from the cdrom driver. The fact that 99.9% of the + * discs out there have a 2K sectorsize doesn't seem to matter that much. + * Anyways, this allows the use of a scsi-generics type of interface on + * Solaris. + */ +static int +readsecs(int startsecno, void *buffer, int sectorcount) +{ + int f = fileno(in_image); + + if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) { + fprintf(stderr," Seek error on old image\n"); + exit(10); + } + return (read(f, buffer, sectorcount * SECTOR_SIZE)); +} +#endif + +/* + * Parse the RR attributes so we can find the file name. + */ +static int +FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt) +{ + int cont_extent, cont_offset, cont_size; + char name_buf[256]; + + cont_extent = cont_offset = cont_size = 0; + + while(len >= 4){ + if(pnt[3] != 1) { + printf("**BAD RRVERSION"); + return -1; + }; + if(strncmp((char *) pnt, "NM", 2) == 0) { + strncpy(name_buf, (char *) pnt+5, pnt[2] - 5); + name_buf[pnt[2] - 5] = 0; + dpnt->name = strdup(name_buf); + return 0; + } + + if(strncmp((char *) pnt, "CE", 2) == 0) { + cont_extent = isonum_733(pnt+4); + cont_offset = isonum_733(pnt+12); + cont_size = isonum_733(pnt+20); + }; + + len -= pnt[2]; + pnt += pnt[2]; + if(len <= 3 && cont_extent) { + unsigned char sector[SECTOR_SIZE]; + readsecs(cont_extent, sector, 1); + parse_rr(§or[cont_offset], cont_size, dpnt); + }; + }; + return 0; +} + + +static int +FDECL4(check_rr_dates, struct directory_entry *, dpnt, + struct directory_entry *, current, + struct stat *, statbuf, + struct stat *,lstatbuf) +{ + int cont_extent, cont_offset, cont_size; + int offset; + unsigned char * pnt; + int len; + int same_file; + int same_file_type; + mode_t mode; + char time_buf[7]; + + + cont_extent = cont_offset = cont_size = 0; + same_file = 1; + same_file_type = 1; + + pnt = dpnt->rr_attributes; + len = dpnt->rr_attr_size; + /* + * We basically need to parse the rr attributes again, and + * dig out the dates and file types. + */ + while(len >= 4){ + if(pnt[3] != 1) { + printf("**BAD RRVERSION"); + return -1; + }; + + /* + * If we have POSIX file modes, make sure that the file type + * is the same. If it isn't, then we must always + * write the new file. + */ + if(strncmp((char *) pnt, "PX", 2) == 0) { + mode = isonum_733(pnt + 4); + if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) ) + { + same_file_type = 0; + same_file = 0; + } + } + + if(strncmp((char *) pnt, "TF", 2) == 0) { + offset = 5; + if( pnt[4] & TF_CREATE ) + { + iso9660_date((char *) time_buf, lstatbuf->st_ctime); + if(memcmp(time_buf, pnt+offset, 7) == 0) + same_file = 0; + offset += 7; + } + if( pnt[4] & TF_MODIFY ) + { + iso9660_date((char *) time_buf, lstatbuf->st_mtime); + if(memcmp(time_buf, pnt+offset, 7) == 0) + same_file = 0; + offset += 7; + } + } + + if(strncmp((char *) pnt, "CE", 2) == 0) { + cont_extent = isonum_733(pnt+4); + cont_offset = isonum_733(pnt+12); + cont_size = isonum_733(pnt+20); + }; + + len -= pnt[2]; + pnt += pnt[2]; + if(len <= 3 && cont_extent) { + unsigned char sector[SECTOR_SIZE]; + + readsecs(cont_extent, sector, 1); + parse_rr(§or[cont_offset], cont_size, dpnt); + }; + }; + + /* + * If we have the same fundamental file type, then it is clearly + * safe to reuse the TRANS.TBL entry. + */ + if( same_file_type ) + { + current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; + } + + return same_file; +} + +struct directory_entry ** +FDECL2(read_merging_directory, struct iso_directory_record *, mrootp, + int *, nent) +{ + unsigned char * cpnt; + unsigned char * cpnt1; + char * dirbuff; + int i; + struct iso_directory_record * idr; + int len; + struct directory_entry **pnt; + int rlen; + struct directory_entry **rtn; + int seen_rockridge; + unsigned char * tt_buf; + int tt_extent; + int tt_size; + + /* + * First, allocate a buffer large enough to read in the entire + * directory. + */ + dirbuff = (char *) e_malloc(isonum_733(mrootp->size)); + + readsecs(isonum_733(mrootp->extent), dirbuff, + isonum_733(mrootp->size)/SECTOR_SIZE); + + /* + * Next look over the directory, and count up how many entries we + * have. + */ + len = isonum_733(mrootp->size); + i = 0; + *nent = 0; + while(i < len ) + { + idr = (struct iso_directory_record *) &dirbuff[i]; + if(idr->length[0] == 0) + { + i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); + continue; + } + (*nent)++; + i += idr->length[0]; + } + + /* + * Now allocate the buffer which will hold the array we are + * about to return. + */ + rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn)); + + /* + * Finally, scan the directory one last time, and pick out the + * relevant bits of information, and store it in the relevant + * bits of the structure. + */ + i = 0; + pnt = rtn; + tt_extent = 0; + seen_rockridge = 0; + tt_size = 0; + while(i < len ) + { + idr = (struct iso_directory_record *) &dirbuff[i]; + if(idr->length[0] == 0) + { + i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); + continue; + } + *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn)); + (*pnt)->next = NULL; + (*pnt)->isorec = *idr; + (*pnt)->starting_block = isonum_733(idr->extent); + (*pnt)->size = isonum_733(idr->size); + (*pnt)->priority = 0; + (*pnt)->name = NULL; + (*pnt)->table = NULL; + (*pnt)->whole_name = NULL; + (*pnt)->filedir = NULL; + (*pnt)->parent_rec = NULL; + /* + * Set this information so that we correctly cache previous + * session bits of information. + */ + (*pnt)->inode = (*pnt)->starting_block; + (*pnt)->dev = PREV_SESS_DEV; + (*pnt)->rr_attributes = NULL; + (*pnt)->rr_attr_size = 0; + (*pnt)->total_rr_attr_size = 0; + (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY; + + /* + * Check for and parse any RR attributes for the file. + * All we are really looking for here is the original name + * of the file. + */ + rlen = idr->length[0] & 0xff; + cpnt = (unsigned char *) idr; + + rlen -= sizeof(struct iso_directory_record); + cpnt += sizeof(struct iso_directory_record); + + rlen += sizeof(idr->name); + cpnt -= sizeof(idr->name); + + rlen -= idr->name_len[0]; + cpnt += idr->name_len[0]; + + if((idr->name_len[0] & 1) == 0){ + cpnt++; + rlen--; + }; + + if( rlen != 0 ) + { + (*pnt)->total_rr_attr_size = (*pnt)->rr_attr_size = rlen; + (*pnt)->rr_attributes = e_malloc(rlen); + memcpy((*pnt)->rr_attributes, cpnt, rlen); + seen_rockridge = 1; + } + + /* + * Now zero out the remainder of the name field. + */ + cpnt = (unsigned char *) &(*pnt)->isorec.name; + cpnt += idr->name_len[0]; + memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]); + + parse_rr((*pnt)->rr_attributes, rlen, *pnt); + + if( ((*pnt)->isorec.name_len[0] == 1) + && ( ((*pnt)->isorec.name[0] == 0) + || ((*pnt)->isorec.name[0] == 1)) ) + { + if( (*pnt)->name != NULL ) + { + free((*pnt)->name); + } + if( (*pnt)->isorec.name[0] == 0 ) + { + (*pnt)->name = strdup("."); + } + else + { + (*pnt)->name = strdup(".."); + } + } + + if( strncmp(idr->name, "TRANS.TBL", 9) == 0) + { + if( (*pnt)->name != NULL ) + { + free((*pnt)->name); + } + (*pnt)->name = strdup("<translation table>"); + tt_extent = isonum_733(idr->extent); + tt_size = isonum_733(idr->size); + } + + pnt++; + i += idr->length[0]; + } + + /* + * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it + * to get the filenames of the files. Also, save the table info, just + * in case we need to use it. + */ + if( tt_extent != 0 && tt_size != 0 ) + { + tt_buf = (unsigned char *) e_malloc(tt_size); + readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE); + + /* + * Loop through the file, examine each entry, and attempt to + * attach it to the correct entry. + */ + cpnt = tt_buf; + cpnt1 = tt_buf; + while( cpnt - tt_buf < tt_size ) + { + while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++; + *cpnt1 = '\0'; + + for(pnt = rtn, i = 0; i <*nent; i++, pnt++) + { + rlen = isonum_711((*pnt)->isorec.name_len); + if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name, + rlen) == 0 + && cpnt[2+rlen] == ' ') + { + (*pnt)->table = strdup((char *) cpnt); + if( (*pnt)->name == NULL ) + { + (*pnt)->name = strdup((char *) cpnt+37); + } + break; + } + } + cpnt = cpnt1 + 1; + cpnt1 = cpnt; + } + + free(tt_buf); + } + else if( !seen_rockridge ) + { + /* + * This is a fatal error right now because we must have some mechanism + * for taking the 8.3 names back to the original unix names. + * In principle we could do this the hard way, and try and translate + * the unix names that we have seen forwards, but this would be + * a real pain in the butt. + */ + fprintf(stderr,"Previous session must have either Rock Ridge (-R) or\n"); + fprintf(stderr,"TRANS.TBL (-T) for mkisofs to be able to correctly\n"); + fprintf(stderr,"generate additional sessions.\n"); + exit(3); + } + + if( dirbuff != NULL ) + { + free(dirbuff); + } + + return rtn; +} + +/* + * Free any associated data related to the structures. + */ +int +FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len ) +{ + int i; + struct directory_entry **p; + + p = ptr; + for(i=0; i<len; i++, p++) + { + /* + * If the tree-handling code decided that it needed an entry, + * it will have removed it from the list. Thus we must allow + * for null pointers here. + */ + if( *p == NULL ) + { + continue; + } + + if( (*p)->name != NULL ) + { + free((*p)->name); + } + + if( (*p)->rr_attributes != NULL ) + { + free((*p)->rr_attributes); + } + + if( (*p)->table != NULL ) + { + free((*p)->table); + } + + free(*p); + + } + + free(ptr); + return 0; +} + +/* + * Search the list to see if we have any entries from the previous + * session that match this entry. If so, copy the extent number + * over so we don't bother to write it out to the new session. + */ + +int +FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len, + struct directory_entry *, curr_entry, + struct stat *, statbuf, struct stat *, lstatbuf, + struct directory_entry **, odpnt) +{ + int i; + + for( i=0; i < len; i++ ) + { + if( ptr[i] == NULL ) + { + continue; + } + +#if 0 + if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 + && ptr[i]->name[0] == '\0' ) + { + continue; + } + if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 + && ptr[i]->name[0] == 1) + { + continue; + } +#else + if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 ) + { + continue; + } + if( ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0 ) + { + continue; + } +#endif + + if( ptr[i]->name != NULL + && strcmp(ptr[i]->name, curr_entry->name) != 0 ) + { + continue; + } + + /* + * We know that the files have the same name. If they also have + * the same file type (i.e. file, dir, block, etc), then we + * can safely reuse the TRANS.TBL entry for this file. + * The check_rr_dates function will do this for us. + * + * Verify that the file type and dates are consistent. + * If not, we probably have a different file, and we need + * to write it out again. + */ + if( (ptr[i]->rr_attributes != NULL) + && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) ) + { + goto found_it; + } + + + /* + * Verify size and timestamp. If rock ridge is in use, we need + * to compare dates from RR too. Directories are special, we + * calculate their size later. + */ + if( (curr_entry->isorec.flags[0] & 2) == 0 + && ptr[i]->size != curr_entry->size ) + { + goto found_it; + } + + if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 ) + { + goto found_it; + } + + /* + * Never ever reuse directory extents. See comments in + * tree.c for an explaination of why this must be the case. + */ + if( (curr_entry->isorec.flags[0] & 2) != 0 ) + { + goto found_it; + } + + memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8); + curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; + goto found_it; + } + return 0; + +found_it: + if( odpnt != NULL ) + { + *odpnt = ptr[i]; + } + else + { + free(ptr[i]); + } + ptr[i] = NULL; + return 0; +} + +/* + * merge_isofs: Scan an existing image, and return a pointer + * to the root directory for this image. + */ +struct iso_directory_record * FDECL1(merge_isofs, char *, path) +{ + char buffer[SECTOR_SIZE]; + int file_addr; + int i; + struct iso_primary_descriptor * pri = NULL; + struct iso_directory_record * rootp; + struct iso_volume_descriptor * vdp; + + /* + * Start by opening up the image and searching for the volume header. + * Ultimately, we need to search for volume headers in multiple places + * because we might be starting with a multisession image. + * FIXME(eric). + */ + + in_image = fopen(path, "rb"); + if( in_image == NULL ) + { + return NULL; + } + + get_session_start(&file_addr); + + for(i = 0; i< 100; i++) + { + if (readsecs(file_addr/SECTOR_SIZE, &buffer, + sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer)) + { + fprintf(stderr," Read error on old image %s\n", path); + exit(10); + } + + vdp = (struct iso_volume_descriptor *)buffer; + + if( (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) + && (isonum_711(vdp->type) == ISO_VD_PRIMARY) ) + { + break; + } + file_addr += SECTOR_SIZE; + } + + if( i == 100 ) + { + return NULL; + } + + pri = (struct iso_primary_descriptor *)vdp; + + /* + * Check the blocksize of the image to make sure it is compatible. + */ + if( (isonum_723 (pri->logical_block_size) != SECTOR_SIZE) + || (isonum_723 (pri->volume_set_size) != 1) ) + { + return NULL; + } + + /* + * Get the location and size of the root directory. + */ + rootp = (struct iso_directory_record *) + malloc(sizeof(struct iso_directory_record)); + + memcpy(rootp, pri->root_directory_record, sizeof(*rootp)); + + return rootp; +} + +void FDECL3(merge_remaining_entries, struct directory *, this_dir, + struct directory_entry **, pnt, + int, n_orig) +{ + int i; + struct directory_entry * s_entry; + unsigned int ttbl_extent = 0; + unsigned int ttbl_index = 0; + + /* + * Whatever is leftover in the list needs to get merged back + * into the directory. + */ + for( i=0; i < n_orig; i++ ) + { + if( pnt[i] == NULL ) + { + continue; + } + + if( pnt[i]->name != NULL + && strcmp(pnt[i]->name, "<translation table>") == 0 ) + { + ttbl_extent = isonum_733(pnt[i]->isorec.extent); + ttbl_index = i; + continue; + } + /* + * Skip directories for now - these need to be treated + * differently. + */ + if( (pnt[i]->isorec.flags[0] & 2) != 0 ) + { + /* + * FIXME - we need to insert this directory into the + * tree, so that the path tables we generate will + * be correct. + */ + if( (strcmp(pnt[i]->name, ".") == 0) + || (strcmp(pnt[i]->name, "..") == 0) ) + { + free(pnt[i]); + pnt[i] = NULL; + continue; + } + else + { + merge_old_directory_into_tree(pnt[i], this_dir); + } + } + pnt[i]->next = this_dir->contents; + pnt[i]->filedir = this_dir; + this_dir->contents = pnt[i]; + pnt[i] = NULL; + } + + + /* + * If we don't have an entry for the translation table, then + * don't bother trying to copy the starting extent over. + * Note that it is possible that if we are copying the entire + * directory, the entry for the translation table will have already + * been inserted into the linked list and removed from the old + * entries list, in which case we want to leave the extent number + * as it was before. + */ + if( ttbl_extent == 0 ) + { + return; + } + + /* + * Finally, check the directory we are creating to see whether + * there are any new entries in it. If there are not, we can + * reuse the same translation table. + */ + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + /* + * Don't care about '.' or '..'. They are never in the table + * anyways. + */ + if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 ) + { + continue; + } + if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 ) + { + continue; + } + if( strcmp(s_entry->name, "<translation table>") == 0) + { + continue; + } + if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 ) + { + return; + } + } + + /* + * Locate the translation table, and re-use the same extent. + * It isn't clear that there should ever be one in there already + * so for now we try and muddle through the best we can. + */ + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + if( strcmp(s_entry->name, "<translation table>") == 0) + { + fprintf(stderr,"Should never get here\n"); + set_733(s_entry->isorec.extent, ttbl_extent); + return; + } + } + + pnt[ttbl_index]->next = this_dir->contents; + pnt[ttbl_index]->filedir = this_dir; + this_dir->contents = pnt[ttbl_index]; + pnt[ttbl_index] = NULL; +} + + +/* + * Here we have a case of a directory that has completely disappeared from + * the face of the earth on the tree we are mastering from. Go through and + * merge it into the tree, as well as everything beneath it. + * + * Note that if a directory has been moved for some reason, this will + * incorrectly pick it up and attempt to merge it back into the old + * location. FIXME(eric). + */ +static int +FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, + struct directory *, parent) +{ + struct directory_entry **contents = NULL; + int i; + int n_orig; + struct directory * this_dir, *next_brother; + char whole_path[1024]; + + this_dir = (struct directory *) e_malloc(sizeof(struct directory)); + this_dir->next = NULL; + this_dir->subdir = NULL; + this_dir->self = dpnt; + this_dir->contents = NULL; + this_dir->size = 0; + this_dir->extent = 0; + this_dir->depth = parent->depth + 1; + this_dir->parent = parent; + if(!parent->subdir) + parent->subdir = this_dir; + else { + next_brother = parent->subdir; + while(next_brother->next) next_brother = next_brother->next; + next_brother->next = this_dir; + } + + /* + * Set the name for this directory. + */ + strcpy(whole_path, parent->de_name); + strcat(whole_path, SPATH_SEPARATOR); + strcat(whole_path, dpnt->name); + this_dir->de_name = strdup(whole_path); + + /* + * Now fill this directory using information from the previous + * session. + */ + contents = read_merging_directory(&dpnt->isorec, &n_orig); + /* + * Start by simply copying the '.', '..' and non-directory + * entries to this directory. Technically we could let + * merge_remaining_entries handle this, but it gets rather confused + * by the '.' and '..' entries. + */ + for(i=0; i < n_orig; i ++ ) + { + /* + * We can always reuse the TRANS.TBL in this particular case. + */ + contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; + + if( ((contents[i]->isorec.flags[0] & 2) != 0) + && (i >= 2) ) + { + continue; + } + + /* + * If we have a directory, don't reuse the extent number. + */ + if( (contents[i]->isorec.flags[0] & 2) != 0 ) + { + memset(contents[i]->isorec.extent, 0, 8); + } + + contents[i]->next = this_dir->contents; + contents[i]->filedir = this_dir; + this_dir->contents = contents[i]; + contents[i] = NULL; + } + + /* + * Zero the extent number for ourselves. + */ + memset(dpnt->isorec.extent, 0, 8); + + /* + * Anything that is left are other subdirectories that need to be merged. + */ + merge_remaining_entries(this_dir, contents, n_orig); + free_mdinfo(contents, n_orig); + sort_n_finish(this_dir); + + return 0; +} + + +char * cdwrite_data = NULL; + +static int +FDECL1(get_session_start, int *, file_addr) +{ + char * pnt; + +#ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS + /* + * FIXME(eric). We need to coordinate with cdwrite to obtain + * the parameters. For now, we assume we are writing the 2nd session, + * so we start from the session that starts at 0. + */ + + *file_addr = (16 << 11); + + /* + * We need to coordinate with cdwrite to get the next writable address + * from the device. Here is where we use it. + */ + session_start = last_extent = last_extent_written = cdwrite_result(); + +#else + + if( cdwrite_data == NULL ) + { + fprintf(stderr,"Special parameters for cdwrite not specified with -C\n"); + exit(1); + } + + /* + * Next try and find the ',' in there which delimits the two numbers. + */ + pnt = strchr(cdwrite_data, ','); + if( pnt == NULL ) + { + fprintf(stderr, "Malformed cdwrite parameters\n"); + exit(1); + } + + *pnt = '\0'; + *file_addr = atol(cdwrite_data) * SECTOR_SIZE; + pnt++; + + session_start = last_extent = last_extent_written = atol(pnt); + + pnt--; + *pnt = ','; + +#endif + return 0; +} diff --git a/gnu/usr.sbin/mkisofs/name.c b/gnu/usr.sbin/mkisofs/name.c new file mode 100644 index 00000000000..ff02cd1f1aa --- /dev/null +++ b/gnu/usr.sbin/mkisofs/name.c @@ -0,0 +1,376 @@ +/* $OpenBSD: name.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * File name.c - map full Unix file names to unique 8.3 names that + * would be valid on DOS. + * + + 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[] ="$From: name.c,v 1.4 1997/04/10 02:58:26 eric Rel $"; + +#include "mkisofs.h" + +#include <ctype.h> + +extern int allow_leading_dots; + +/* + * Function: iso9660_file_length + * + * Purpose: Map file name to 8.3 format, return length + * of result. + * + * Arguments: name file name we need to map. + * sresult directory entry structure to contain mapped name. + * dirflag flag indicating whether this is a directory or not. + * + * Notes: This procedure probably needs to be rationalized somehow. + * New options to affect the behavior of this function + * would also be nice to have. + */ +int FDECL3(iso9660_file_length, + const char*, name, + struct directory_entry *, sresult, + int, dirflag) +{ + char * c; + int chars_after_dot = 0; + int chars_before_dot = 0; + int current_length = 0; + int extra = 0; + int ignore = 0; + char * last_dot; + const char * pnt; + int priority = 32767; + char * result; + int seen_dot = 0; + int seen_semic = 0; + int tildes = 0; + + result = sresult->isorec.name; + + /* + * For the '.' entry, generate the correct record, and return + * 1 for the length. + */ + if(strcmp(name,".") == 0) + { + if(result) + { + *result = 0; + } + return 1; + } + + /* + * For the '..' entry, generate the correct record, and return + * 1 for the length. + */ + if(strcmp(name,"..") == 0) + { + if(result) + { + *result++ = 1; + *result++ = 0; + } + return 1; + } + + /* + * Now scan the directory one character at a time, and figure out + * what to do. + */ + pnt = name; + + /* + * Find the '.' that we intend to use for the extension. Usually this + * is the last dot, but if we have . followed by nothing or a ~, we + * would consider this to be unsatisfactory, and we keep searching. + */ + last_dot = strrchr (pnt,'.'); + if( (last_dot != NULL) + && ( (last_dot[1] == '~') + || (last_dot[1] == '\0') + || (last_dot[1] == '\0')) ) + { + c = last_dot; + *c = '\0'; + last_dot = strrchr (pnt,'.'); + *c = '.'; + } + + while(*pnt) + { +#ifdef VMS + if( strcmp(pnt,".DIR;1") == 0 ) + { + break; + } +#endif + + /* + * This character indicates a Unix style of backup file + * generated by some editors. Lower the priority of + * the file. + */ + if(*pnt == '#') + { + priority = 1; + pnt++; + continue; + } + + /* + * This character indicates a Unix style of backup file + * generated by some editors. Lower the priority of + * the file. + */ + if(*pnt == '~') + { + priority = 1; + tildes++; + pnt++; + continue; + } + + /* + * This might come up if we had some joker already try and put + * iso9660 version numbers into the file names. This would be + * a silly thing to do on a Unix box, but we check for it + * anyways. If we see this, then we don't have to add our + * own version number at the end. + */ + if(*pnt == ';') + { + seen_semic = 1; + *result++ = *pnt++; + continue; + } + + /* + * If we have a name with multiple '.' characters, we ignore everything + * after we have gotten the extension. + */ + if(ignore) + { + pnt++; + continue; + } + + /* + * Spin past any iso9660 version number we might have. + */ + if(seen_semic) + { + if(*pnt >= '0' && *pnt <= '9') + { + *result++ = *pnt; + } + extra++; + pnt++; + continue; + } + + /* + * If we have full names, the names we generate will not + * work on a DOS machine, since they are not guaranteed + * to be 8.3. Nonetheless, in many cases this is a useful + * option. We still only allow one '.' character in the + * name, however. + */ + if(full_iso9660_filenames) + { + /* Here we allow a more relaxed syntax. */ + if(*pnt == '.') + { + if (seen_dot) + { + ignore++; + continue; + } + seen_dot++; + } + if(current_length < 30) + { + *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt); + } + } + else + { + /* + * Dos style filenames. We really restrict the + * names here. + */ + /* It would be nice to have .tar.gz transform to .tgz, + * .ps.gz to .psz, ... + */ + if(*pnt == '.') + { + if (!chars_before_dot && !allow_leading_dots) + { + /* DOS can't read files with dot first */ + chars_before_dot++; + if (result) + { + *result++ = '_'; /* Substitute underscore */ + } + } + else if( pnt != last_dot ) + { + /* + * If this isn't the dot that we use for the extension, + * then change the character into a '_' instead. + */ + if(chars_before_dot < 8) + { + chars_before_dot++; + if(result) + { + *result++ = '_'; + } + } + } + else + { + if (seen_dot) + { + ignore++; continue; + } + if(result) + { + *result++ = '.'; + } + seen_dot++; + } + } + else + { + if( (seen_dot && (chars_after_dot < 3) && ++chars_after_dot) + || ((chars_before_dot < 8) && ++chars_before_dot) ) + { + if(result) + { + switch (*pnt) + { + default: + *result++ = islower(*pnt) ? toupper(*pnt) : *pnt; + break; + + /* + * Descriptions of DOS's 'Parse Filename' + * (function 29H) describes V1 and V2.0+ + * separator and terminator characters. + * These characters in a DOS name make + * the file visible but un-manipulable + * (all useful operations error off. + */ + /* separators */ + case '+': + case '=': + case ':': + case ';': /* already handled */ + case '.': /* already handled */ + case ',': /* already handled */ + case '\t': + case ' ': + /* V1 only separators */ + case '/': + case '"': + case '[': + case ']': + /* terminators */ + case '>': + case '<': + case '|': + /* Hmm - what to do here? Skip? + * Win95 looks like it substitutes '_' + */ + *result++ = '_'; + break; + } /* switch (*pnt) */ + } /* if (result) */ + } /* if (chars_{after,before}_dot) ... */ + } /* else *pnt == '.' */ + } /* else DOS file names */ + current_length++; + pnt++; + } /* while (*pnt) */ + + /* + * OK, that wraps up the scan of the name. Now tidy up a few other + * things. + */ + + /* + * Look for emacs style of numbered backups, like foo.c.~3~. If + * we see this, convert the version number into the priority + * number. In case of name conflicts, this is what would end + * up being used as the 'extension'. + */ + if(tildes == 2) + { + int prio1 = 0; + pnt = name; + while (*pnt && *pnt != '~') + { + pnt++; + } + if (*pnt) + { + pnt++; + } + while(*pnt && *pnt != '~') + { + prio1 = 10*prio1 + *pnt - '0'; + pnt++; + } + priority = prio1; + } + + /* + * If this is not a directory, force a '.' in case we haven't + * seen one, and add a version number if we haven't seen one + * of those either. + */ + if (!dirflag) + { + if (!seen_dot && !omit_period) + { + if (result) *result++ = '.'; + extra++; + } + if(!omit_version_number && !seen_semic) + { + if(result) + { + *result++ = ';'; + *result++ = '1'; + }; + extra += 2; + } + } + + if(result) + { + *result++ = 0; + } + sresult->priority = priority; + + return (chars_before_dot + chars_after_dot + seen_dot + extra); +} diff --git a/gnu/usr.sbin/mkisofs/rock.c b/gnu/usr.sbin/mkisofs/rock.c new file mode 100644 index 00000000000..592bb79229f --- /dev/null +++ b/gnu/usr.sbin/mkisofs/rock.c @@ -0,0 +1,557 @@ +/* $OpenBSD: rock.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * 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[] ="$From: rock.c,v 1.2 1997/02/23 16:08:07 eric Rel $"; + +#include <stdlib.h> + +#include "config.h" + +#ifndef VMS +#if defined(MAJOR_IN_SYSMACROS) +#include <sys/sysmacros.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#endif +#if defined(MAJOR_IN_MKDEV) +#include <sys/types.h> +#include <sys/mkdev.h> +#endif + +#include "mkisofs.h" +#include "iso9660.h" +#include <string.h> + +#ifdef NON_UNIXFS +#define S_ISLNK(m) (0) +#else +#ifndef S_ISLNK +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#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(){ + 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; + + /* 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 + */ +#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 MAJOR_IN_SYSMACROS == 0 && MAJOR_IN_MKDEV == 0 + 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 + /* + * Check for and symbolic links. VMS does not have these. + */ + if (S_ISLNK(lstatbuf->st_mode)){ + int lenpos, lenval, j0, j1; + int nchar; + unsigned char * cpnt, *cpnt1; + nchar = readlink(whole_name, symlink_buff, sizeof(symlink_buff)); + symlink_buff[nchar < 0 ? 0 : nchar] = 0; + set_733(s_entry->isorec.size, 0); + cpnt = &symlink_buff[0]; + flagval |= (1<<2); + + 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(MAYBE_ADD_CE_ENTRY(6)) { + 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 */ + /* + * 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, "r"); + 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 %d\n", 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, "r"); + if(zipfile) { + OK_flag = 0; + fprintf(stderr,"Unable to insert transparent compressed file - name conflict\n"); + 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 ipnt = 0; + char * pnt; + int len_id, len_des, len_src; + + len_id = strlen(id); + len_des = strlen(descriptor); + len_src = strlen(source); + Rock[ipnt++] ='E'; + Rock[ipnt++] ='R'; + Rock[ipnt++] = ER_SIZE + len_id + len_des + len_src; + Rock[ipnt++] = 1; + Rock[ipnt++] = len_id; + Rock[ipnt++] = len_des; + Rock[ipnt++] = len_src; + Rock[ipnt++] = 1; + + memcpy(Rock + ipnt, id, len_id); + ipnt += len_id; + + memcpy(Rock + ipnt, descriptor, len_des); + ipnt += len_des; + + memcpy(Rock + ipnt, source, len_src); + ipnt += len_src; + + if(ipnt > SECTOR_SIZE) { + fprintf(stderr,"Extension record too long\n"); + exit(1); + }; + pnt = (char *) e_malloc(SECTOR_SIZE); + memset(pnt, 0, SECTOR_SIZE); + memcpy(pnt, Rock, ipnt); + *size = ipnt; + return pnt; +} diff --git a/gnu/usr.sbin/mkisofs/tree.c b/gnu/usr.sbin/mkisofs/tree.c new file mode 100644 index 00000000000..fc0bbd12f1d --- /dev/null +++ b/gnu/usr.sbin/mkisofs/tree.c @@ -0,0 +1,1275 @@ +/* $OpenBSD: tree.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * 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[] ="$From: tree.c,v 1.7 1997/03/25 03:55:28 eric Rel $"; + +/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <errno.h> + +#include "config.h" + +#ifndef VMS +#if defined(MAJOR_IN_SYSMACROS) +#include <sys/sysmacros.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if defined(MAJOR_IN_MKDEV) +#include <sys/types.h> +#include <sys/mkdev.h> +#endif +#else +#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 <sys/stat.h> + +#include "exclude.h" + +#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 + +#ifdef __svr4__ +extern char * strdup(const char *); +#endif + +static unsigned char symlink_buff[256]; + +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; + +void +FDECL1(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; + if (st->st_mode & 0111) + st->st_mode |= 0111; + st->st_mode &= ~07222; +} + +int +FDECL2(stat_filter, char *, path, struct stat *, st) +{ + int result = stat(path, st); + if (result >= 0 && rationalize) + stat_fix(st); + return result; +} + +int +FDECL2(lstat_filter, char *, path, struct stat *, st) +{ + int result = lstat(path, st); + if (result >= 0 && rationalize) + stat_fix(st); + return result; +} + +void FDECL1(sort_n_finish, struct directory *, this_dir) +{ + struct directory_entry * s_entry; + struct directory_entry * s_entry1; + time_t current_time; + struct directory_entry * table; + int count; + int new_reclen; + char * c; + int tablesize = 0; + char newname[34]; + char rootname[34]; + + /* Here we can take the opportunity to toss duplicate entries from the + directory. */ + + table = NULL; + + if(fstatbuf.st_ctime == 0) + { + time (¤t_time); + fstatbuf.st_uid = 0; + fstatbuf.st_gid = 0; + fstatbuf.st_ctime = current_time; + fstatbuf.st_mtime = current_time; + fstatbuf.st_atime = current_time; + } + + flush_file_hash(); + s_entry = this_dir->contents; + while(s_entry) + { + + /* + * 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) + { + fprintf(stderr,"Fatal goof\n"); + exit(1); + } + + /* + * OK, handle the conflicts. Try substitute names until we come + * up with a winner + */ + strcpy(rootname, s_entry->isorec.name); + if(full_iso9660_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, '.'); + if (c) + *c = 0; + else + { + c = strchr(rootname, ';'); + if (c) *c = 0; + } + count = 0; + while(count < 0x1000) + { + sprintf(newname,"%s.%3.3X%s", rootname, count, + (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)) break; + count++; + } + if(count >= 0x1000) + { + fprintf(stderr,"Unable to generate unique name for file %s\n", s_entry->name); + exit(1); + } + + /* + * 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) + { + 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 = sizeof(struct iso_directory_record) - + sizeof(s_entry->isorec.name) + + 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); + 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 = sizeof(struct iso_directory_record) - + sizeof(s_entry1->isorec.name) + + 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->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, DEF_VSN); + set_733((char *) table->isorec.size, tablesize); + table->size = tablesize; + table->filedir = this_dir; + table->name = strdup("<translation table>"); + table->table = (char *) e_malloc(ROUND_UP(tablesize)); + memset(table->table, 0, ROUND_UP(tablesize)); + iso9660_file_length ("TRANS.TBL", table, 1); + + if(use_RockRidge) + { + fstatbuf.st_mode = 0444 | S_IFREG; + fstatbuf.st_nlink = 1; + generate_rock_ridge_attributes("", + "TRANS.TBL", table, + &fstatbuf, &fstatbuf, 0); + } + } + + for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) + { + new_reclen = strlen(s_entry->isorec.name); + + if(s_entry->isorec.flags[0] == 2) + { + if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) + { + path_table_size += new_reclen + sizeof(struct iso_path_table) - 1; + if (new_reclen & 1) path_table_size++; + } + else + { + new_reclen = 1; + if (this_dir == root && strlen(s_entry->name) == 1) + path_table_size += sizeof(struct iso_path_table); + } + } + if(path_table_size & 1) path_table_size++; /* For odd lengths we pad */ + s_entry->isorec.name_len[0] = new_reclen; + + new_reclen += + sizeof(struct iso_directory_record) - + sizeof(s_entry->isorec.name); + + if (new_reclen & 1) + new_reclen++; + + new_reclen += s_entry->rr_attr_size; + + if (new_reclen & 1) new_reclen++; + + if(new_reclen > 0xff) + { + fprintf(stderr,"Fatal error - RR overflow for file %s\n", + s_entry->name); + exit(1); + } + s_entry->isorec.length[0] = new_reclen; + } + + sort_directory(&this_dir->contents); + + if(table) + { + char buffer[1024]; + count = 0; + for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){ + if(s_entry == table) continue; + if(!s_entry->table) continue; + if(strcmp(s_entry->name, ".") == 0 || + strcmp(s_entry->name, "..") == 0) continue; + + sprintf(buffer,"%c %-34s%s",s_entry->table[0], + s_entry->isorec.name, s_entry->table+1); + memcpy(table->table + count, buffer, strlen(buffer)); + count += strlen(buffer); + free(s_entry->table); + s_entry->table = NULL; + } + + if(count != tablesize) + { + fprintf(stderr,"Translation table size mismatch %d %d\n", + count, tablesize); + exit(1); + } + } + + /* + * Now go through the directory and figure out how large this one will be. + * Do not split a directory entry across a sector boundary + */ + s_entry = this_dir->contents; + this_dir->ce_bytes = 0; + while(s_entry) + { + new_reclen = s_entry->isorec.length[0]; + if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) + this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) & + ~(SECTOR_SIZE - 1); + this_dir->size += new_reclen; + + /* See if continuation entries were used on disc */ + if(use_RockRidge && + s_entry->rr_attr_size != s_entry->total_rr_attr_size) + { + unsigned char * pnt; + int len; + int nbytes; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + + /* + * We make sure that each continuation entry record is not + * split across sectors, but each file could in theory have more + * than one CE, so we scan through and figure out what we need. + */ + while(len > 3) + { + if(pnt[0] == 'C' && pnt[1] == 'E') + { + nbytes = get_733((char *) pnt+20); + + if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >= + SECTOR_SIZE) this_dir->ce_bytes = + ROUND_UP(this_dir->ce_bytes); + /* Now store the block in the ce buffer */ + this_dir->ce_bytes += nbytes; + if(this_dir->ce_bytes & 1) this_dir->ce_bytes++; + } + len -= pnt[2]; + pnt += pnt[2]; + } + } + s_entry = s_entry->next; + } +} + +static void generate_reloc_directory() +{ + int new_reclen; + time_t current_time; + struct directory_entry *s_entry; + + /* Create an entry for our internal tree */ + time (¤t_time); + reloc_dir = (struct directory *) + e_malloc(sizeof(struct directory)); + memset(reloc_dir, 0, sizeof(struct directory)); + reloc_dir->parent = root; + reloc_dir->next = root->subdir; + root->subdir = reloc_dir; + reloc_dir->depth = 1; + reloc_dir->whole_name = strdup("./rr_moved"); + reloc_dir->de_name = strdup("rr_moved"); + reloc_dir->extent = 0; + + new_reclen = strlen(reloc_dir->de_name); + + /* Now create an actual directory entry */ + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memset(s_entry, 0, sizeof(struct directory_entry)); + s_entry->next = root->contents; + reloc_dir->self = s_entry; + + root->contents = s_entry; + root->contents->name = strdup(reloc_dir->de_name); + root->contents->filedir = root; + root->contents->isorec.flags[0] = 2; + root->contents->priority = 32768; + iso9660_date(root->contents->isorec.date, current_time); + root->contents->inode = UNCACHED_INODE; + root->contents->dev = (dev_t) UNCACHED_DEVICE; + set_723(root->contents->isorec.volume_sequence_number, DEF_VSN); + iso9660_file_length (reloc_dir->de_name, root->contents, 1); + + if(use_RockRidge){ + fstatbuf.st_mode = 0555 | S_IFDIR; + fstatbuf.st_nlink = 2; + generate_rock_ridge_attributes("", + "rr_moved", s_entry, + &fstatbuf, &fstatbuf, 0); + }; + + /* Now create the . and .. entries in rr_moved */ + /* Now create an actual directory entry */ + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memcpy(s_entry, root->contents, + sizeof(struct directory_entry)); + s_entry->name = strdup("."); + iso9660_file_length (".", s_entry, 1); + + s_entry->filedir = reloc_dir; + reloc_dir->contents = s_entry; + + if(use_RockRidge){ + fstatbuf.st_mode = 0555 | S_IFDIR; + fstatbuf.st_nlink = 2; + generate_rock_ridge_attributes("", + ".", s_entry, + &fstatbuf, &fstatbuf, 0); + }; + + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memcpy(s_entry, root->contents, + sizeof(struct directory_entry)); + s_entry->name = strdup(".."); + iso9660_file_length ("..", s_entry, 1); + s_entry->filedir = root; + reloc_dir->contents->next = s_entry; + reloc_dir->contents->next->next = NULL; + if(use_RockRidge){ + fstatbuf.st_mode = 0555 | S_IFDIR; + fstatbuf.st_nlink = 2; + generate_rock_ridge_attributes("", + "..", s_entry, + &root_statbuf, &root_statbuf, 0); + }; +} + +static void FDECL1(increment_nlink, struct directory_entry *, s_entry){ + unsigned char * pnt; + int len, nlink; + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + while(len){ + if(pnt[0] == 'P' && pnt[1] == 'X') { + nlink = get_733((char *) pnt+12); + set_733((char *) pnt+12, nlink+1); + break; + }; + len -= pnt[2]; + pnt += pnt[2]; + }; +} + +void finish_cl_pl_entries(){ + struct directory_entry *s_entry, *s_entry1; + struct directory * d_entry; + + s_entry = reloc_dir->contents; + s_entry = s_entry->next->next; /* Skip past . and .. */ + for(; s_entry; s_entry = s_entry->next){ + d_entry = reloc_dir->subdir; + while(d_entry){ + if(d_entry->self == s_entry) break; + d_entry = d_entry->next; + }; + if(!d_entry){ + fprintf(stderr,"Unable to locate directory parent\n"); + exit(1); + }; + + /* First fix the PL pointer in the directory in the rr_reloc dir */ + s_entry1 = d_entry->contents->next; + set_733((char *) s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8, + s_entry->filedir->extent); + + /* Now fix the CL pointer */ + s_entry1 = s_entry->parent_rec; + + set_733((char *) s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8, + d_entry->extent); + + s_entry->filedir = reloc_dir; /* Now we can fix this */ + } + /* Next we need to modify the NLINK terms in the assorted root directory records + to account for the presence of the RR_MOVED directory */ + + increment_nlink(root->self); + increment_nlink(root->self->next); + d_entry = root->subdir; + while(d_entry){ + increment_nlink(d_entry->contents->next); + d_entry = d_entry->next; + }; +} + +/* + * This function scans the directory tree, looking for files, and it makes + * note of everything that is found. We also begin to construct the ISO9660 + * directory entries, so that we can determine how large each directory is. + */ + +int +FDECL3(scan_directory_tree,char *, path, struct directory_entry *, de, + struct iso_directory_record *, mrootp){ + DIR * current_dir; + char whole_path[1024]; + struct dirent * d_entry; + struct directory_entry * s_entry, *s_entry1; + struct directory * this_dir, *next_brother, *parent; + struct stat statbuf, lstatbuf; + int status, dflag; + int lstatus; + int n_orig; + struct directory_entry **orig_contents = NULL; + struct directory_entry * odpnt = NULL; + char * cpnt; + int new_reclen; + int deep_flag; + char * old_path; + + current_dir = opendir(path); + d_entry = NULL; + + /* Apparently NFS sometimes allows you to open the directory, but + then refuses to allow you to read the contents. Allow for this */ + + old_path = path; + + if(current_dir) d_entry = readdir_add_files(&path, old_path, current_dir); + + if(!current_dir || !d_entry) { + fprintf(stderr,"Unable to open directory %s\n", path); + de->isorec.flags[0] &= ~2; /* Mark as not a directory */ + if(current_dir) closedir(current_dir); + return 0; + }; + + parent = de->filedir; + /* Set up the struct for the current directory, and insert it into the + tree */ + +#ifdef VMS + vms_path_fixup(path); +#endif + + this_dir = (struct directory *) e_malloc(sizeof(struct directory)); + this_dir->next = NULL; + new_reclen = 0; + this_dir->subdir = NULL; + this_dir->self = de; + this_dir->contents = NULL; + this_dir->whole_name = strdup(path); + cpnt = strrchr(path, PATH_SEPARATOR); + if(cpnt) + cpnt++; + else + cpnt = path; + this_dir->de_name = strdup(cpnt); + this_dir->size = 0; + this_dir->extent = 0; + + if(!parent || parent == root){ + if (!root) { + root = this_dir; /* First time through for root directory only */ + root->depth = 0; + root->parent = root; + } else { + this_dir->depth = 1; + if(!root->subdir) + root->subdir = this_dir; + else { + next_brother = root->subdir; + while(next_brother->next) next_brother = next_brother->next; + next_brother->next = this_dir; + }; + this_dir->parent = parent; + }; + } else { + /* Come through here for normal traversal of tree */ +#ifdef DEBUG + fprintf(stderr,"%s(%d) ", path, this_dir->depth); +#endif + if(parent->depth > RR_relocation_depth) { + fprintf(stderr,"Directories too deep %s\n", path); + exit(1); + }; + + this_dir->parent = parent; + this_dir->depth = parent->depth + 1; + + if(!parent->subdir) + parent->subdir = this_dir; + else { + next_brother = parent->subdir; + while(next_brother->next) next_brother = next_brother->next; + next_brother->next = this_dir; + } + } + + /* + * Parse the same directory in the image that we are merging + * for multisession stuff. + */ + if( mrootp != NULL ) + { + orig_contents = read_merging_directory(mrootp, &n_orig); + } + +/* Now we scan the directory itself, and look at what is inside of it. */ + + dflag = 0; + while(1==1){ + + /* The first time through, skip this, since we already asked for + the first entry when we opened the directory. */ + if(dflag) d_entry = readdir_add_files(&path, old_path, current_dir); + dflag++; + + if(!d_entry) break; + + /* OK, got a valid entry */ + + /* If we do not want all files, then pitch the backups. */ + if(!all_files){ + if(strchr(d_entry->d_name,'~')) continue; + if(strchr(d_entry->d_name,'#')) continue; + }; + + if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)){ + fprintf(stderr, "Overflow of stat buffer\n"); + exit(1); + }; + + /* Generate the complete ASCII path for this file */ + strcpy(whole_path, path); +#ifndef VMS + if(whole_path[strlen(whole_path)-1] != '/') + strcat(whole_path, "/"); +#endif + strcat(whole_path, d_entry->d_name); + + /* Should we exclude this file? */ + if (is_excluded(whole_path)) { + if (verbose) { + fprintf(stderr, "Excluded: %s\n",whole_path); + } + continue; + } + /** Should we exclude this file ? */ + if (matches(d_entry->d_name)) { + if (verbose) { + fprintf(stderr, "Excluded by match: %s\n", whole_path); + } + continue; + } + + if( generate_tables + && strcmp(d_entry->d_name, "TRANS.TBL") == 0 ) + { + /* + * Ignore this entry. We are going to be generating new + * versions of these files, and we need to ignore any + * originals that we might have found. + */ + if (verbose) + { + fprintf(stderr, "Excluded: %s\n",whole_path); + } + continue; + } + +#if 0 + if (verbose) fprintf(stderr, "%s\n",whole_path); +#endif + status = stat_filter(whole_path, &statbuf); + + lstatus = lstat_filter(whole_path, &lstatbuf); + + if( (status == -1) && (lstatus == -1) ) + { + /* + * This means that the file doesn't exist, or isn't accessible. + * Sometimes this is because of NFS permissions problems + * or it could mean that the user has attempted to 'add' something + * with the -i option and the directory being added doesn't exist. + */ + fprintf(stderr, "Non-existant or inaccessible: %s\n",whole_path); + continue; + } + + if(this_dir == root && strcmp(d_entry->d_name, ".") == 0) + root_statbuf = statbuf; /* Save this for later on */ + + /* We do this to make sure that the root entries are consistent */ + if(this_dir == root && strcmp(d_entry->d_name, "..") == 0) { + statbuf = root_statbuf; + lstatbuf = root_statbuf; + }; + + if(S_ISLNK(lstatbuf.st_mode)){ + + /* Here we decide how to handle the symbolic links. Here + we handle the general case - if we are not following + links or there is an error, then we must change + something. If RR is in use, it is easy, we let RR + describe the file. If not, then we punt the file. */ + + if((status || !follow_links)){ + if(use_RockRidge){ + status = 0; + statbuf.st_size = 0; + STAT_INODE(statbuf) = UNCACHED_INODE; + statbuf.st_dev = (dev_t) UNCACHED_DEVICE; + statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; + } else { + if(follow_links) fprintf(stderr, + "Unable to stat file %s - ignoring and continuing.\n", + whole_path); + else fprintf(stderr, + "Symlink %s ignored - continuing.\n", + whole_path); + continue; /* Non Rock Ridge discs - ignore all symlinks */ + }; + } + + /* Here we handle a different kind of case. Here we have + a symlink, but we want to follow symlinks. If we run + across a directory loop, then we need to pretend that + we are not following symlinks for this file. If this + is the first time we have seen this, then make this + seem as if there was no symlink there in the first + place */ + + if( follow_links + && S_ISDIR(statbuf.st_mode) ) + { + if( strcmp(d_entry->d_name, ".") + && strcmp(d_entry->d_name, "..") ) + { + if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) + { + if(!use_RockRidge) + { + fprintf(stderr, "Already cached directory seen (%s)\n", + whole_path); + continue; + } + statbuf.st_size = 0; + STAT_INODE(statbuf) = UNCACHED_INODE; + statbuf.st_dev = (dev_t) UNCACHED_DEVICE; + statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; + } else { + lstatbuf = statbuf; + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + } + } + } + + /* + * For non-directories, we just copy the stat information over + * so we correctly include this file. + */ + if( follow_links + && !S_ISDIR(statbuf.st_mode) ) + { + lstatbuf = statbuf; + } + } + + /* + * Add directories to the cache so that we don't waste space even + * if we are supposed to be following symlinks. + */ + if( follow_links + && strcmp(d_entry->d_name, ".") + && strcmp(d_entry->d_name, "..") + && S_ISDIR(statbuf.st_mode) ) + { + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + } +#ifdef VMS + if(!S_ISDIR(lstatbuf.st_mode) && (statbuf.st_fab_rfm != FAB$C_FIX && + statbuf.st_fab_rfm != FAB$C_STMLF)) { + fprintf(stderr,"Warning - file %s has an unsupported VMS record" + " format (%d)\n", + whole_path, statbuf.st_fab_rfm); + } +#endif + + if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))){ + fprintf(stderr, "File %s is not readable (errno = %d) - ignoring\n", + whole_path, errno); + continue; + } + + /* Add this so that we can detect directory loops with hard links. + If we are set up to follow symlinks, then we skip this checking. */ + if( !follow_links + && S_ISDIR(lstatbuf.st_mode) + && strcmp(d_entry->d_name, ".") + && strcmp(d_entry->d_name, "..") ) + { + if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) { + fprintf(stderr,"Directory loop - fatal goof (%s %lx %lu).\n", + whole_path, (unsigned long) statbuf.st_dev, + (unsigned long) STAT_INODE(statbuf)); + exit(1); + }; + add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); + }; + + if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) && + !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) + && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) && + !S_ISDIR(lstatbuf.st_mode)) { + fprintf(stderr,"Unknown file type %s - ignoring and continuing.\n", + whole_path); + continue; + }; + + /* Who knows what trash this is - ignore and continue */ + + if(status) { + fprintf(stderr, + "Unable to stat file %s - ignoring and continuing.\n", + whole_path); + continue; + }; + + s_entry = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + s_entry->next = this_dir->contents; + memset(s_entry->isorec.extent, 0, 8); + this_dir->contents = s_entry; + deep_flag = 0; + s_entry->table = NULL; + + s_entry->name = strdup(d_entry->d_name); + s_entry->whole_name = strdup (whole_path); + + s_entry->de_flags = 0; + s_entry->filedir = this_dir; + s_entry->isorec.flags[0] = 0; + s_entry->isorec.ext_attr_length[0] = 0; + iso9660_date(s_entry->isorec.date, statbuf.st_mtime); + s_entry->isorec.file_unit_size[0] = 0; + s_entry->isorec.interleave[0] = 0; + if(parent && parent == reloc_dir && strcmp(d_entry->d_name, "..") == 0){ + s_entry->inode = UNCACHED_INODE; + s_entry->dev = (dev_t) UNCACHED_DEVICE; + deep_flag = NEED_PL; + } else { + s_entry->inode = STAT_INODE(statbuf); + s_entry->dev = statbuf.st_dev; + }; + set_723(s_entry->isorec.volume_sequence_number, DEF_VSN); + iso9660_file_length(d_entry->d_name, s_entry, S_ISDIR(statbuf.st_mode)); + s_entry->rr_attr_size = 0; + s_entry->total_rr_attr_size = 0; + s_entry->rr_attributes = NULL; + + /* Directories are assigned sizes later on */ + if (!S_ISDIR(statbuf.st_mode)) { + set_733((char *) s_entry->isorec.size, statbuf.st_size); + + if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) || + S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode) + || S_ISLNK(lstatbuf.st_mode)) + s_entry->size = 0; + else + s_entry->size = statbuf.st_size; + } else + s_entry->isorec.flags[0] = 2; + + /* + * We always should create an entirely new directory tree whenever + * we generate a new session, unless there were *no* changes whatsoever + * to any of the directories, in which case it would be kind of pointless + * to generate a new session. + * + * I believe it is possible to rigorously prove that any change anywhere + * in the filesystem will force the entire tree to be regenerated + * because the modified directory will get a new extent number. Since + * each subdirectory of the changed directory has a '..' entry, all of + * them will need to be rewritten too, and since the parent directory + * of the modified directory will have an extent pointer to the directory + * it too will need to be rewritten. Thus we will never be able to reuse + * any directory information when writing new sessions. + * + * We still check the previous session so we can mark off the equivalent + * entry in the list we got from the original disc, however. + */ + if(S_ISDIR(statbuf.st_mode) && orig_contents != NULL){ + check_prev_session(orig_contents, n_orig, s_entry, + &statbuf, &lstatbuf, &odpnt); + } + + if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..") && + S_ISDIR(statbuf.st_mode) && this_dir->depth > RR_relocation_depth){ + if(!reloc_dir) generate_reloc_directory(); + + s_entry1 = (struct directory_entry *) + e_malloc(sizeof (struct directory_entry)); + memcpy(s_entry1, this_dir->contents, + sizeof(struct directory_entry)); + s_entry1->table = NULL; + s_entry1->name = strdup(this_dir->contents->name); + s_entry1->next = reloc_dir->contents; + reloc_dir->contents = s_entry1; + s_entry1->priority = 32768; + s_entry1->parent_rec = this_dir->contents; + + deep_flag = NEED_RE; + + if(use_RockRidge) { + generate_rock_ridge_attributes(whole_path, + d_entry->d_name, s_entry1, + &statbuf, &lstatbuf, deep_flag); + } + + deep_flag = 0; + + /* We need to set this temporarily so that the parent to this is correctly + determined. */ + s_entry1->filedir = reloc_dir; + if( odpnt != NULL ) + { + scan_directory_tree(whole_path, s_entry1, &odpnt->isorec); + } + else + { + scan_directory_tree(whole_path, s_entry1, NULL); + } + if( odpnt != NULL ) + { + free(odpnt); + odpnt = NULL; + } + s_entry1->filedir = this_dir; + + statbuf.st_size = 0; + statbuf.st_mode &= 0777; + set_733((char *) s_entry->isorec.size, 0); + s_entry->size = 0; + s_entry->isorec.flags[0] = 0; + s_entry->inode = UNCACHED_INODE; + deep_flag = NEED_CL; + }; + + if(generate_tables && strcmp(s_entry->name, ".") && strcmp(s_entry->name, "..")) { + char buffer[2048]; + int nchar; + switch(lstatbuf.st_mode & S_IFMT){ + case S_IFDIR: + sprintf(buffer,"D\t%s\n", + s_entry->name); + break; +#ifndef NON_UNIXFS + case S_IFBLK: + sprintf(buffer,"B\t%s\t%lu %lu\n", + s_entry->name, + (unsigned long) major(statbuf.st_rdev), + (unsigned long) minor(statbuf.st_rdev)); + break; + case S_IFIFO: + sprintf(buffer,"P\t%s\n", + s_entry->name); + break; + case S_IFCHR: + sprintf(buffer,"C\t%s\t%lu %lu\n", + s_entry->name, + (unsigned long) major(statbuf.st_rdev), + (unsigned long) minor(statbuf.st_rdev)); + break; + case S_IFLNK: + nchar = readlink(whole_path, + symlink_buff, + sizeof(symlink_buff)); + symlink_buff[nchar < 0 ? 0 : nchar] = 0; + sprintf(buffer,"L\t%s\t%s\n", + s_entry->name, symlink_buff); + break; +#ifdef S_IFSOCK + case S_IFSOCK: + sprintf(buffer,"S\t%s\n", + s_entry->name); + break; +#endif +#endif /* NON_UNIXFS */ + case S_IFREG: + default: + sprintf(buffer,"F\t%s\n", + s_entry->name); + break; + }; + s_entry->table = strdup(buffer); + }; + + /* + * See if we have an entry for this guy in the previous session. + */ + if( orig_contents != NULL && !S_ISDIR(statbuf.st_mode)) + { + check_prev_session(orig_contents, n_orig, s_entry, + &statbuf, &lstatbuf, NULL); + } + + if(S_ISDIR(statbuf.st_mode)){ + int dflag; + if (strcmp(d_entry->d_name,".") && strcmp(d_entry->d_name,"..")) { + if( odpnt != NULL ) + { + dflag = scan_directory_tree(whole_path, s_entry, + &odpnt->isorec); + } + else + { + dflag = scan_directory_tree(whole_path, s_entry, NULL); + } + /* If unable to scan directory, mark this as a non-directory */ + if(!dflag) + lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; + if( odpnt != NULL ) + { + free(odpnt); + odpnt = NULL; + } + } + } + + if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".") == 0) + deep_flag |= NEED_CE | NEED_SP; /* For extension record */ + + /* Now figure out how much room this file will take in the directory */ + + if(use_RockRidge) { + generate_rock_ridge_attributes(whole_path, + d_entry->d_name, s_entry, + &statbuf, &lstatbuf, deep_flag); + + } + } + closedir(current_dir); + + if( orig_contents != NULL ) + { + merge_remaining_entries(this_dir, orig_contents, n_orig); + free_mdinfo(orig_contents, n_orig); + } + + sort_n_finish(this_dir); + + return 1; +} + + +void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){ + struct directory * dpnt; + + dpnt = node; + + while (dpnt){ + if( dpnt->extent > session_start ) + { + generate_one_directory(dpnt, outfile); + } + if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile); + dpnt = dpnt->next; + } +} + +void FDECL1(dump_tree, struct directory *, node){ + struct directory * dpnt; + + dpnt = node; + + while (dpnt){ + fprintf(stderr,"%4d %5d %s\n",dpnt->extent, dpnt->size, dpnt->de_name); + if(dpnt->subdir) dump_tree(dpnt->subdir); + dpnt = dpnt->next; + } +} + +/* + * something quick and dirty to locate a file given a path + * recursively walks down path in filename until it finds the + * directory entry for the desired file + */ +struct directory_entry * FDECL2(search_tree_file, struct directory *, + node,char *, filename) +{ + struct directory_entry * depnt; + struct directory * dpnt; + char * p1; + char * rest; + char * subdir; + + /* + * strip off next directory name from filename + */ + subdir = strdup(filename); + + if( (p1=strchr(subdir, '/')) == subdir ) + { + fprintf(stderr,"call to search_tree_file with an absolute path, stripping\n"); + fprintf(stderr,"initial path separator. Hope this was intended...\n"); + memmove(subdir, subdir+1, strlen(subdir)-1); + p1 = strchr(subdir, '/'); + } + + /* + * do we need to find a subdirectory + */ + if (p1) + { + *p1 = '\0'; + +#ifdef DEBUG_TORITO + printf("Looking for subdir called %s\n",p1); +#endif + + rest = p1+1; + +#ifdef DEBUG_TORITO + printf("Remainder of path name is now %s\n", rest); +#endif + + dpnt = node->subdir; + while( dpnt ) + { +#ifdef DEBUG_TORITO + fprintf(stderr,"%4d %5d %s\n", dpnt->extent, dpnt->size, + dpnt->de_name); +#endif + if (!strcmp(subdir, dpnt->de_name)) + { +#ifdef DEBUG_TORITO + printf("Calling next level with filename = %s", rest); +#endif + return(search_tree_file( dpnt, rest )); + } + dpnt = dpnt->next; + } + + /* if we got here means we couldnt find the subdir */ + return (NULL); + } + else + { + /* + * look for a normal file now + */ + depnt = node->contents; + while (depnt) + { +#ifdef DEBUG_TORITO + fprintf(stderr,"%4d %5d %s\n",depnt->isorec.extent, + depnt->size, depnt->name); +#endif + if (!strcmp(filename, depnt->name)) + { +#ifdef DEBUG_TORITO + printf("Found our file %s", filename); +#endif + return(depnt); + } + depnt = depnt->next; + } + /* + * if we got here means we couldnt find the subdir + */ + return (NULL); + } + fprintf(stderr,"We cant get here in search_tree_file :-/ \n"); +} + diff --git a/gnu/usr.sbin/mkisofs/write.c b/gnu/usr.sbin/mkisofs/write.c new file mode 100644 index 00000000000..a81dab5e0ec --- /dev/null +++ b/gnu/usr.sbin/mkisofs/write.c @@ -0,0 +1,1140 @@ +/* $OpenBSD: write.c,v 1.1 1997/09/15 06:01:53 downsj Exp $ */ +/* + * 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[] ="$From: write.c,v 1.4 1997/04/10 03:33:25 eric Rel $"; + +#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 __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 next_path_index = 1; + +/* Used to fill in some of the information in the volume descriptor. */ +static struct tm *local; + +/* 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) +{ + 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; + +static struct directory_entry * sort_dir; +static struct eltorito_boot_descriptor boot_desc; + +unsigned int last_extent_written =0; +static struct iso_primary_descriptor vol_desc; +static 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 */ + +void FDECL1(assign_directory_addresses, struct directory *, node) +{ + int dir_size; + struct directory * dpnt; + + dpnt = node; + + while (dpnt) + { + /* + * 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; + } +} + +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 0 +static 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"); +} +#endif + +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; + + /* + * 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. + */ + if( strcmp(rpnt, ".") == 0 ) return -1; + if( strcmp(lpnt, ".") == 0 ) return 1; + + if( strcmp(rpnt, "..") == 0 ) return -1; + if( strcmp(lpnt, "..") == 0 ) return 1; + + 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(*rpnt < *lpnt) return -1; + if(*rpnt > *lpnt) return 1; + rpnt++; lpnt++; + } + if(*rpnt) return 1; + if(*lpnt) return -1; + return 0; +} + +void FDECL1(sort_directory, struct directory_entry **, sort_dir) +{ + int dcount = 0; + int i, len; + struct directory_entry * s_entry; + struct directory_entry ** sortlist; + + s_entry = *sort_dir; + while(s_entry) + { + dcount++; + s_entry = s_entry->next; + } + + /* + * OK, now we know how many there are. Build a vector for sorting. + */ + sortlist = (struct directory_entry **) + e_malloc(sizeof(struct directory_entry *) * dcount); + + dcount = 0; + s_entry = *sort_dir; + while(s_entry) + { + sortlist[dcount] = s_entry; + len = s_entry->isorec.name_len[0]; + s_entry->isorec.name[len] = 0; + dcount++; + s_entry = s_entry->next; + } + + qsort(sortlist, dcount, sizeof(struct directory_entry *), + (int (*)(const void *, const void *))compare_dirs); + + /* + * Now reassemble the linked list in the proper sorted order + */ + for(i=0; i<dcount-1; i++) + { + sortlist[i]->next = sortlist[i+1]; + } + + sortlist[dcount-1]->next = NULL; + *sort_dir = sortlist[0]; + + free(sortlist); + +} + +void generate_root_record() +{ + time_t ctime; + + time (&ctime); + local = localtime(&ctime); + + root_record.length[0] = 1 + sizeof(struct iso_directory_record) + - sizeof(root_record.name); + root_record.ext_attr_length[0] = 0; + set_733((char *) root_record.extent, root->extent); + set_733((char *) root_record.size, ROUND_UP(root->size)); + iso9660_date(root_record.date, ctime); + root_record.flags[0] = 2; + root_record.file_unit_size[0] = 0; + root_record.interleave[0] = 0; + set_723(root_record.volume_sequence_number, DEF_VSN); + root_record.name_len[0] = 1; +} + +static void FDECL1(assign_file_addresses, struct directory *, dpnt) +{ + struct directory * finddir; + struct directory_entry * s_entry; + struct file_hash *s_hash; + struct deferred_write * dwpnt; + char whole_path[1024]; + + while (dpnt) + { + s_entry = dpnt->contents; + for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) + { + + /* + * If we already have an extent for this entry, + * then don't assign a new one. It must have come + * from a previous session on the disc. Note that + * we don't end up scheduling the thing for writing + * either. + */ + if( isonum_733(s_entry->isorec.extent) != 0 ) + { + continue; + } + + /* + * This saves some space if there are symlinks present + */ + s_hash = find_hash(s_entry->dev, s_entry->inode); + if(s_hash) + { + if(verbose) + { + fprintf(stderr, "Cache hit for %s%s%s\n",s_entry->filedir->de_name, + SPATH_SEPARATOR, s_entry->name); + } + set_733((char *) s_entry->isorec.extent, s_hash->starting_block); + set_733((char *) s_entry->isorec.size, s_hash->size); + continue; + } + + /* + * If this is for a directory that is not a . or a .. entry, + * then look up the information for the entry. We have already + * assigned extents for directories, so we just need to + * fill in the blanks here. + */ + if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && + s_entry->isorec.flags[0] == 2) + { + finddir = dpnt->subdir; + while(1==1) + { + if(finddir->self == s_entry) break; + finddir = finddir->next; + if(!finddir) + { + fprintf(stderr,"Fatal goof\n"); exit(1); + } + } + set_733((char *) s_entry->isorec.extent, finddir->extent); + s_entry->starting_block = finddir->extent; + s_entry->size = ROUND_UP(finddir->size); + total_dir_size += s_entry->size; + add_hash(s_entry); + set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size)); + continue; + } + + + /* + * If this is . or .., then look up the relevant info from the + * tables. + */ + if(strcmp(s_entry->name,".") == 0) + { + set_733((char *) s_entry->isorec.extent, dpnt->extent); + + /* + * Set these so that the hash table has the + * correct information + */ + s_entry->starting_block = dpnt->extent; + s_entry->size = ROUND_UP(dpnt->size); + + add_hash(s_entry); + s_entry->starting_block = dpnt->extent; + set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size)); + continue; + } + + if(strcmp(s_entry->name,"..") == 0) + { + if(dpnt == root) + { + total_dir_size += root->size; + } + set_733((char *) s_entry->isorec.extent, dpnt->parent->extent); + + /* + * Set these so that the hash table has the + * correct information + */ + s_entry->starting_block = dpnt->parent->extent; + s_entry->size = ROUND_UP(dpnt->parent->size); + + add_hash(s_entry); + s_entry->starting_block = dpnt->parent->extent; + set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size)); + continue; + } + + /* + * Some ordinary non-directory file. Just schedule the + * file to be written. This is all quite + * straightforward, just make a list and assign extents + * as we go. Once we get through writing all of the + * directories, we should be ready write out these + * files + */ + if(s_entry->size) + { + dwpnt = (struct deferred_write *) + e_malloc(sizeof(struct deferred_write)); + if(dw_tail) + { + dw_tail->next = dwpnt; + dw_tail = dwpnt; + } + else + { + dw_head = dwpnt; + dw_tail = dwpnt; + } + if(s_entry->inode == TABLE_INODE) + { + dwpnt->table = s_entry->table; + dwpnt->name = NULL; + sprintf(whole_path,"%s%sTRANS.TBL", + s_entry->filedir->whole_name, SPATH_SEPARATOR); + } + else + { + dwpnt->table = NULL; + strcpy(whole_path, s_entry->whole_name); + dwpnt->name = strdup(whole_path); + } + dwpnt->next = NULL; + dwpnt->size = s_entry->size; + dwpnt->extent = last_extent; + set_733((char *) s_entry->isorec.extent, last_extent); + s_entry->starting_block = last_extent; + add_hash(s_entry); + last_extent += ROUND_UP(s_entry->size) >> 11; + if(verbose) + { + fprintf(stderr,"%d %d %s\n", s_entry->starting_block, + last_extent-1, whole_path); + } +#ifdef DBG_ISO + if((ROUND_UP(s_entry->size) >> 11) > 500) + { + fprintf(stderr,"Warning: large file %s\n", whole_path); + fprintf(stderr,"Starting block is %d\n", s_entry->starting_block); + fprintf(stderr,"Reported file size is %d extents\n", s_entry->size); + + } +#endif + if(last_extent > (800000000 >> 11)) + { + /* + * More than 800Mb? Punt + */ + fprintf(stderr,"Extent overflow processing file %s\n", whole_path); + fprintf(stderr,"Starting block is %d\n", s_entry->starting_block); + fprintf(stderr,"Reported file size is %d extents\n", s_entry->size); + exit(1); + } + continue; + } + + /* + * This is for zero-length files. If we leave the extent 0, + * then we get screwed, because many readers simply drop files + * that have an extent of zero. Thus we leave the size 0, + * and just assign the extent number. + */ + set_733((char *) s_entry->isorec.extent, last_extent); + } + if(dpnt->subdir) + { + assign_file_addresses(dpnt->subdir); + } + dpnt = dpnt->next; + } +} /* assign_file_addresses(... */ + +void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile) +{ + unsigned int ce_address = 0; + char * ce_buffer; + unsigned int ce_index = 0; + unsigned int ce_size; + unsigned int dir_index; + char * directory_buffer; + int new_reclen; + struct directory_entry * s_entry; + struct directory_entry * s_entry_d; + unsigned int total_size; + + total_size = (dpnt->size + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); + directory_buffer = (char *) e_malloc(total_size); + memset(directory_buffer, 0, total_size); + dir_index = 0; + + ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); + ce_buffer = NULL; + + if(ce_size) + { + ce_buffer = (char *) e_malloc(ce_size); + memset(ce_buffer, 0, ce_size); + + ce_index = 0; + + /* + * Absolute byte address of CE entries for this directory + */ + ce_address = last_extent_written + (total_size >> 11); + ce_address = ce_address << 11; + } + + s_entry = dpnt->contents; + while(s_entry) + { + + /* + * We do not allow directory entries to cross sector boundaries. + * Simply pad, and then start the next entry at the next sector + */ + new_reclen = s_entry->isorec.length[0]; + if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE ) + { + dir_index = (dir_index + (SECTOR_SIZE - 1)) & + ~(SECTOR_SIZE - 1); + } + + memcpy(directory_buffer + dir_index, &s_entry->isorec, + sizeof(struct iso_directory_record) - + sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]); + dir_index += sizeof(struct iso_directory_record) - + sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0]; + + /* + * Add the Rock Ridge attributes, if present + */ + if(s_entry->rr_attr_size) + { + if(dir_index & 1) + { + directory_buffer[dir_index++] = 0; + } + + /* + * If the RR attributes were too long, then write the + * CE records, as required. + */ + if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) + { + unsigned char * pnt; + int len, nbytes; + + /* + * Go through the entire record and fix up the CE entries + * so that the extent and offset are correct + */ + + pnt = s_entry->rr_attributes; + len = s_entry->total_rr_attr_size; + while(len > 3) + { +#ifdef DEBUG + if (!ce_size) + { + fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n", + ce_index, ce_address); + } +#endif + + if(pnt[0] == 'C' && pnt[1] == 'E') + { + nbytes = get_733( (char *) pnt+20); + + if((ce_index & (SECTOR_SIZE - 1)) + nbytes >= + SECTOR_SIZE) + { + ce_index = ROUND_UP(ce_index); + } + + set_733( (char *) pnt+4, + (ce_address + ce_index) >> 11); + set_733( (char *) pnt+12, + (ce_address + ce_index) & (SECTOR_SIZE - 1)); + + + /* + * Now store the block in the ce buffer + */ + memcpy(ce_buffer + ce_index, + pnt + pnt[2], nbytes); + ce_index += nbytes; + if(ce_index & 1) + { + ce_index++; + } + } + len -= pnt[2]; + pnt += pnt[2]; + } + + } + + rockridge_size += s_entry->total_rr_attr_size; + memcpy(directory_buffer + dir_index, s_entry->rr_attributes, + s_entry->rr_attr_size); + dir_index += s_entry->rr_attr_size; + } + if(dir_index & 1) + { + directory_buffer[dir_index++] = 0; + } + + s_entry_d = s_entry; + s_entry = s_entry->next; + + if (s_entry_d->rr_attributes) free(s_entry_d->rr_attributes); + free (s_entry_d->name); + free (s_entry_d); + } + sort_dir = NULL; + + if(dpnt->size != dir_index) + { + fprintf(stderr,"Unexpected directory length %d %d %s\n",dpnt->size, + dir_index, dpnt->de_name); + } + + xfwrite(directory_buffer, 1, total_size, outfile); + last_extent_written += total_size >> 11; + free(directory_buffer); + + if(ce_size) + { + if(ce_index != dpnt->ce_bytes) + { + fprintf(stderr,"Continuation entry record length mismatch (%d %d).\n", + ce_index, dpnt->ce_bytes); + } + xfwrite(ce_buffer, 1, ce_size, outfile); + last_extent_written += ce_size >> 11; + free(ce_buffer); + } + +} /* generate_one_directory(... */ + +static +void FDECL1(build_pathlist, struct directory *, node) +{ + struct directory * dpnt; + + dpnt = node; + + while (dpnt) + { + pathlist[dpnt->path_index] = dpnt; + if(dpnt->subdir) build_pathlist(dpnt->subdir); + dpnt = dpnt->next; + } +} /* build_pathlist(... */ + +int FDECL2(compare_paths, void const *, r, void const *, l) +{ + struct directory const *ll = *(struct directory * const *)l; + struct directory const *rr = *(struct directory * const *)r; + + if (rr->parent->path_index < ll->parent->path_index) + { + return -1; + } + + if (rr->parent->path_index > ll->parent->path_index) + { + return 1; + } + + return strcmp(rr->self->isorec.name, ll->self->isorec.name); + +} /* compare_paths(... */ + +void generate_path_tables() +{ + struct directory_entry * de; + struct directory * dpnt; + int fix; + int i; + int j; + int namelen; + char * npnt; + char * npnt1; + int tablesize; + + /* + * First allocate memory for the tables and initialize the memory + */ + tablesize = path_blocks << 11; + path_table_m = (char *) e_malloc(tablesize); + path_table_l = (char *) e_malloc(tablesize); + memset(path_table_l, 0, tablesize); + memset(path_table_m, 0, tablesize); + + /* + * Now start filling in the path tables. Start with root directory + */ + path_table_index = 0; + pathlist = (struct directory **) e_malloc(sizeof(struct directory *) + * next_path_index); + memset(pathlist, 0, sizeof(struct directory *) * next_path_index); + build_pathlist(root); + + do + { + fix = 0; + qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), + (int (*)(const void *, const void *))compare_paths); + + for(j=1; j<next_path_index; j++) + { + if(pathlist[j]->path_index != j) + { + pathlist[j]->path_index = j; + fix++; + } + } + } while(fix); + + for(j=1; j<next_path_index; j++) + { + dpnt = pathlist[j]; + if(!dpnt) + { + fprintf(stderr,"Entry %d not in path tables\n", j); + exit(1); + } + npnt = dpnt->de_name; + + /* + * So the root comes out OK + */ + if( (*npnt == 0) || (dpnt == root) ) + { + npnt = "."; + } + npnt1 = strrchr(npnt, PATH_SEPARATOR); + if(npnt1) + { + npnt = npnt1 + 1; + } + + de = dpnt->self; + if(!de) + { + fprintf(stderr,"Fatal goof\n"); + exit(1); + } + + + namelen = de->isorec.name_len[0]; + + path_table_l[path_table_index] = namelen; + path_table_m[path_table_index] = namelen; + path_table_index += 2; + + set_731(path_table_l + path_table_index, dpnt->extent); + set_732(path_table_m + path_table_index, dpnt->extent); + path_table_index += 4; + + set_721(path_table_l + path_table_index, + dpnt->parent->path_index); + set_722(path_table_m + path_table_index, + dpnt->parent->path_index); + path_table_index += 2; + + for(i =0; i<namelen; i++) + { + path_table_l[path_table_index] = de->isorec.name[i]; + path_table_m[path_table_index] = de->isorec.name[i]; + path_table_index++; + } + if(path_table_index & 1) + { + path_table_index++; /* For odd lengths we pad */ + } + } + + free(pathlist); + if(path_table_index != path_table_size) + { + fprintf(stderr,"Path table lengths do not match %d %d\n", + path_table_index, + path_table_size); + } +} /* generate_path_tables(... */ + +void +FDECL3(memcpy_max, char *, to, char *, from, int, max) +{ + int n = strlen(from); + if (n > max) + { + n = max; + } + memcpy(to, from, n); + +} /* memcpy_max(... */ + +int FDECL1(iso_write, FILE *, outfile) +{ + char buffer[2048]; + int i; + char iso_time[17]; + int should_write; + + time(&begun); + assign_file_addresses(root); + + memset(buffer, 0, sizeof(buffer)); + + /* + * This will break in the year 2000, I supose, but there is no good way + * to get the top two digits of the year. + */ + sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local->tm_year, + local->tm_mon+1, local->tm_mday, + local->tm_hour, local->tm_min, local->tm_sec); + + /* + * First, we output 16 sectors of all zero + */ + + for(i=0; i<16; i++) + { + xfwrite(buffer, 1, sizeof(buffer), outfile); + } + + last_extent_written += 16; + + /* + * Next we write out the primary descriptor for the disc + */ + memset(&vol_desc, 0, sizeof(vol_desc)); + vol_desc.type[0] = ISO_VD_PRIMARY; + memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); + vol_desc.version[0] = 1; + + memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id)); + memcpy_max(vol_desc.system_id, system_id, strlen(system_id)); + + memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id)); + memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id)); + + should_write = last_extent - session_start; + set_733((char *) vol_desc.volume_space_size, should_write); + set_723(vol_desc.volume_set_size, 1); + set_723(vol_desc.volume_sequence_number, DEF_VSN); + set_723(vol_desc.logical_block_size, 2048); + + /* + * The path tables are used by DOS based machines to cache directory + * locations + */ + + set_733((char *) vol_desc.path_table_size, path_table_size); + set_731(vol_desc.type_l_path_table, path_table[0]); + set_731(vol_desc.opt_type_l_path_table, path_table[1]); + set_732(vol_desc.type_m_path_table, path_table[2]); + set_732(vol_desc.opt_type_m_path_table, path_table[3]); + + /* + * Now we copy the actual root directory record + */ + memcpy(vol_desc.root_directory_record, &root_record, + sizeof(struct iso_directory_record) + 1); + + /* + * The rest is just fluff. It looks nice to fill in many of these fields, + * though. + */ + FILL_SPACE(volume_set_id); + if(volset_id) memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id)); + + FILL_SPACE(publisher_id); + if(publisher) memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher)); + + FILL_SPACE(preparer_id); + if(preparer) memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer)); + + FILL_SPACE(application_id); + if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid)); + + FILL_SPACE(copyright_file_id); + if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright, + strlen(copyright)); + + FILL_SPACE(abstract_file_id); + if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract, + strlen(abstract)); + + FILL_SPACE(bibliographic_file_id); + if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio, + strlen(biblio)); + + FILL_SPACE(creation_date); + FILL_SPACE(modification_date); + FILL_SPACE(expiration_date); + FILL_SPACE(effective_date); + vol_desc.file_structure_version[0] = 1; + FILL_SPACE(application_data); + + memcpy(vol_desc.creation_date, iso_time, 17); + memcpy(vol_desc.modification_date, iso_time, 17); + memcpy(vol_desc.expiration_date, "0000000000000000", 17); + memcpy(vol_desc.effective_date, iso_time, 17); + + /* + * if not a bootable cd do it the old way + */ + xfwrite(&vol_desc, 1, 2048, outfile); + if (!use_eltorito) + { + /* + * For some reason, Young Minds writes this twice. Aw, what the heck + */ + xfwrite(&vol_desc, 1, 2048, outfile); + } + else + { + /* + * Next we write out the boot volume descriptor for the disc + */ + get_torito_desc(&boot_desc); + xfwrite(&boot_desc, 1, 2048, outfile); + } + + /* + * either way, we've written two more + */ + + last_extent_written += 2; + + /* + * Now write the end volume descriptor. Much simpler than the other one + */ + memset(&vol_desc, 0, sizeof(vol_desc)); + vol_desc.type[0] = ISO_VD_END; + memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); + vol_desc.version[0] = 1; + xfwrite(&vol_desc, 1, 2048, outfile); + xfwrite(&vol_desc, 1, 2048, outfile); + last_extent_written += 2; + + /* + * Next we write the path tables + */ + xfwrite(path_table_l, 1, path_blocks << 11, outfile); + xfwrite(path_table_m, 1, path_blocks << 11, outfile); + last_extent_written += 2*path_blocks; + free(path_table_l); + free(path_table_m); + path_table_l = NULL; + path_table_m = NULL; + + /* + * OK, all done with that crap. Now write out the directories. + * This is where the fur starts to fly, because we need to keep track of + * each file as we find it and keep track of where we put it. + */ + +#ifdef DBG_ISO + fprintf(stderr,"Total directory extents being written = %d\n", last_extent); +#endif +#if 0 + generate_one_directory(root, outfile); +#endif + generate_iso9660_directories(root, outfile); + + if(extension_record) + { + xfwrite(extension_record, 1, SECTOR_SIZE, outfile); + last_extent_written++; + } + + /* + * Now write all of the files that we need. + */ + fprintf(stderr,"Total extents scheduled to be written = %d\n", + last_extent - session_start); + write_files(outfile); + + fprintf(stderr,"Total extents actually written = %d\n", + last_extent_written - session_start); + /* + * Hard links throw us off here + */ + if(should_write != last_extent - session_start) + { + fprintf(stderr,"Number of extents written not what was predicted. Please fix.\n"); + fprintf(stderr,"Predicted = %d, written = %d\n", should_write, last_extent); + } + + fprintf(stderr,"Total translation table size: %d\n", table_size); + fprintf(stderr,"Total rockridge attributes bytes: %d\n", rockridge_size); + fprintf(stderr,"Total directory bytes: %d\n", total_dir_size); + fprintf(stderr,"Path table size(bytes): %d\n", path_table_size); + +#ifdef DEBUG + fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n", + next_extent, last_extent, last_extent_written); +#endif + + return 0; + +} /* iso_write(... */ |