summaryrefslogtreecommitdiff
path: root/genisoimage/name.c
diff options
context:
space:
mode:
Diffstat (limited to 'genisoimage/name.c')
-rw-r--r--genisoimage/name.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/genisoimage/name.c b/genisoimage/name.c
new file mode 100644
index 0000000..c2faeb6
--- /dev/null
+++ b/genisoimage/name.c
@@ -0,0 +1,531 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)name.c 1.28 04/03/05 joerg */
+/*
+ * File name.c - map full Unix file names to unique 8.3 names that
+ * would be valid on DOS.
+ *
+ *
+ * Written by Eric Youngdale (1993).
+ * Almost totally rewritten by J. Schilling (2000).
+ *
+ * Copyright 1993 Yggdrasil Computing, Incorporated
+ * Copyright (c) 1999,2000 J. Schilling
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mconfig.h>
+#include "genisoimage.h"
+#include <standard.h>
+#include <schily.h>
+#include <ctype.h>
+
+void iso9660_check(struct iso_directory_record *idr,
+ struct directory_entry *ndr);
+int iso9660_file_length(const char *name,
+ struct directory_entry *sresult,
+ int dirflag);
+
+void
+iso9660_check(struct iso_directory_record *idr,
+ struct directory_entry *ndr)
+{
+ int nlen;
+ char schar;
+ char *p;
+ char *np;
+
+ nlen = idr->name_len[0];
+ schar = idr->name[nlen];
+
+ if (nlen == 1 && (idr->name[0] == '\0' || idr->name[0] == '\001'))
+ return;
+
+ idr->name[nlen] = '\0'; /* Make it null terminated */
+ if ((p = strrchr(idr->name, ';')) != NULL) {
+ *p = '\0'; /* Strip off old version # */
+ }
+ iso9660_file_length(idr->name, ndr,
+ (idr->flags[0] & ISO_DIRECTORY) != 0);
+
+ if ((np = strrchr(ndr->isorec.name, ';')) != NULL) {
+ *np = '\0'; /* Strip off new version # */
+ }
+ if (strcmp(idr->name, ndr->isorec.name)) {
+ if (p)
+ *p = ';'; /* Restore old version # */
+ if (np)
+ *np = ';'; /* Restore new version # */
+ errmsgno(EX_BAD,
+ "Old session has illegal name '%.*s' length %d\n",
+ idr->name_len[0],
+ idr->name,
+ idr->name_len[0]);
+ errmsgno(EX_BAD,
+ "New session will use name '%s'\n",
+ ndr->isorec.name);
+ }
+ if (p)
+ *p = ';'; /* Restore old version # */
+ if (np)
+ *np = ';'; /* Restore new version # */
+ idr->name[nlen] = schar; /* Restore old iso record*/
+}
+
+/*
+ * 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.
+ *
+ * Note: name being const * is a bug introduced by Eric but hard to
+ * fix without going through the whole source.
+ */
+int
+iso9660_file_length(const char *name /* Not really const !!! */,
+ struct directory_entry *sresult, int dirflag)
+{
+ char c;
+ char *cp;
+ int before_dot = 8;
+ int after_dot = 3;
+ 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 ochars_after_dot;
+ int ochars_before_dot;
+ int seen_dot = 0;
+ int seen_semic = 0;
+ int tildes = 0;
+
+ result = sresult->isorec.name;
+
+ if (sresult->priority)
+ priority = sresult->priority;
+
+ /*
+ * For the '.' entry, generate the correct record, and return 1 for
+ * the length.
+ */
+ if (strcmp(name, ".") == 0) {
+ *result = 0;
+ return (1);
+ }
+ /*
+ * For the '..' entry, generate the correct record, and return 1
+ * for the length.
+ */
+ if (strcmp(name, "..") == 0) {
+ *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'))) {
+ cp = last_dot;
+ *cp = '\0';
+ last_dot = strrchr(pnt, '.');
+ *cp = '.';
+ /*
+ * If we found no better '.' back up to the last match.
+ */
+ if (last_dot == NULL)
+ last_dot = cp;
+ }
+
+ if (last_dot != NULL) {
+ ochars_after_dot = strlen(last_dot); /* dot counts */
+ ochars_before_dot = last_dot - pnt;
+ } else {
+ ochars_before_dot = 128;
+ ochars_after_dot = 0;
+ }
+ /*
+ * 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 || iso9660_level > 1) {
+ before_dot = iso9660_namelen;
+ after_dot = before_dot - 1;
+
+ if (!dirflag) {
+ if (ochars_after_dot > ((iso9660_namelen/2)+1)) {
+ /*
+ * The minimum number of characters before
+ * the dot is 3 to allow renaming.
+ * Let us allow to have 15 characters after
+ * dot to give more rational filenames.
+ */
+ before_dot = iso9660_namelen/2;
+ after_dot = ochars_after_dot;
+ } else {
+ before_dot -= ochars_after_dot; /* dot counts */
+ after_dot = ochars_after_dot;
+ }
+ }
+ }
+
+ while (*pnt) {
+#ifdef VMS
+ if (strcmp(pnt, ".DIR;1") == 0) {
+ break;
+ }
+#endif
+
+#ifdef Eric_code_does_not_work
+ /*
+ * XXX If we make this code active we get corrupted direcrory
+ * XXX trees with infinite loops.
+ */
+ /*
+ * This character indicates a Unix style of backup file
+ * generated by some editors. Lower the priority of the file.
+ */
+ if (iso_translate && *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 (iso_translate && *pnt == '~') {
+ priority = 1;
+ tildes++;
+ pnt++;
+ continue;
+ }
+#endif
+ /*
+ * 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. UNLESS the ';' is part of the
+ * filename and no valid version number is following.
+ */
+ if (use_fileversion && *pnt == ';' && seen_dot) {
+ /*
+ * Check if a valid version number follows.
+ * The maximum valid version number is 32767.
+ */
+ for (c = 1, cp = (char *)&pnt[1]; c < 6 && *cp; c++, cp++) {
+ if (*cp < '0' || *cp > '9')
+ break;
+ }
+ if (c <= 6 && *cp == '\0' && atoi(&pnt[1]) <= 32767)
+ seen_semic++;
+ }
+ /*
+ * If we have a name with multiple '.' characters, we ignore
+ * everything after we have gotten the extension.
+ */
+ if (ignore) {
+ pnt++;
+ continue;
+ }
+ if (current_length >= iso9660_namelen) {
+#ifdef nono
+ /*
+ * Does not work as we may truncate before the dot.
+ */
+ fprintf(stderr, "Truncating '%s' to '%.*s'.\n",
+ name,
+ current_length, sresult->isorec.name);
+ ignore++;
+#endif
+ pnt++;
+ continue;
+ }
+ /* Spin past any iso9660 version number we might have. */
+ if (seen_semic) {
+ if (seen_semic == 1) {
+ seen_semic++;
+ *result++ = ';';
+ }
+ if (*pnt >= '0' && *pnt <= '9') {
+ *result++ = *pnt;
+ }
+ extra++;
+ pnt++;
+ continue;
+ }
+
+ if (*pnt == '.') {
+ if (!allow_multidot) {
+ if (strcmp(pnt, ".tar.gz") == 0)
+ pnt = last_dot = ".tgz";
+ if (strcmp(pnt, ".ps.gz") == 0)
+ pnt = last_dot = ".psz";
+ }
+
+ if (!chars_before_dot && !allow_leading_dots) {
+ /*
+ * DOS can't read files with dot first
+ */
+ chars_before_dot++;
+ *result++ = '_'; /* Substitute underscore */
+
+ } else if (pnt == last_dot) {
+ if (seen_dot) {
+ ignore++;
+ continue;
+ }
+ *result++ = '.';
+ seen_dot++;
+ } else if (allow_multidot) {
+ if (chars_before_dot < before_dot) {
+ chars_before_dot++;
+ *result++ = '.';
+ }
+ } else {
+ /*
+ * If this isn't the dot that we use
+ * for the extension, then change the
+ * character into a '_' instead.
+ */
+ if (chars_before_dot < before_dot) {
+ chars_before_dot++;
+ *result++ = '_';
+ }
+ }
+ } else {
+ if ((seen_dot && (chars_after_dot < after_dot) &&
+ ++chars_after_dot) ||
+ (!seen_dot && (chars_before_dot < before_dot) &&
+ ++chars_before_dot)) {
+
+ c = *pnt;
+ if (c & 0x80) {
+ /*
+ * We allow 8 bit chars if -iso-level
+ * is at least 4
+ *
+ * XXX We should check if the output
+ * XXX character set is a 7 Bit ASCI
+ * extension.
+ */
+ if (iso9660_level >= 4) {
+ c = conv_charset(c, in_nls, out_nls);
+ } else {
+ c = '_';
+ }
+ } else if (!allow_lowercase) {
+ c = islower((unsigned char)c) ?
+ toupper((unsigned char)c) : c;
+ }
+ if (relaxed_filenames) {
+ /*
+ * Here we allow a more relaxed syntax.
+ */
+ if (c == '/')
+ c = '_';
+ *result++ = c;
+ } else switch (c) {
+ /*
+ * Dos style filenames.
+ * We really restrict the names here.
+ */
+
+ default:
+ *result++ = c;
+ 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 '%': /* not legal DOS */
+ /* filename */
+ case ':':
+ case ';': /* already handled */
+ case '.': /* already handled */
+ case ',': /* already handled */
+ case '\t':
+ case ' ':
+ /* V1 only separators */
+ case '/':
+ case '"':
+ case '[':
+ case ']':
+ /* terminators */
+ case '>':
+ case '<':
+ case '|':
+ /*
+ * Other characters that are not valid ISO-9660
+ * characters.
+ */
+ case '!':
+/* case '#':*/
+ case '$':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+/* case '-':*/
+ case '?':
+ case '@':
+ case '\\':
+ case '^':
+ case '`':
+ case '{':
+ case '}':
+/* case '~':*/
+ /*
+ * All characters below 32 (space) are not
+ * allowed too.
+ */
+ case 1: case 2: case 3: case 4:
+ case 5: case 6: case 7: case 8:
+ /* case 9: */
+ case 10: case 11: case 12:
+ case 13: case 14: case 15:
+ case 16: case 17: case 18:
+ case 19: case 20: case 21:
+ case 22: case 23: case 24:
+ case 25: case 26: case 27:
+ case 28: case 29: case 30:
+ case 31:
+
+ /*
+ * Hmm - what to do here? Skip? Win95
+ * looks like it substitutes '_'
+ */
+ *result++ = '_';
+ break;
+
+ case '#':
+ case '-':
+ case '~':
+ /*
+ * Check if we should allow these
+ * illegal characters used by
+ * Microsoft.
+ */
+ if (iso_translate)
+ *result++ = '_';
+ else
+ *result++ = c;
+ break;
+ } /* switch (*pnt) */
+ } else { /* if (chars_{after,before}_dot) ... */
+ pnt++;
+ continue;
+ }
+ } /* else *pnt == '.' */
+ 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 (chars_before_dot >= (iso9660_namelen-1)) {
+ chars_before_dot--;
+ result--;
+ }
+ *result++ = '.';
+ extra++;
+ }
+ if (!omit_version_number && !seen_semic) {
+ *result++ = ';';
+ *result++ = '1';
+ extra += 2;
+ }
+ }
+ *result++ = 0;
+ sresult->priority = priority;
+
+/*#define DEBBUG*/
+#ifdef DEBBUG
+ fprintf(stderr, "NAME: '%s'\n", sresult->isorec.name);
+ fprintf(stderr, "chars_before_dot %d chars_after_dot %d seen_dot %d extra %d\n",
+ chars_before_dot, chars_after_dot, seen_dot, extra);
+#endif
+ return (chars_before_dot + chars_after_dot + seen_dot + extra);
+}