Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

name.c

/*
 * 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);
}

Generated by  Doxygen 1.6.0   Back to index