home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / UNZP50P1.ZIP / mapname.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  16KB  |  375 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   mapname.c
  4.  
  5.   This routine changes DEC-20, VAX/VMS, and DOS-style filenames into normal
  6.   Unix names (and vice versa, in some cases); it also creates any necessary 
  7.   directories, if the -d switch was specified.
  8.  
  9.   ---------------------------------------------------------------------------
  10.  
  11.   Notes:
  12.  
  13.      - This routine REALLY needs to be rewritten (different routines for
  14.        each output OS, with different rules for different parts of the path
  15.        name).  If each zip program stores local-format names (like the VMS
  16.        one did at one time), it would probably be best to convert to an in-
  17.        termediate format first (assuming we're not extracting under the same
  18.        OS as that under which the zipfile was created), then from that to
  19.        the current operating system's format.
  20.      - The strcpy and strcat operations on both cdp and filename may over-
  21.        write memory, since they don't check lengths.  With a kilobyte in
  22.        which to work, this is probably not that big a deal, but it could
  23.        cause problems eventually.
  24.  
  25.   ---------------------------------------------------------------------------*/
  26.  
  27.  
  28. #include "unzip.h"
  29.  
  30.  
  31. /*******************/
  32. /* Mapname Defines */
  33. /*******************/
  34.  
  35. #ifdef VMS
  36. #  define PERMS   0
  37. #else
  38. #  define PERMS   0777
  39. #endif
  40.  
  41. #ifndef NO_MKDIR
  42. #  if (defined(DOS_OS2) && !defined(__GO32__))
  43. #    if (_MSC_VER >= 600)       /* have special MSC mkdir prototype */
  44. #      include <direct.h>
  45. #    else                       /* own prototype because dir.h conflicts? */
  46.        int mkdir(const char *path);
  47. #    endif /* ?(MSC 6.0 or later) */
  48. #    define MKDIR(path,mode)   mkdir(path)
  49. #  else /* !DOS_OS2 || __GO32__ */
  50. #    ifdef MACOS
  51. #      define MKDIR(path,mode)   macmkdir(path,gnVRefNum,glDirID)
  52. #    else /* !MACOS */
  53. #      define MKDIR(path,mode)   mkdir(path,mode)
  54. #    endif /* ?MACOS */
  55. #  endif /* ?(DOS_OS2 && !__GO32__)  */
  56. #endif /* !NO_MKDIR */
  57.  
  58.  
  59.  
  60.  
  61. /************************/
  62. /*  Function mapname()  */
  63. /************************/
  64.  
  65. int mapname(create_dirs)   /* return 0 if no error, 1 if caution (filename */
  66.     int create_dirs;       /*  truncated), 2 if warning (skip file because */
  67. {                          /*  dir doesn't exist), 3 if error (skip file) */
  68. #ifdef NO_MKDIR
  69.     char command[FILNAMSIZ+40]; /* buffer for system() call */
  70. #endif
  71. #ifdef VMS
  72.     int stat_val;               /* temp. holder for stat() return value */
  73.     char *dp, *xp;              /* pointers to directory name */
  74.     char *np;                   /* pointer into filename */
  75. #endif /* VMS */
  76. #ifdef DOS_VMS
  77.     char *last_dot=NULL;        /* last dot not converted to underscore */
  78. #endif /* DOS_VMS */
  79. #ifdef OS2
  80.     char *last;
  81.     extern char longfilename[]; /*  AFTER file created and closed */
  82.     extern int longname;        /* used also in file_io.c:  set EAs */
  83.     int longdir;
  84. #endif /* OS2 */
  85.     char name[FILNAMSIZ];       /* file name buffer */
  86.     char *pp, *cp, *cdp;        /* character pointers */
  87.     char delim = '\0';          /* directory delimiter */
  88.     int quote = FALSE;          /* flags */
  89.     int indir = FALSE;
  90.     int done = FALSE;
  91.     int created = FALSE;
  92.     register unsigned workch;   /* hold the character being tested */
  93.  
  94.  
  95. /*---------------------------------------------------------------------------
  96.     Initialize various pointers and counters and stuff.
  97.   ---------------------------------------------------------------------------*/
  98.  
  99. #ifdef MAP_DEBUG
  100.     fprintf(stderr, "%s ", filename);   /* echo name of this file */
  101. #endif
  102.     cdp = (char *)NULL;
  103.     pp = name;                  /* point to translation buffer */
  104.     *name = '\0';               /* initialize buffer */
  105.     if (!jflag) {               /* -j => junk pathnames */
  106.         cdp = (char *)malloc(strlen(filename) + 3);   /* place for holding */
  107.         if (cdp == (char *)NULL) {                    /*  directory name */
  108.             fprintf(stderr, "mapname:  out of memory [%s]\n", filename);
  109.             return 3;
  110.         }
  111. #ifdef VMS
  112.         *cdp++ = '[';
  113.         xp = cdp;               /* always points to last non-NULL char */
  114.         *cdp++ = '.';
  115. #endif /* VMS */
  116. #ifdef MACOS
  117.         *cdp = ':';             /* the Mac uses ':' as a directory separator */
  118.         cdp[1] = '\0';
  119. #else /* !MACOS */
  120.         *cdp = '\0';
  121. #endif /* ?MACOS */
  122.     }
  123.  
  124. /*---------------------------------------------------------------------------
  125.     Begin main loop through characters in filename.
  126.   ---------------------------------------------------------------------------*/
  127.  
  128.     for (cp = filename; (workch = (unsigned char) *cp++) != 0  &&  !done;) {
  129.  
  130.         if (quote) {                 /* if char quoted, */
  131.             *pp++ = (char) workch;   /*  include it literally */
  132.             quote = FALSE;
  133.         } else if (indir) {          /* if in directory name, */
  134.             if (workch == (unsigned)delim)  /*  look for end delimiter */
  135.                 indir = FALSE;
  136.         } else
  137.             switch (workch) {
  138.             case '<':                /* discard DEC-20 directory name */
  139.                 indir = TRUE;
  140.                 delim = '>';
  141.                 break;
  142.             case '[':                /* discard VMS directory name */
  143.                 indir = TRUE;
  144.                 delim = ']';
  145.                 break;
  146.             case '/':                /* discard Unix path name  */
  147.             case '\\':               /*  or MS-DOS path name... */
  148.                                      /*  iff -j flag was given  */
  149.                 /*
  150.                  * Special processing case:  if -j flag was not specified on
  151.                  * command line and create_dirs is TRUE, create any necessary
  152.                  * directories included in the pathname.  Creation of dirs is
  153.                  * straightforward on BSD and MS-DOS machines but requires use
  154.                  * of the system() command on SysV systems (or any others which
  155.                  * don't have mkdir()).  The stat() check is necessary with
  156.                  * MSC because it doesn't have an EEXIST errno, and it saves
  157.                  * the overhead of multiple system() calls on SysV machines.
  158.                  */
  159.  
  160.                 if (!jflag) {
  161.                     *pp = '\0';
  162. #ifdef VMS
  163.                     dp = name;
  164.                     while (*++xp = *dp++);  /* copy name to cdp */
  165.                     last_dot = NULL;        /* dir name:  no dots allowed */
  166.                     strcpy(xp, ".dir");     /* add extension for stat check */
  167.                     stat_val = stat(cdp, &statbuf);
  168.                     *xp = '\0';             /* remove extension for all else */
  169.                     if (stat_val) {         /* doesn't exist, so create */
  170. #else /* !VMS */
  171. #ifdef MSDOS
  172.                     if (last_dot != NULL) {  /* one dot in dir name is legal */
  173.                         *last_dot = '.';
  174.                         last_dot = NULL;
  175.                     }
  176. #endif /* MSDOS */
  177.                     strcat(cdp, name);
  178. #ifdef OS2
  179.                     if ((longdir = !IsFileNameValid(cdp)) != 0) {
  180.                         last = strrchr(cdp, '/');
  181.                         strcpy(longfilename, last ? last + 1 : cdp);
  182.                         fprintf(stderr, "renaming directory \"%s\"", cdp);
  183.                         ChangeNameForFAT(cdp);
  184.                         fprintf(stderr, " to \"%s\"\n", cdp);
  185.                     }
  186. #endif /* OS2 */
  187.                     if (stat(cdp, &statbuf)) {  /* doesn't exist, so create */
  188. #endif /* ?VMS */
  189.                         if (!create_dirs) /* told not to create (freshening) */
  190.                             return 2;
  191. #ifdef NO_MKDIR
  192.                         sprintf(command,
  193.                           "IFS=\" \t\n\" /bin/mkdir %s 2>/dev/null", cdp);
  194.                         if (system(command)) {
  195. #else /* !NO_MKDIR */
  196.                         if (MKDIR(cdp, PERMS) == -1) {
  197. #endif /* ?NO_MKDIR */
  198.                             perror(cdp);
  199.                             free(cdp);
  200.                             fprintf(stderr, "mapame:  unable to process [%s]\n",
  201.                               filename);
  202.                             return 3;
  203.                         }
  204.                         created = TRUE;
  205. #ifdef OS2
  206.                         if (longdir)
  207.                             SetLongNameEA(cdp, longfilename);
  208. #endif /* OS2 */
  209.                     } else if (!(statbuf.st_mode & S_IFDIR)) {
  210.                         fprintf(stderr,
  211.                           "mapname:  %s exists but is not a directory\n", cdp);
  212.                         free(cdp);
  213.                         fprintf(stderr, "mapame:  unable to process [%s]\n",
  214.                           filename);
  215.                         return 3;
  216.                     }
  217. #ifdef VMS
  218.                     *xp = '/';  /* for now... (mkdir()) */
  219. #else /* !VMS */
  220. #ifdef MACOS
  221.                     strcat(cdp, ":");
  222. #else /* !MACOS */
  223.                     strcat(cdp, "/");
  224. #endif /* ?MACOS */
  225. #endif /* ?VMS */
  226.                 }
  227.                 pp = name;
  228.                 break;
  229.             case ':':
  230. #ifdef UNIX                       /* colon is a valid character in Unix */
  231.                 *pp++ = workch;   /*  filenames, so keep it; anywhere else, */
  232. #else /* !UNIX */                 /*  change it to an underscore (should  */
  233.                 *pp++ = '_';      /*  NOT have stored drive/node names!!) */
  234. #endif /* ?UNIX */
  235.              /* pp = name;  (OLD) discard DEC dev: or node:: name */
  236.                 break;
  237.             case '.':                   /* DEC-20 generation number or */
  238. #ifdef DOS_VMS                          /*  MS-DOS or VMS separator */
  239.                 last_dot = pp;          /* point at last dot so far... */
  240.                 *pp++ = '_';            /* convert dot to underscore */
  241. #else /* !DOS_VMS */
  242.                 *pp++ = workch;
  243. #endif /* ?DOS_VMS */
  244.                 break;
  245.             case ';':                   /* VMS generation or DEC-20 attrib */
  246. #ifdef MACOS
  247.                 if (V_flag || macflag)
  248. #else /* !MACOS */
  249.                 if (V_flag)                 /* if requested, save VMS ";##" */
  250. #endif /* ?MACOS */                         /*  version info or Macintosh */
  251.                     *pp++ = (char) workch;  /*  (?) info; otherwise discard */
  252.                 else                        /*  everything starting with */
  253.                     done = TRUE;            /*  semicolon.  (Worry about */
  254.                 break;                      /*  DEC-20 later.) */
  255.             case '\026':                /* control-V quote for special chars */
  256.                 quote = TRUE;           /* set flag for next character */
  257.                 break;
  258.             case ' ':
  259. #if (defined(VMS) || defined(MTS))
  260.                 *pp++ = '_';            /* change spaces to underscore */
  261. #else /* !(VMS || MTS) */               /*  under VMS and MTS, and under DOS */
  262. #ifdef DOS_OS2                          /*  and OS/2 if -s not specified. */
  263.                 if (!sflag)
  264.                     *pp++ = '_';
  265.                 else
  266. #endif /* DOS_OS2 */
  267.                 *pp++ = (char) workch;  /* otherwise, leave as spaces */
  268. #endif /* ?(VMS || MTS) */
  269.                 break;
  270.             default:
  271. #ifdef MACOS
  272.                 if ((macflag && ((unsigned)workch > 0x1F)) || isprint(workch))
  273. #else /* !MACOS */
  274. #if (defined(DOS_OS2) || (defined(UNIX) && !defined(VMS)))  /* allow non-US */
  275.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  276. #else /* !(DOS_OS2 || UNIX) */
  277.                 if (isprint(workch))    /* other printable, just keep */
  278. #endif /* ?(DOS_OS2 || UNIX) */
  279. #endif /* ?MACOS */
  280.                     *pp++ = (char) workch;
  281.             } /* end switch */
  282.     } /* end for loop */
  283.     *pp = '\0';                         /* done with name:  terminate it */
  284. #ifdef DOS_VMS                          /*  and put a dot back in if VMS */
  285.     if (last_dot != NULL)               /*  or MS-DOS */
  286.         *last_dot = '.';
  287. #endif /* DOS_VMS */
  288.  
  289. /*---------------------------------------------------------------------------
  290.     We COULD check for existing names right now, create a "unique" name, etc.
  291.     At present, we do this in extract_or_test_files() (immediately after we
  292.     return from here).  If conversion went bad, the name'll either be nulled
  293.     out (in which case we'll return non-0), or following procedures won't be
  294.     able to create the extracted file and other error msgs will result.
  295.   ---------------------------------------------------------------------------*/
  296.  
  297.     if (filename[strlen(filename) - 1] == '/') {
  298.         /* A directory was extracted. It had a trailing /, 
  299.          * don't report the error below. */
  300.         if (created) {
  301.             printf("   Creating: %s", filename);
  302. #ifdef OS2
  303.             SetPathInfo(filename, lrec.last_mod_file_date,
  304.                                   lrec.last_mod_file_time, -1);
  305.             if (extra_field)
  306.                 SetEAs(filename, extra_field);
  307. #endif
  308.             printf("\n");
  309.         }
  310.         return 2; /* but skip file */
  311.     }
  312.  
  313.     if (*name == '\0') {
  314.         fprintf(stderr, "mapname:  conversion of [%s] failed\n", filename);
  315.         return 3;
  316.     }
  317.  
  318. #ifdef OS2
  319.     if (!longname && ((longname = !IsFileNameValid(name)) != 0)) {
  320.         /* in case of second call after user renamed the file, skip this */
  321.         last = strrchr(name, '/');      /* THIS time, save for file_io */
  322.         last = last ? last + 1 : name;  /* only last component */
  323.         strcpy(longfilename, last);
  324.         fprintf(stderr, "renaming \"%s\"", name);
  325.         ChangeNameForFAT(last);
  326.         fprintf(stderr, " to \"%s\"\n", name);
  327.     }
  328. #endif /* OS2 */
  329.  
  330. #ifdef VMS
  331.     /* convert filename to legal VMS one, substituting underscores for
  332.      * all invalid characters */
  333.     for (np = name;  *np;  ++np)
  334.         if (!(isdigit(*np) || isalpha(*np) || (*np == '$') ||
  335.             (*np == '-') || (*np == '_') || (*np == '.') || (*np == ';')))
  336.             *np = '_';
  337. #endif /* VMS */
  338.  
  339.     if (!jflag) {
  340. #ifdef VMS
  341.         *xp++ = ']';                 /* proper end-of-dir-name delimiter */
  342.         if (xp == cdp) {             /* no path-name stuff, so... */
  343.             strcpy(filename, name);  /* copy file name into global */
  344.             cdp -= 2;                /*   prepare to free malloc'd space */
  345.         } else {                     /* we've added path-name stuff... */
  346.             *xp = '\0';              /*   so terminate and convert to */
  347.             dp = cdp;                /*   VMS subdir separators (skip */
  348.             while (*++dp)            /*   first char:  better not be */
  349.                 if (*dp == '/')      /*   "/"):  change all slashes */
  350.                     *dp = '.';       /*   to dots */
  351.             cdp -= 2;                /*   include leading bracket and dot */
  352.             strcpy(filename, cdp);   /* copy VMS-style path name into global */
  353.             strcat(filename, name);  /* concatenate file name to global */
  354.         }
  355. #else /* !VMS */
  356.         strcpy(filename, cdp);       /* either "" or slash-terminated path */
  357.         strcat(filename, name);      /* append file name to path name */
  358. #endif /* ?VMS */
  359.         free(cdp);
  360.     } else
  361.         strcpy(filename, name);      /* copy converted name into global */
  362.  
  363. #if PATH_MAX < (FILNAMSIZ - 1)
  364.     /* check the length of the file name and truncate if necessary */
  365.     if (PATH_MAX < strlen(filename)) {
  366.         fprintf(stderr, "caution:  truncating filename\n");
  367.         filename[PATH_MAX] = '\0';
  368.         fprintf(stderr, "[ %s ]\n", filename);
  369.         return 1;             /* 1:  warning error */
  370.     }
  371. #endif
  372.  
  373.     return 0;
  374. }
  375.