flexos.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:32k
源码类别:

压缩解压

开发平台:

MultiPlatform

  1. /*---------------------------------------------------------------------------
  2.   flexos.c
  3.   FlexOS-specific routines for use with Info-ZIP's UnZip 5.2 and later.
  4.   Based upon the MSDOS version of this file (msdos/msdos.c)
  5.   Contains:  do_wild()
  6.              mapattr()
  7.              mapname()
  8.              map2fat()
  9.              checkdir()
  10.              close_outfile()
  11.              dateformat()
  12.              version()
  13.              _wildarg()
  14.   ---------------------------------------------------------------------------*/
  15. #define UNZIP_INTERNAL
  16. #include "unzip.h"
  17. #include <flexif.h>
  18. /* The following should really be a static declaration,  but the compiler
  19.    complains (crappy compiler can't cope with a static forward declaration).
  20.  */
  21. extern void map2fat OF((char *pathcomp, char *last_dot));
  22. static int created_dir;        /* used by mapname(), checkdir() */
  23. static int renamed_fullpath;   /* ditto */
  24. /*****************************/
  25. /*  Strings used in flexos.c  */
  26. /*****************************/
  27. #ifndef SFX
  28.   static char Far CantAllocateWildcard[] =
  29.     "warning:  cannot allocate wildcard buffersn";
  30. #endif
  31. static char Far Creating[] = "   creating: %sn";
  32. static char Far ConversionFailed[] = "mapname:  conversion of %s failedn";
  33. static char Far PathTooLong[] = "checkdir error:  path too long: %sn";
  34. static char Far CantCreateDir[] = "checkdir error:  cannot create %sn
  35.                  unable to process %s.n";
  36. static char Far DirIsntDirectory[] =
  37.   "checkdir error:  %s exists but is not directoryn
  38.                  unable to process %s.n";
  39. static char Far PathTooLongTrunc[] =
  40.   "checkdir warning:  path too long; truncatingn                   %sn
  41.                 -> %sn";
  42. #if (!defined(SFX) || defined(SFX_EXDIR))
  43.    static char Far CantCreateExtractDir[] =
  44.      "checkdir:  cannot create extraction directory: %sn";
  45. #endif
  46. #include <dirent.h>
  47. #ifndef SFX
  48. /************************/
  49. /*  Function do_wild()  */   /* identical to OS/2 version */
  50. /************************/
  51. char *do_wild(__G__ wildspec)
  52.     __GDEF
  53.     char *wildspec;          /* only used first time on a given dir */
  54. {
  55.     static DIR *dir = (DIR *)NULL;
  56.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  57.     static int firstcall=TRUE, have_dirname, dirnamelen;
  58.     char *fnamestart;
  59.     struct dirent *file;
  60.     /* Even when we're just returning wildspec, we *always* do so in
  61.      * matchname[]--calling routine is allowed to append four characters
  62.      * to the returned string, and wildspec may be a pointer to argv[].
  63.      */
  64.     if (firstcall) {        /* first call:  must initialize everything */
  65.         firstcall = FALSE;
  66.         if (!iswild(wildspec)) {
  67.             strcpy(matchname, wildspec);
  68.             have_dirname = FALSE;
  69.             dir = NULL;
  70.             return matchname;
  71.         }
  72.         /* break the wildspec into a directory part and a wildcard filename */
  73.         if ((wildname = strrchr(wildspec, '/')) == (char *)NULL &&
  74.             (wildname = strrchr(wildspec, ':')) == (char *)NULL) {
  75.             dirname = ".";
  76.             dirnamelen = 1;
  77.             have_dirname = FALSE;
  78.             wildname = wildspec;
  79.         } else {
  80.             ++wildname;     /* point at character after '/' or ':' */
  81.             dirnamelen = (int)(wildname - wildspec);
  82.             if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  83.                 Info(slide, 1, ((char *)slide,
  84.                   LoadFarString(CantAllocateWildcard)));
  85.                 strcpy(matchname, wildspec);
  86.                 return matchname;   /* but maybe filespec was not a wildcard */
  87.             }
  88. /* GRR:  cannot strip trailing char for opendir since might be "d:/" or "d:"
  89.  *       (would have to check for "./" at end--let opendir handle it instead) */
  90.             strncpy(dirname, wildspec, dirnamelen);
  91.             dirname[dirnamelen] = '';       /* terminate for strcpy below */
  92.             have_dirname = TRUE;
  93.         }
  94.         Trace((stderr, "do_wild:  dirname = [%s]n", dirname));
  95.         if ((dir = opendir(dirname)) != (DIR *)NULL) {
  96.             if (have_dirname) {
  97.                 strcpy(matchname, dirname);
  98.                 fnamestart = matchname + dirnamelen;
  99.             } else
  100.                 fnamestart = matchname;
  101.             while ((file = readdir(dir)) != (struct dirent *)NULL) {
  102.                 Trace((stderr, "do_wild:  readdir returns %sn", file->d_name));
  103.                 strcpy(fnamestart, file->d_name);
  104.                 if (strrchr(fnamestart, '.') == (char *)NULL)
  105.                     strcat(fnamestart, ".");
  106.                 if (match(fnamestart, wildname, 1) &&  /* 1 == ignore case */
  107.                     /* skip "." and ".." directory entries */
  108.                     strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
  109.                     Trace((stderr, "do_wild:  match() succeedsn"));
  110.                     /* remove trailing dot */
  111.                     fnamestart += strlen(fnamestart) - 1;
  112.                     if (*fnamestart == '.')
  113.                         *fnamestart = '';
  114.                     return matchname;
  115.                 }
  116.             }
  117.             /* if we get to here directory is exhausted, so close it */
  118.             closedir(dir);
  119.             dir = (DIR *)NULL;
  120.         }
  121. #ifdef DEBUG
  122.         else {
  123.             Trace((stderr, "do_wild:  opendir(%s) returns NULLn", dirname));
  124.         }
  125. #endif /* DEBUG */
  126.         /* return the raw wildspec in case that works (e.g., directory not
  127.          * searchable, but filespec was not wild and file is readable) */
  128.         strcpy(matchname, wildspec);
  129.         return matchname;
  130.     }
  131.     /* last time through, might have failed opendir but returned raw wildspec */
  132.     if (dir == (DIR *)NULL) {
  133.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  134.         if (have_dirname)
  135.             free(dirname);
  136.         return (char *)NULL;
  137.     }
  138.     /* If we've gotten this far, we've read and matched at least one entry
  139.      * successfully (in a previous call), so dirname has been copied into
  140.      * matchname already.
  141.      */
  142.     if (have_dirname) {
  143.         /* strcpy(matchname, dirname); */
  144.         fnamestart = matchname + dirnamelen;
  145.     } else
  146.         fnamestart = matchname;
  147.     while ((file = readdir(dir)) != (struct dirent *)NULL) {
  148.         Trace((stderr, "do_wild:  readdir returns %sn", file->d_name));
  149.         strcpy(fnamestart, file->d_name);
  150.         if (strrchr(fnamestart, '.') == (char *)NULL)
  151.             strcat(fnamestart, ".");
  152.         if (match(fnamestart, wildname, 1)) {   /* 1 == ignore case */
  153.             Trace((stderr, "do_wild:  match() succeedsn"));
  154.             /* remove trailing dot */
  155.             fnamestart += strlen(fnamestart) - 1;
  156.             if (*fnamestart == '.')
  157.                 *fnamestart = '';
  158.             return matchname;
  159.         }
  160.     }
  161.     closedir(dir);     /* have read at least one dir entry; nothing left */
  162.     dir = (DIR *)NULL;
  163.     firstcall = TRUE;  /* reset for new wildspec */
  164.     if (have_dirname)
  165.         free(dirname);
  166.     return (char *)NULL;
  167. } /* end function do_wild() */
  168. #endif /* !SFX */
  169. /**********************/
  170. /* Function mapattr() */
  171. /**********************/
  172. int mapattr(__G)
  173.     __GDEF
  174. {
  175.     /* set archive bit (file is not backed up): */
  176.     G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes & 7) | 32;
  177.     return 0;
  178. }
  179. /************************/
  180. /*  Function mapname()  */
  181. /************************/
  182.                              /* return 0 if no error, 1 if caution (filename */
  183. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  184.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  185.     int renamed;             /*  or 10 if out of memory (skip file) */
  186. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  187.     char pathcomp[FILNAMSIZ];      /* path-component buffer */
  188.     char *pp, *cp=(char *)NULL;    /* character pointers */
  189.     char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
  190.     char *last_dot=(char *)NULL;   /* last dot not converted to underscore */
  191.     int dotname = FALSE;           /* path component begins with dot? */
  192.     int error = 0;
  193.     register unsigned workch;      /* hold the character being tested */
  194.     if (G.pInfo->vollabel)
  195.         return IZ_VOL_LABEL;    /* Cannot set disk volume labels in FlexOS */
  196. /*---------------------------------------------------------------------------
  197.     Initialize various pointers and counters and stuff.
  198.   ---------------------------------------------------------------------------*/
  199.     /* can create path as long as not just freshening, or if user told us */
  200.     G.create_dirs = (!uO.fflag || renamed);
  201.     created_dir = FALSE;        /* not yet */
  202.     renamed_fullpath = FALSE;
  203.     if (renamed) {
  204.         cp = G.filename - 1;    /* point to beginning of renamed name... */
  205.         while (*++cp)
  206.             if (*cp == '\')    /* convert backslashes to forward */
  207.                 *cp = '/';
  208.         cp = G.filename;
  209.         /* use temporary rootpath if user gave full pathname */
  210.         if (G.filename[0] == '/') {
  211.             renamed_fullpath = TRUE;
  212.             pathcomp[0] = '/';  /* copy the '/' and terminate */
  213.             pathcomp[1] = '';
  214.             ++cp;
  215.         } else if (isalpha(G.filename[0]) && G.filename[1] == ':') {
  216.             renamed_fullpath = TRUE;
  217.             pp = pathcomp;
  218.             *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
  219.             *pp++ = *cp++;
  220.             if (*cp == '/')
  221.                 *pp++ = *cp++;  /* otherwise add "./"? */
  222.             *pp = '';
  223.         }
  224.     }
  225.     /* pathcomp is ignored unless renamed_fullpath is TRUE: */
  226.     if ((error = checkdir(__G__ pathcomp, INIT)) != 0) /* initialize path buf */
  227.         return error;           /* ...unless no mem or vol label on hard disk */
  228.     *pathcomp = '';           /* initialize translation buffer */
  229.     pp = pathcomp;              /* point to translation buffer */
  230.     if (!renamed) {             /* cp already set if renamed */
  231.         if (uO.jflag)           /* junking directories */
  232.             cp = (char *)strrchr(G.filename, '/');
  233.         if (cp == (char *)NULL) /* no '/' or not junking dirs */
  234.             cp = G.filename;    /* point to internal zipfile-member pathname */
  235.         else
  236.             ++cp;               /* point to start of last component of path */
  237.     }
  238. /*---------------------------------------------------------------------------
  239.     Begin main loop through characters in filename.
  240.   ---------------------------------------------------------------------------*/
  241.     while ((workch = (uch)*cp++) != 0) {
  242.         switch (workch) {
  243.             case '/':             /* can assume -j flag not given */
  244.                 *pp = '';
  245.                 map2fat(pathcomp, last_dot);   /* 8.3 truncation (in place) */
  246.                 last_dot = (char *)NULL;
  247.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  248.                     return error;
  249.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  250.                 lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  251.                 break;
  252.             /* drive names are not stored in zipfile, so no colons allowed;
  253.              *  no brackets or most other punctuation either (all of which
  254.              *  can appear in Unix-created archives; backslash is particularly
  255.              *  bad unless all necessary directories exist) */
  256.             case '[':          /* these punctuation characters forbidden */
  257.             case ']':          /*  only on plain FAT file systems */
  258.             case '+':
  259.             case ',':
  260.             case '=':
  261.             case ':':           /* special shell characters of command.com */
  262.             case '\':          /*  (device and directory limiters, wildcard */
  263.             case '"':           /*  characters, stdin/stdout redirection and */
  264.             case '<':           /*  pipe indicators and the quote sign) are */
  265.             case '>':           /*  never allowed in filenames on (V)FAT */
  266.             case '|':
  267.             case '*':
  268.             case '?':
  269.                 *pp++ = '_';
  270.                 break;
  271.             case '.':
  272.                 if (pp == pathcomp) {     /* nothing appended yet... */
  273.                     if (*cp == '/') {     /* don't bother appending a "./" */
  274.                         ++cp;             /*  component to the path:  skip */
  275.                         break;            /*  to next char after the '/' */
  276.                     } else if (*cp == '.' && cp[1] == '/') {   /* "../" */
  277.                         *pp++ = '.';      /* add first dot, unchanged... */
  278.                         ++cp;             /* skip second dot, since it will */
  279.                     } else {              /*  be "added" at end of if-block */
  280.                         *pp++ = '_';      /* FAT doesn't allow null filename */
  281.                         dotname = TRUE;   /*  bodies, so map .exrc -> _.exrc */
  282.                     }                     /*  (extra '_' now, "dot" below) */
  283.                 } else if (dotname) {     /* found a second dot, but still */
  284.                     dotname = FALSE;      /*  have extra leading underscore: */
  285.                     *pp = '';           /*  remove it by shifting chars */
  286.                     pp = pathcomp + 1;    /*  left one space (e.g., .p1.p2: */
  287.                     while (pp[1]) {       /*  __p1 -> _p1_p2 -> _p1.p2 when */
  288.                         *pp = pp[1];      /*  finished) [opt.:  since first */
  289.                         ++pp;             /*  two chars are same, can start */
  290.                     }                     /*  shifting at second position] */
  291.                 }
  292.                 last_dot = pp;    /* point at last dot so far... */
  293.                 *pp++ = '_';      /* convert dot to underscore for now */
  294.                 break;
  295.             case ';':             /* start of VMS version? */
  296.                 lastsemi = pp;
  297.                 break;
  298.             case ' ':                      /* change spaces to underscores */
  299.                 if (uO.sflag)              /*  only if requested */
  300.                     *pp++ = '_';
  301.                 else
  302.                     *pp++ = (char)workch;
  303.                 break;
  304.             default:
  305.                 /* allow ASCII 255 and European characters in filenames: */
  306.                 if (isprint(workch) || workch >= 127)
  307.                     *pp++ = (char)workch;
  308.         } /* end switch */
  309.     } /* end while loop */
  310.     *pp = '';                   /* done with pathcomp:  terminate it */
  311.     /* if not saving them, remove VMS version numbers (appended ";###") */
  312.     if (!uO.V_flag && lastsemi) {
  313.         pp = lastsemi;            /* semi-colon was omitted:  expect all #'s */
  314.         while (isdigit((uch)(*pp)))
  315.             ++pp;
  316.         if (*pp == '')          /* only digits between ';' and end:  nuke */
  317.             *lastsemi = '';
  318.     }
  319.     map2fat(pathcomp, last_dot);  /* 8.3 truncation (in place) */
  320. /*---------------------------------------------------------------------------
  321.     Report if directory was created (and no file to create:  filename ended
  322.     in '/'), check name to be sure it exists, and combine path and name be-
  323.     fore exiting.
  324.   ---------------------------------------------------------------------------*/
  325.     if (G.filename[strlen(G.filename) - 1] == '/') {
  326.         checkdir(__G__ G.filename, GETPATH);
  327.         if (created_dir) {
  328.             if (QCOND2) {
  329.                 Info(slide, 0, ((char *)slide, LoadFarString(Creating),
  330.                   FnFilter1(G.filename)));
  331.             }
  332.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  333.         }
  334.         return 2;   /* dir existed already; don't look for data to extract */
  335.     }
  336.     if (*pathcomp == '') {
  337.         Info(slide, 1, ((char *)slide, LoadFarString(ConversionFailed),
  338.           FnFilter1(G.filename)));
  339.         return 3;
  340.     }
  341.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  342.     checkdir(__G__ G.filename, GETPATH);
  343.     return error;
  344. } /* end function mapname() */
  345. /**********************/
  346. /* Function map2fat() */
  347. /**********************/
  348. static void map2fat(pathcomp, last_dot)
  349.     char *pathcomp, *last_dot;
  350. {
  351.     char *pEnd = pathcomp + strlen(pathcomp);
  352. /*---------------------------------------------------------------------------
  353.     Case 1:  filename has no dot, so figure out if we should add one.  Note
  354.     that the algorithm does not try to get too fancy:  if there are no dots
  355.     already, the name either gets truncated at 8 characters or the last un-
  356.     derscore is converted to a dot (only if more characters are saved that
  357.     way).  In no case is a dot inserted between existing characters.
  358.               GRR:  have problem if filename is volume label??
  359.   ---------------------------------------------------------------------------*/
  360.     /* pEnd = pathcomp + strlen(pathcomp); */
  361.     if (last_dot == (char *)NULL) {   /* no dots:  check for underscores... */
  362.         char *plu = strrchr(pathcomp, '_');   /* pointer to last underscore */
  363.         if (plu == (char *)NULL) {  /* no dots, no underscores:  truncate at */
  364.             if (pEnd > pathcomp+8)  /* 8 chars (could insert '.' and keep 11) */
  365.                 *(pEnd = pathcomp+8) = '';
  366.         } else if (MIN(plu - pathcomp, 8) + MIN(pEnd - plu - 1, 3) > 8) {
  367.             last_dot = plu;       /* be lazy:  drop through to next if-block */
  368.         } else if ((pEnd - pathcomp) > 8)    /* more fits into just basename */
  369.             pathcomp[8] = '';    /* than if convert last underscore to dot */
  370.         /* else whole thing fits into 8 chars or less:  no change */
  371.     }
  372. /*---------------------------------------------------------------------------
  373.     Case 2:  filename has dot in it, so truncate first half at 8 chars (shift
  374.     extension if necessary) and second half at three.
  375.   ---------------------------------------------------------------------------*/
  376.     if (last_dot != (char *)NULL) {   /* one dot (or two, in the case of */
  377.         *last_dot = '.';              /*  "..") is OK:  put it back in */
  378.         if ((last_dot - pathcomp) > 8) {
  379.             char *p=last_dot, *q=pathcomp+8;
  380.             int i;
  381.             for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
  382.                 *q++ = *p++;                   /*  shift extension left and */
  383.             *q = '';                         /*  truncate/terminate it */
  384.         } else if ((pEnd - last_dot) > 4)
  385.             last_dot[4] = '';                /* too many chars in extension */
  386.         /* else filename is fine as is:  no change */
  387.     }
  388. } /* end function map2fat() */
  389. /***********************/
  390. /* Function checkdir() */
  391. /***********************/
  392. int checkdir(__G__ pathcomp, flag)
  393.     __GDEF
  394.     char *pathcomp;
  395.     int flag;
  396. /*
  397.  * returns:  1 - (on APPEND_NAME) truncated filename
  398.  *           2 - path doesn't exist, not allowed to create
  399.  *           3 - path doesn't exist, tried to create and failed; or
  400.  *               path exists and is not a directory, but is supposed to be
  401.  *           4 - path is too long
  402.  *          10 - can't allocate memory for filename buffers
  403.  */
  404. {
  405.     static int rootlen = 0;   /* length of rootpath */
  406.     static char *rootpath;    /* user's "extract-to" directory */
  407.     static char *buildpath;   /* full path (so far) to extracted file */
  408.     static char *end;         /* pointer to end of buildpath ('') */
  409. #   define FN_MASK   7
  410. #   define FUNCTION  (flag & FN_MASK)
  411. /*---------------------------------------------------------------------------
  412.     APPEND_DIR:  append the path component to the path being built and check
  413.     for its existence.  If doesn't exist and we are creating directories, do
  414.     so for this one; else signal success or error as appropriate.
  415.   ---------------------------------------------------------------------------*/
  416.     if (FUNCTION == APPEND_DIR) {
  417.         int too_long = FALSE;
  418.         Trace((stderr, "appending dir segment [%s]n", pathcomp));
  419.         while ((*end = *pathcomp++) != '')
  420.             ++end;
  421.         /* GRR:  could do better check, see if overrunning buffer as we go:
  422.          * check end-buildpath after each append, set warning variable if
  423.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  424.          * appending.  Clear variable when begin new path. */
  425.         if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '' */
  426.             too_long = TRUE;                /* check if extracting directory? */
  427.         if (stat(buildpath, &G.statbuf))    /* path doesn't exist */
  428.         {
  429.             if (!G.create_dirs) { /* told not to create (freshening) */
  430.                 free(buildpath);
  431.                 return 2;         /* path doesn't exist:  nothing to do */
  432.             }
  433.             if (too_long) {
  434.                 Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
  435.                   FnFilter1(buildpath)));
  436.                 free(buildpath);
  437.                 return 4;         /* no room for filenames:  fatal */
  438.             }
  439.             if (mkdir(buildpath, 0777) == -1) {   /* create the directory */
  440.                 Info(slide, 1, ((char *)slide, LoadFarString(CantCreateDir),
  441.                   FnFilter2(buildpath), FnFilter1(G.filename)));
  442.                 free(buildpath);
  443.                 return 3;      /* path didn't exist, tried to create, failed */
  444.             }
  445.             created_dir = TRUE;
  446.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  447.             Info(slide, 1, ((char *)slide, LoadFarString(DirIsntDirectory),
  448.               FnFilter2(buildpath), FnFilter1(G.filename)));
  449.             free(buildpath);
  450.             return 3;          /* path existed but wasn't dir */
  451.         }
  452.         if (too_long) {
  453.             Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
  454.               FnFilter1(buildpath)));
  455.             free(buildpath);
  456.             return 4;         /* no room for filenames:  fatal */
  457.         }
  458.         *end++ = '/';
  459.         *end = '';
  460.         Trace((stderr, "buildpath now = [%s]n", FnFilter1(buildpath)));
  461.         return 0;
  462.     } /* end if (FUNCTION == APPEND_DIR) */
  463. /*---------------------------------------------------------------------------
  464.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  465.     buildpath.
  466.   ---------------------------------------------------------------------------*/
  467.     if (FUNCTION == GETPATH) {
  468.         strcpy(pathcomp, buildpath);
  469.         Trace((stderr, "getting and freeing path [%s]n",
  470.           FnFilter1(pathcomp)));
  471.         free(buildpath);
  472.         buildpath = end = (char *)NULL;
  473.         return 0;
  474.     }
  475. /*---------------------------------------------------------------------------
  476.     APPEND_NAME:  assume the path component is the filename; append it and
  477.     return without checking for existence.
  478.   ---------------------------------------------------------------------------*/
  479.     if (FUNCTION == APPEND_NAME) {
  480.         Trace((stderr, "appending filename [%s]n", FnFilter1(pathcomp)));
  481.         while ((*end = *pathcomp++) != '') {
  482.             ++end;
  483.             if ((end-buildpath) >= FILNAMSIZ) {
  484.                 *--end = '';
  485.                 Info(slide, 1, ((char *)slide, LoadFarString(PathTooLongTrunc),
  486.                   FnFilter1(G.filename), FnFilter2(buildpath)));
  487.                 return 1;   /* filename truncated */
  488.             }
  489.         }
  490.         Trace((stderr, "buildpath now = [%s]n", FnFilter1(buildpath)));
  491.         return 0;  /* could check for existence here, prompt for new name... */
  492.     }
  493. /*---------------------------------------------------------------------------
  494.     INIT:  allocate and initialize buffer space for the file currently being
  495.     extracted.  If file was renamed with an absolute path, don't prepend the
  496.     extract-to path.
  497.   ---------------------------------------------------------------------------*/
  498.     if (FUNCTION == INIT) {
  499.         Trace((stderr, "initializing buildpath to "));
  500.         /* allocate space for full filename, root path, and maybe "./" */
  501.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+3)) ==
  502.             (char *)NULL)
  503.             return 10;
  504.         if (renamed_fullpath) {   /* pathcomp = valid data */
  505.             end = buildpath;
  506.             while ((*end = *pathcomp++) != '')
  507.                 ++end;
  508.         } else if (rootlen > 0) {
  509.             strcpy(buildpath, rootpath);
  510.             end = buildpath + rootlen;
  511.         } else {
  512.             *buildpath = '';
  513.             end = buildpath;
  514.         }
  515.         Trace((stderr, "[%s]n", FnFilter1(buildpath)));
  516.         return 0;
  517.     }
  518. /*---------------------------------------------------------------------------
  519.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  520.     sary; else assume it's a zipfile member and return.  This path segment
  521.     gets used in extracting all members from every zipfile specified on the
  522.     command line.  Note that under FlexOS, if a candidate extract-to
  523.     directory specification includes a drive letter (leading "x:"), it is
  524.     treated just as if it had a trailing '/'--that is, one directory level
  525.     will be created if the path doesn't exist, unless this is otherwise pro-
  526.     hibited (e.g., freshening).
  527.   ---------------------------------------------------------------------------*/
  528. #if (!defined(SFX) || defined(SFX_EXDIR))
  529.     if (FUNCTION == ROOT) {
  530.         Trace((stderr, "initializing root path to [%s]n",
  531.           FnFilter1(pathcomp)));
  532.         if (pathcomp == (char *)NULL) {
  533.             rootlen = 0;
  534.             return 0;
  535.         }
  536.         if ((rootlen = strlen(pathcomp)) > 0) {
  537.             int had_trailing_pathsep=FALSE, xtra=2;
  538.             if (pathcomp[rootlen-1] == '/' || pathcomp[rootlen-1] == '\') {
  539.                 pathcomp[--rootlen] = '';
  540.                 had_trailing_pathsep = TRUE;
  541.             }
  542.             if (pathcomp[rootlen-1] == ':') {
  543.                 if (!had_trailing_pathsep)   /* i.e., original wasn't "xxx:/" */
  544.                     xtra = 3;      /* room for '.' + '/' + 0 at end of "xxx:" */
  545.             } else if (rootlen > 0) {     /* need not check "xxx:." and "xxx:/" */
  546.                 if (stat(pathcomp,&G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
  547.                 {
  548.                     /* path does not exist */
  549.                     if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  550.                         rootlen = 0;
  551.                         return 2;   /* treat as stored file */
  552.                     }
  553. /* GRR:  scan for wildcard characters?  OS-dependent...  if find any, return 2:
  554.  * treat as stored file(s) */
  555.                     /* create directory (could add loop here to scan pathcomp
  556.                      * and create more than one level, but really necessary?) */
  557.                     if (mkdir(pathcomp, 0777) == -1) {
  558.                         Info(slide, 1, ((char *)slide,
  559.                           LoadFarString(CantCreateExtractDir),
  560.                           FnFilter1(pathcomp)));
  561.                         rootlen = 0;   /* path didn't exist, tried to create, */
  562.                         return 3;  /* failed:  file exists, or need 2+ levels */
  563.                     }
  564.                 }
  565.             }
  566.             if ((rootpath = (char *)malloc(rootlen+xtra)) == (char *)NULL) {
  567.                 rootlen = 0;
  568.                 return 10;
  569.             }
  570.             strcpy(rootpath, pathcomp);
  571.             if (xtra == 3)                  /* had just "x:", make "x:." */
  572.                 rootpath[rootlen++] = '.';
  573.             rootpath[rootlen++] = '/';
  574.             rootpath[rootlen] = '';
  575.             Trace((stderr, "rootpath now = [%s]n", FnFilter1(rootpath)));
  576.         }
  577.         return 0;
  578.     }
  579. #endif /* !SFX || SFX_EXDIR */
  580. /*---------------------------------------------------------------------------
  581.     END:  free rootpath, immediately prior to program exit.
  582.   ---------------------------------------------------------------------------*/
  583.     if (FUNCTION == END) {
  584.         Trace((stderr, "freeing rootpathn"));
  585.         if (rootlen > 0) {
  586.             free(rootpath);
  587.             rootlen = 0;
  588.         }
  589.         return 0;
  590.     }
  591.     return 99;  /* should never reach */
  592. }
  593. /****************************/
  594. /* Function close_outfile() */
  595. /****************************/
  596. void close_outfile(__G)
  597.     __GDEF
  598.  /*
  599.   * FlexOS VERSION
  600.   *
  601.   * Set the output file date/time stamp according to information from the
  602.   * zipfile directory record for this member, then close the file and set
  603.   * its permissions (archive, hidden, read-only, system).  Aside from closing
  604.   * the file, this routine is optional (but most compilers support it).
  605.   */
  606. {
  607.     DISKFILE    df;
  608.     LONG        fnum;
  609.     struct {                /* date and time words */
  610.         union {             /* DOS file modification time word */
  611.             ush ztime;
  612.             struct {
  613.                 unsigned zt_se : 5;
  614.                 unsigned zt_mi : 6;
  615.                 unsigned zt_hr : 5;
  616.             } _tf;
  617.         } _t;
  618.         union {             /* DOS file modification date word */
  619.             ush zdate;
  620.             struct {
  621.                 unsigned zd_dy : 5;
  622.                 unsigned zd_mo : 4;
  623.                 unsigned zd_yr : 7;
  624.             } _df;
  625.         } _d;
  626.     } zt;
  627. #ifdef USE_EF_UT_TIME
  628.     iztimes z_utime;
  629.     struct tm *t;
  630. #endif /* ?USE_EF_UT_TIME */
  631.     fclose(G.outfile);
  632.     if ((fnum = s_open(A_SET, G.filename)) < 0) {
  633.         Info(slide, 0x201, ((char *)slide,
  634.           "warning:  cannot open %s to set the timen", G.filename));
  635.         return;
  636.     }
  637.     if (s_get(T_FILE, fnum, &df, DSKFSIZE) < 0) {
  638.         s_close(0, fnum);
  639.         Info(slide, 0x201, ((char *)slide,
  640.           "warning:  cannot get info on %sn", G.filename));
  641.         return;
  642.     }
  643. /*---------------------------------------------------------------------------
  644.     Copy and/or convert time and date variables, if necessary; then fill in
  645.     the file time/date.
  646.   ---------------------------------------------------------------------------*/
  647. #ifdef USE_EF_UT_TIME
  648.     if (G.extra_field &&
  649. #ifdef IZ_CHECK_TZ
  650.         G.tz_is_valid &&
  651. #endif
  652.         (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  653.          G.lrec.last_mod_dos_datetime, &z_utime, NULL) & EB_UT_FL_MTIME))
  654.     {
  655.         TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ldn",
  656.           z_utime.mtime));
  657.         t = localtime(&(z_utime.mtime));
  658.     } else
  659.         t = (struct tm *)NULL;
  660.     if (t != (struct tm *)NULL) {
  661.         if (t->tm_year < 80) {
  662.             df.df_modyear = 1980;
  663.             df.df_modmonth = 1;
  664.             df.df_modday = 1;
  665.             df.df_modhr = 0;
  666.             df.df_modmin = 0;
  667.             df.df_modsec = 0;
  668.         } else {
  669.             df.df_modyear = t->tm_year + 1900;
  670.             df.df_modmonth = t->tm_mon + 1;
  671.             df.df_modday = t->tm_mday;
  672.             df.df_modhr = t->tm_hour;
  673.             df.df_modmin = t->tm_min;
  674.             df.df_modsec = t->tm_sec;
  675.         }
  676.     } else
  677. #endif /* ?USE_EF_UX_TIME */
  678.     {
  679.         zt._t.ztime = (ush)(G.lrec.last_mod_dos_datetime) & 0xffff;
  680.         zt._d.zdate = (ush)(G.lrec.last_mod_dos_datetime >> 16);
  681.         df.df_modyear = 1980 + zt._d._df.zd_yr;
  682.         df.df_modmonth = zt._d._df.zd_mo;
  683.         df.df_modday = zt._d._df.zd_dy;
  684.         df.df_modhr = zt._t._tf.zt_hr;
  685.         df.df_modmin = zt._t._tf.zt_mi;
  686.         df.df_modsec = zt._t._tf.zt_se << 1;
  687.     }
  688. /*---------------------------------------------------------------------------
  689.     Fill in the file attributes.
  690.   ---------------------------------------------------------------------------*/
  691.     df.df_attr1 = (UBYTE)G.pInfo->file_attr;
  692. /*---------------------------------------------------------------------------
  693.     Now we try to set the attributes & date/time.
  694.   ---------------------------------------------------------------------------*/
  695.     if (s_set(T_FILE, fnum, &df, DSKFSIZE) < 0)
  696.         Info(slide, 0x201, ((char *)slide,
  697.           "warning:  cannot set info for %sn", G.filename));
  698.     s_close(0, fnum);
  699. }
  700. #ifndef SFX
  701. /*************************/
  702. /* Function dateformat() */
  703. /*************************/
  704. int dateformat()
  705. {
  706.     return DF_DMY;   /* default for systems without locale info */
  707. }
  708. /************************/
  709. /*  Function version()  */
  710. /************************/
  711. void version(__G)
  712.     __GDEF
  713. {
  714.     int len;
  715.     len = sprintf((char *)slide, LoadFarString(CompiledWith),
  716.             "MetaWare High C",
  717.             "",
  718.             "FlexOS",
  719.             " (16-bit, big)",
  720. #ifdef __DATE__
  721.       " on ", __DATE__
  722. #else
  723.       "", ""
  724. #endif
  725.     );
  726.     (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  727. }
  728. #endif /* !SFX */
  729. /************************/
  730. /*  Function _wildarg() */
  731. /************************/
  732. /* This prevents the PORTLIB startup code from preforming argument globbing */
  733. _wildarg() {}