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

压缩解压

开发平台:

MultiPlatform

  1. /*---------------------------------------------------------------------------
  2.   atari.c
  3.   Atari-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  4.   Contains:  readdir()
  5.              do_wild()           <-- generic enough to put in fileio.c?
  6.              mapattr()
  7.              mapname()
  8.              checkdir()
  9.              mkdir()
  10.              close_outfile()
  11.              stamp_file()        [optional feature]
  12.              version()
  13.   Due to the amazing MiNT library being very, very close to BSD unix's
  14.   library, I'm using the unix.c as a base for this.  Note:  If you're not
  15.   going to compile this with the MiNT libraries (for GNU C, Turbo C, Pure C,
  16.   Lattice C, or Heat & Serve C), you're going to be in for some nasty work.
  17.   Most of the modifications in this file were made by Chris Herborth
  18.   (cherborth@semprini.waterloo-rdp.on.ca) and /should/ be marked with [cjh].
  19.   ---------------------------------------------------------------------------*/
  20. #define UNZIP_INTERNAL
  21. #include "unzip.h"
  22. #include <dirent.h>            /* MiNTlibs has dirent [cjh] */
  23. static int created_dir;        /* used in mapname(), checkdir() */
  24. static int renamed_fullpath;   /* ditto */
  25. #ifndef SFX
  26. /**********************/
  27. /* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  28. /**********************/
  29. char *do_wild(__G__ wildspec)
  30.     __GDEF
  31.     char *wildspec;         /* only used first time on a given dir */
  32. {
  33.     static DIR *dir = (DIR *)NULL;
  34.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  35.     static int firstcall=TRUE, have_dirname, dirnamelen;
  36.     struct dirent *file;
  37.     /* Even when we're just returning wildspec, we *always* do so in
  38.      * matchname[]--calling routine is allowed to append four characters
  39.      * to the returned string, and wildspec may be a pointer to argv[].
  40.      */
  41.     if (firstcall) {        /* first call:  must initialize everything */
  42.         firstcall = FALSE;
  43.         if (!iswild(wildspec)) {
  44.             strcpy(matchname, wildspec);
  45.             have_dirname = FALSE;
  46.             dir = NULL;
  47.             return matchname;
  48.         }
  49.         /* break the wildspec into a directory part and a wildcard filename */
  50.         if ((wildname = strrchr(wildspec, '/')) == (char *)NULL) {
  51.             dirname = ".";
  52.             dirnamelen = 1;
  53.             have_dirname = FALSE;
  54.             wildname = wildspec;
  55.         } else {
  56.             ++wildname;     /* point at character after '/' */
  57.             dirnamelen = wildname - wildspec;
  58.             if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  59.                 Info(slide, 0x201, ((char *)slide,
  60.                   "warning:  cannot allocate wildcard buffersn"));
  61.                 strcpy(matchname, wildspec);
  62.                 return matchname;   /* but maybe filespec was not a wildcard */
  63.             }
  64.             strncpy(dirname, wildspec, dirnamelen);
  65.             dirname[dirnamelen] = '';   /* terminate for strcpy below */
  66.             have_dirname = TRUE;
  67.         }
  68.         if ((dir = opendir(dirname)) != (DIR *)NULL) {
  69.             while ((file = readdir(dir)) != (struct dirent *)NULL) {
  70.                 Trace((stderr, "do_wild:  readdir returns %sn", file->d_name));
  71.                 if (file->d_name[0] == '.' && wildname[0] != '.')
  72.                     continue;  /* Unix:  '*' and '?' do not match leading dot */
  73.                     /* Need something here for TOS filesystem? [cjh] */
  74.                 if (match(file->d_name, wildname, 0) &&  /* 0 == case sens. */
  75.                     /* skip "." and ".." directory entries */
  76.                     strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {
  77.                     Trace((stderr, "do_wild:  match() succeedsn"));
  78.                     if (have_dirname) {
  79.                         strcpy(matchname, dirname);
  80.                         strcpy(matchname+dirnamelen, file->d_name);
  81.                     } else
  82.                         strcpy(matchname, file->d_name);
  83.                     return matchname;
  84.                 }
  85.             }
  86.             /* if we get to here directory is exhausted, so close it */
  87.             closedir(dir);
  88.             dir = (DIR *)NULL;
  89.         }
  90.         /* return the raw wildspec in case that works (e.g., directory not
  91.          * searchable, but filespec was not wild and file is readable) */
  92.         strcpy(matchname, wildspec);
  93.         return matchname;
  94.     }
  95.     /* last time through, might have failed opendir but returned raw wildspec */
  96.     if (dir == (DIR *)NULL) {
  97.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  98.         if (have_dirname)
  99.             free(dirname);
  100.         return (char *)NULL;
  101.     }
  102.     /* If we've gotten this far, we've read and matched at least one entry
  103.      * successfully (in a previous call), so dirname has been copied into
  104.      * matchname already.
  105.      */
  106.     while ((file = readdir(dir)) != (struct dirent *)NULL) {
  107.         /* May need special TOS handling here. [cjh] */
  108.         Trace((stderr, "do_wild:  readdir returns %sn", file->d_name));
  109.         if (file->d_name[0] == '.' && wildname[0] != '.')
  110.             continue;   /* Unix:  '*' and '?' do not match leading dot */
  111.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  112.             Trace((stderr, "do_wild:  match() succeedsn"));
  113.             if (have_dirname) {
  114.                 /* strcpy(matchname, dirname); */
  115.                 strcpy(matchname+dirnamelen, file->d_name);
  116.             } else
  117.                 strcpy(matchname, file->d_name);
  118.             return matchname;
  119.         }
  120.     }
  121.     closedir(dir);     /* have read at least one dir entry; nothing left */
  122.     dir = (DIR *)NULL;
  123.     firstcall = TRUE;  /* reset for new wildspec */
  124.     if (have_dirname)
  125.         free(dirname);
  126.     return (char *)NULL;
  127. } /* end function do_wild() */
  128. #endif /* !SFX */
  129. /**********************/
  130. /* Function mapattr() */
  131. /**********************/
  132. int mapattr(__G)
  133.     __GDEF
  134. {
  135.     ulg tmp = G.crec.external_file_attributes;
  136.     switch (G.pInfo->hostnum) {
  137.         case AMIGA_:
  138.             tmp = (unsigned)(tmp>>17 & 7);   /* Amiga RWE bits */
  139.             G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
  140.             break;
  141.         case UNIX_:
  142.         case VMS_:
  143.         case ACORN_:
  144.         case ATARI_:
  145.         case BEOS_:
  146.         case QDOS_:
  147.         case TANDEM_:
  148.             G.pInfo->file_attr = (unsigned)(tmp >> 16);
  149.             if (G.pInfo->file_attr != 0 || !G.extra_field) {
  150.                 return 0;
  151.             } else {
  152.                 /* Some (non-Info-ZIP) implementations of Zip for Unix and
  153.                    VMS (and probably others ??) leave 0 in the upper 16-bit
  154.                    part of the external_file_attributes field. Instead, they
  155.                    store file permission attributes in some extra field.
  156.                    As a work-around, we search for the presence of one of
  157.                    these extra fields and fall back to the MSDOS compatible
  158.                    part of external_file_attributes if one of the known
  159.                    e.f. types has been detected.
  160.                    Later, we might implement extraction of the permission
  161.                    bits from the VMS extra field. But for now, the work-around
  162.                    should be sufficient to provide "readable" extracted files.
  163.                    (For ASI Unix e.f., an experimental remap of the e.f.
  164.                    mode value IS already provided!)
  165.                  */
  166.                 ush ebID;
  167.                 unsigned ebLen;
  168.                 uch *ef = G.extra_field;
  169.                 unsigned ef_len = G.crec.extra_field_length;
  170.                 int r = FALSE;
  171.                 while (!r && ef_len >= EB_HEADSIZE) {
  172.                     ebID = makeword(ef);
  173.                     ebLen = (unsigned)makeword(ef+EB_LEN);
  174.                     if (ebLen > (ef_len - EB_HEADSIZE))
  175.                         /* discoverd some e.f. inconsistency! */
  176.                         break;
  177.                     switch (ebID) {
  178.                       case EF_ASIUNIX:
  179.                         if (ebLen >= (EB_ASI_MODE+2)) {
  180.                             G.pInfo->file_attr =
  181.                               (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
  182.                             /* force stop of loop: */
  183.                             ef_len = (ebLen + EB_HEADSIZE);
  184.                             break;
  185.                         }
  186.                         /* else: fall through! */
  187.                       case EF_PKVMS:
  188.                         /* "found nondecypherable e.f. with perm. attr" */
  189.                         r = TRUE;
  190.                       default:
  191.                         break;
  192.                     }
  193.                     ef_len -= (ebLen + EB_HEADSIZE);
  194.                     ef += (ebLen + EB_HEADSIZE);
  195.                 }
  196.                 if (!r)
  197.                     return 0;
  198.             }
  199.             /* fall through! */
  200.         /* all remaining cases:  expand MSDOS read-only bit into write perms */
  201.         case FS_FAT_:
  202.         case FS_HPFS_:
  203.         case FS_NTFS_:
  204.         case MAC_:
  205.         case TOPS20_:
  206.         default:
  207.             tmp = !(tmp & 1) << 1;   /* read-only bit --> write perms bits */
  208.             G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
  209.             break;
  210.     } /* end switch (host-OS-created-by) */
  211.     /* for originating systems with no concept of "group," "other," "system": */
  212.     umask( (int)(tmp=umask(0)) );    /* apply mask to expanded r/w(/x) perms */
  213.     G.pInfo->file_attr &= ~tmp;
  214.     return 0;
  215. } /* end function mapattr() */
  216. /************************/
  217. /*  Function mapname()  */
  218. /************************/
  219.                              /* return 0 if no error, 1 if caution (filename */
  220. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  221.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  222.     int renamed;             /*  or 10 if out of memory (skip file) */
  223. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  224.     char pathcomp[FILNAMSIZ];      /* path-component buffer */
  225.     char *pp, *cp=(char *)NULL;    /* character pointers */
  226.     char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
  227.     int quote = FALSE;             /* flags */
  228.     int error = 0;
  229.     register unsigned workch;      /* hold the character being tested */
  230. /*---------------------------------------------------------------------------
  231.     Initialize various pointers and counters and stuff.
  232.   ---------------------------------------------------------------------------*/
  233.     if (G.pInfo->vollabel)
  234.         return IZ_VOL_LABEL;    /* can't set disk volume labels on Atari */
  235.     /* can create path as long as not just freshening, or if user told us */
  236.     G.create_dirs = (!uO.fflag || renamed);
  237.     created_dir = FALSE;        /* not yet */
  238.     /* user gave full pathname:  don't prepend rootpath */
  239.     renamed_fullpath = (renamed && (*G.filename == '/'));
  240.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  241.         return 10;              /* initialize path buffer, unless no memory */
  242.     *pathcomp = '';           /* initialize translation buffer */
  243.     pp = pathcomp;              /* point to translation buffer */
  244.     if (uO.jflag)               /* junking directories */
  245.         cp = (char *)strrchr(G.filename, '/');
  246.     if (cp == (char *)NULL)     /* no '/' or not junking dirs */
  247.         cp = G.filename;        /* point to internal zipfile-member pathname */
  248.     else
  249.         ++cp;                   /* point to start of last component of path */
  250. /*---------------------------------------------------------------------------
  251.     Begin main loop through characters in filename.
  252.   ---------------------------------------------------------------------------*/
  253.     while ((workch = (uch)*cp++) != 0) {
  254.         if (quote) {                 /* if character quoted, */
  255.             *pp++ = (char)workch;    /*  include it literally */
  256.             quote = FALSE;
  257.         } else
  258.             switch (workch) {
  259.             case '/':             /* can assume -j flag not given */
  260.                 *pp = '';
  261.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  262.                     return error;
  263.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  264.                 lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  265.                 break;
  266.             case ';':             /* VMS version (or DEC-20 attrib?) */
  267.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  268.                 *pp++ = (char)workch;  /*  later, if requested */
  269.                 break;
  270.             case '26':          /* control-V quote for special chars */
  271.                 quote = TRUE;     /* set flag for next character */
  272.                 break;
  273. #ifdef MTS
  274.             case ' ':             /* change spaces to underscore under */
  275.                 *pp++ = '_';      /*  MTS; leave as spaces under Unix */
  276.                 break;
  277. #endif
  278.             default:
  279.                 /* allow European characters in filenames: */
  280.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  281.                     *pp++ = (char)workch;
  282.             } /* end switch */
  283.     } /* end while loop */
  284.     *pp = '';                   /* done with pathcomp:  terminate it */
  285.     /* if not saving them, remove VMS version numbers (appended ";###") */
  286.     if (!uO.V_flag && lastsemi) {
  287.         pp = lastsemi + 1;
  288.         while (isdigit((uch)(*pp)))
  289.             ++pp;
  290.         if (*pp == '')          /* only digits between ';' and end:  nuke */
  291.             *lastsemi = '';
  292.     }
  293. /*---------------------------------------------------------------------------
  294.     Report if directory was created (and no file to create:  filename ended
  295.     in '/'), check name to be sure it exists, and combine path and name be-
  296.     fore exiting.
  297.   ---------------------------------------------------------------------------*/
  298.     if (G.filename[strlen(G.filename) - 1] == '/') {
  299.         checkdir(__G__ G.filename, GETPATH);
  300.         if (created_dir) {
  301.             if (QCOND2) {
  302.                 Info(slide, 0, ((char *)slide, "   creating: %sn",
  303.                   G.filename));
  304.             }
  305.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  306.         }
  307.         return 2;   /* dir existed already; don't look for data to extract */
  308.     }
  309.     if (*pathcomp == '') {
  310.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failedn",
  311.           G.filename));
  312.         return 3;
  313.     }
  314.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  315.     checkdir(__G__ G.filename, GETPATH);
  316.     return error;
  317. } /* end function mapname() */
  318. #if 0  /*========== NOTES ==========*/
  319.   extract-to dir:      a:path/
  320.   buildpath:           path1/path2/ ...   (NULL-terminated)
  321.   pathcomp:                filename
  322.   mapname():
  323.     loop over chars in zipfile member name
  324.       checkdir(path component, COMPONENT | CREATEDIR) --> map as required?
  325.         (d:/tmp/unzip/)                    (disk:[tmp.unzip.)
  326.         (d:/tmp/unzip/jj/)                 (disk:[tmp.unzip.jj.)
  327.         (d:/tmp/unzip/jj/temp/)            (disk:[tmp.unzip.jj.temp.)
  328.     finally add filename itself and check for existence? (could use with rename)
  329.         (d:/tmp/unzip/jj/temp/msg.outdir)  (disk:[tmp.unzip.jj.temp]msg.outdir)
  330.     checkdir(name, GETPATH)     -->  copy path to name and free space
  331. #endif /* 0 */
  332. /***********************/
  333. /* Function checkdir() */
  334. /***********************/
  335. int checkdir(__G__ pathcomp, flag)
  336.     __GDEF
  337.     char *pathcomp;
  338.     int flag;
  339. /*
  340.  * returns:  1 - (on APPEND_NAME) truncated filename
  341.  *           2 - path doesn't exist, not allowed to create
  342.  *           3 - path doesn't exist, tried to create and failed; or
  343.  *               path exists and is not a directory, but is supposed to be
  344.  *           4 - path is too long
  345.  *          10 - can't allocate memory for filename buffers
  346.  */
  347. {
  348.     static int rootlen = 0;   /* length of rootpath */
  349.     static char *rootpath;    /* user's "extract-to" directory */
  350.     static char *buildpath;   /* full path (so far) to extracted file */
  351.     static char *end;         /* pointer to end of buildpath ('') */
  352. #   define FN_MASK   7
  353. #   define FUNCTION  (flag & FN_MASK)
  354. /*---------------------------------------------------------------------------
  355.     APPEND_DIR:  append the path component to the path being built and check
  356.     for its existence.  If doesn't exist and we are creating directories, do
  357.     so for this one; else signal success or error as appropriate.
  358.   ---------------------------------------------------------------------------*/
  359.     if (FUNCTION == APPEND_DIR) {
  360.         int too_long = FALSE;
  361. /* SHORT_NAMES required for TOS, but it has to co-exist for minix fs... [cjh] */
  362. #ifdef SHORT_NAMES
  363.         char *old_end = end;
  364. #endif
  365.         Trace((stderr, "appending dir segment [%s]n", pathcomp));
  366.         while ((*end = *pathcomp++) != '')
  367.             ++end;
  368. /* SHORT_NAMES required for TOS, but it has to co-exist for minix fs... [cjh] */
  369. #ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
  370.         if ((end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
  371.             *(end = old_end + FILENAME_MAX) = '';
  372. #endif
  373.         /* GRR:  could do better check, see if overrunning buffer as we go:
  374.          * check end-buildpath after each append, set warning variable if
  375.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  376.          * appending.  Clear variable when begin new path. */
  377.         if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '' */
  378.             too_long = TRUE;                /* check if extracting directory? */
  379.         if (stat(buildpath, &G.statbuf)) {  /* path doesn't exist */
  380.             if (!G.create_dirs) { /* told not to create (freshening) */
  381.                 free(buildpath);
  382.                 return 2;         /* path doesn't exist:  nothing to do */
  383.             }
  384.             if (too_long) {
  385.                 Info(slide, 1, ((char *)slide,
  386.                   "checkdir error:  path too long: %sn", buildpath));
  387.                 free(buildpath);
  388.                 return 4;         /* no room for filenames:  fatal */
  389.             }
  390.             if (mkdir(buildpath, 0777) == -1) {   /* create the directory */
  391.                 Info(slide, 1, ((char *)slide,
  392.                   "checkdir error:  cannot create %sn
  393.                  unable to process %s.n", buildpath, G.filename));
  394.                 free(buildpath);
  395.                 return 3;      /* path didn't exist, tried to create, failed */
  396.             }
  397.             created_dir = TRUE;
  398.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  399.             Info(slide, 1, ((char *)slide,
  400.               "checkdir error:  %s exists but is not directoryn
  401.                  unable to process %s.n", buildpath, G.filename));
  402.             free(buildpath);
  403.             return 3;          /* path existed but wasn't dir */
  404.         }
  405.         if (too_long) {
  406.             Info(slide, 1, ((char *)slide,
  407.               "checkdir error:  path too long: %sn", buildpath));
  408.             free(buildpath);
  409.             return 4;         /* no room for filenames:  fatal */
  410.         }
  411.         *end++ = '/';
  412.         *end = '';
  413.         Trace((stderr, "buildpath now = [%s]n", buildpath));
  414.         return 0;
  415.     } /* end if (FUNCTION == APPEND_DIR) */
  416. /*---------------------------------------------------------------------------
  417.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  418.     buildpath.
  419.   ---------------------------------------------------------------------------*/
  420.     if (FUNCTION == GETPATH) {
  421.         strcpy(pathcomp, buildpath);
  422.         Trace((stderr, "getting and freeing path [%s]n", pathcomp));
  423.         free(buildpath);
  424.         buildpath = end = (char *)NULL;
  425.         return 0;
  426.     }
  427. /*---------------------------------------------------------------------------
  428.     APPEND_NAME:  assume the path component is the filename; append it and
  429.     return without checking for existence.
  430.   ---------------------------------------------------------------------------*/
  431.     if (FUNCTION == APPEND_NAME) {
  432. /* SHORT_NAMES required for TOS, but it has to co-exist for minix fs... [cjh] */
  433. #ifdef SHORT_NAMES
  434.         char *old_end = end;
  435. #endif
  436.         Trace((stderr, "appending filename [%s]n", pathcomp));
  437.         while ((*end = *pathcomp++) != '') {
  438.             ++end;
  439. /* SHORT_NAMES required for TOS, but it has to co-exist for minix fs... [cjh] */
  440. #ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
  441.             if ((end-old_end) > FILENAME_MAX)      /* GRR:  proper constant? */
  442.                 *(end = old_end + FILENAME_MAX) = '';
  443. #endif
  444.             if ((end-buildpath) >= FILNAMSIZ) {
  445.                 *--end = '';
  446.                 Info(slide, 0x201, ((char *)slide,
  447.                   "checkdir warning:  path too long; truncatingn
  448.                    %sn                -> %sn", G.filename, buildpath));
  449.                 return 1;   /* filename truncated */
  450.             }
  451.         }
  452.         Trace((stderr, "buildpath now = [%s]n", buildpath));
  453.         return 0;  /* could check for existence here, prompt for new name... */
  454.     }
  455. /*---------------------------------------------------------------------------
  456.     INIT:  allocate and initialize buffer space for the file currently being
  457.     extracted.  If file was renamed with an absolute path, don't prepend the
  458.     extract-to path.
  459.   ---------------------------------------------------------------------------*/
  460. /* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  461.     if (FUNCTION == INIT) {
  462.         Trace((stderr, "initializing buildpath to "));
  463.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1)) ==
  464.             (char *)NULL)
  465.             return 10;
  466.         if ((rootlen > 0) && !renamed_fullpath) {
  467.             strcpy(buildpath, rootpath);
  468.             end = buildpath + rootlen;
  469.         } else {
  470.             *buildpath = '';
  471.             end = buildpath;
  472.         }
  473.         Trace((stderr, "[%s]n", buildpath));
  474.         return 0;
  475.     }
  476. /*---------------------------------------------------------------------------
  477.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  478.     sary; else assume it's a zipfile member and return.  This path segment
  479.     gets used in extracting all members from every zipfile specified on the
  480.     command line.
  481.   ---------------------------------------------------------------------------*/
  482. #if (!defined(SFX) || defined(SFX_EXDIR))
  483.     if (FUNCTION == ROOT) {
  484.         Trace((stderr, "initializing root path to [%s]n", pathcomp));
  485.         if (pathcomp == (char *)NULL) {
  486.             rootlen = 0;
  487.             return 0;
  488.         }
  489.         if ((rootlen = strlen(pathcomp)) > 0) {
  490.             if (pathcomp[rootlen-1] == '/') {
  491.                 pathcomp[--rootlen] = '';
  492.             }
  493.             if (rootlen > 0 && (stat(pathcomp, &G.statbuf) ||
  494.                 !S_ISDIR(G.statbuf.st_mode)))       /* path does not exist */
  495.             {
  496.                 if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  497.                     rootlen = 0;
  498.                     return 2;   /* skip (or treat as stored file) */
  499.                 }
  500.                 /* create the directory (could add loop here to scan pathcomp
  501.                  * and create more than one level, but why really necessary?) */
  502.                 if (mkdir(pathcomp, 0777) == -1) {
  503.                     Info(slide, 1, ((char *)slide,
  504.                       "checkdir:  cannot create extraction directory: %sn",
  505.                       pathcomp));
  506.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  507.                     return 3;  /* failed:  file exists, or 2+ levels required */
  508.                 }
  509.             }
  510.             if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
  511.                 rootlen = 0;
  512.                 return 10;
  513.             }
  514.             strcpy(rootpath, pathcomp);
  515.             rootpath[rootlen++] = '/';
  516.             rootpath[rootlen] = '';
  517.             Trace((stderr, "rootpath now = [%s]n", rootpath));
  518.         }
  519.         return 0;
  520.     }
  521. #endif /* !SFX || SFX_EXDIR */
  522. /*---------------------------------------------------------------------------
  523.     END:  free rootpath, immediately prior to program exit.
  524.   ---------------------------------------------------------------------------*/
  525.     if (FUNCTION == END) {
  526.         Trace((stderr, "freeing rootpathn"));
  527.         if (rootlen > 0) {
  528.             free(rootpath);
  529.             rootlen = 0;
  530.         }
  531.         return 0;
  532.     }
  533.     return 99;  /* should never reach */
  534. } /* end function checkdir() */
  535. /****************************/
  536. /* Function close_outfile() */
  537. /****************************/
  538. void close_outfile(__G)    /* GRR: change to return PK-style warning level */
  539.     __GDEF
  540. {
  541. #ifdef USE_EF_UT_TIME
  542.     unsigned eb_izux_flg;
  543.     iztimes zt;
  544. #endif
  545.     ztimbuf tp;
  546. /*---------------------------------------------------------------------------
  547.     If symbolic links are supported, allocate a storage area, put the uncom-
  548.     pressed "data" in it, and create the link.  Since we know it's a symbolic
  549.     link to start with, we shouldn't have to worry about overflowing unsigned
  550.     ints with unsigned longs.
  551.   ---------------------------------------------------------------------------*/
  552.     /* symlinks allowed on minix filesystems [cjh]
  553.      * Hopefully this will work properly... We won't bother to try if
  554.      * MiNT isn't present; the symlink should fail if we're on a TOS
  555.      * filesystem.
  556.      * BUG: should we copy the original file to the "symlink" if the
  557.      *      link fails?
  558.      */
  559.     if (G.symlnk) {
  560.         unsigned ucsize = (unsigned)G.lrec.ucsize;
  561.         char *linktarget = (char *)malloc((unsigned)G.lrec.ucsize+1);
  562.         fclose(G.outfile);                      /* close "data" file... */
  563.         G.outfile = fopen(G.filename, FOPR);    /* ...and reopen for reading */
  564.         if (!linktarget || (fread(linktarget, 1, ucsize, G.outfile) !=
  565.                             (int)ucsize)) {
  566.             Info(slide, 0x201, ((char *)slide,
  567.               "warning:  symbolic link (%s) failedn", G.filename));
  568.             if (linktarget)
  569.                 free(linktarget);
  570.             fclose(G.outfile);
  571.             return;
  572.         }
  573.         fclose(G.outfile);                  /* close "data" file for good... */
  574.         unlink(G.filename);                 /* ...and delete it */
  575.         linktarget[ucsize] = '';
  576.         if (QCOND2)
  577.             Info(slide, 0, ((char *)slide, "-> %s ", linktarget));
  578.         if (symlink(linktarget, G.filename))  /* create the real link */
  579.             perror("symlink error");
  580.         free(linktarget);
  581.         return;                             /* can't set time on symlinks */
  582.     }
  583.     fclose(G.outfile);
  584. /*---------------------------------------------------------------------------
  585.     Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
  586.     time:  adjust base year from 1980 to 1970, do usual conversions from
  587.     yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
  588.     light savings time differences.
  589.   ---------------------------------------------------------------------------*/
  590. #ifdef USE_EF_UT_TIME
  591.     eb_izux_flg = (G.extra_field
  592. #ifdef IZ_CHECK_TZ
  593.                    && G.tz_is_valid
  594. #endif
  595.                    ? ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length,
  596.                        0, G.lrec.last_mod_dos_datetime, &zt, NULL)
  597.                    : 0);
  598.     if (eb_izux_flg & EB_UT_FL_MTIME) {
  599.         tp.modtime = zt.mtime;
  600.         TTrace((stderr, "nclose_outfile:  Unix e.f. modif. time = %ldn",
  601.           tp.modtime));
  602.     } else {
  603.         tp.modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  604.     }
  605.     if (eb_izux_flg & EB_UT_FL_ATIME) {
  606.         tp.actime = zt.atime;
  607.         TTrace((stderr, "close_outfile:  Unix e.f. access time = %ldn",
  608.           tp.actime));
  609.     } else {
  610.         tp.actime = tp.modtime;
  611.         TTrace((stderr, "nclose_outfile:  modification/access times = %ldn",
  612.           tp.modtime));
  613.     }
  614. #else /* !USE_EF_UT_TIME */
  615.     tp.actime = tp.modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  616.     TTrace((stderr, "nclose_outfile:  modification/access times = %ldn",
  617.       tp.modtime));
  618. #endif /* ?USE_EF_UT_TIME */
  619.     /* set the file's access and modification times */
  620.     if (utime(G.filename, &tp))
  621.         Info(slide, 0x201, ((char *)slide,
  622.           "warning:  cannot set the time for %sn", G.filename));
  623. /*---------------------------------------------------------------------------
  624.     Change the file permissions from default ones to those stored in the
  625.     zipfile.
  626.   ---------------------------------------------------------------------------*/
  627. #ifndef NO_CHMOD
  628.     if (chmod(G.filename, 0xffff & G.pInfo->file_attr))
  629.             perror("chmod (file attributes) error");
  630. #endif
  631. } /* end function close_outfile() */
  632. #ifdef TIMESTAMP
  633. /***************************/
  634. /*  Function stamp_file()  */
  635. /***************************/
  636. int stamp_file(fname, modtime)
  637.     ZCONST char *fname;
  638.     time_t modtime;
  639. {
  640.     ztimbuf tp;
  641.     tp.modtime = tp.actime = modtime;
  642.     return (utime(fname, &tp));
  643. } /* end function stamp_file() */
  644. #endif /* TIMESTAMP */
  645. #ifndef SFX
  646. /************************/
  647. /*  Function version()  */
  648. /************************/
  649. void version(__G)
  650.     __GDEF
  651. {
  652. #ifdef __TURBOC__
  653.     char buf[40];
  654. #endif
  655.     sprintf((char *)slide, LoadFarString(CompiledWith),
  656. #ifdef __GNUC__
  657.       "gcc ", __VERSION__,
  658. #else
  659. #  if 0
  660.       "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
  661. #  else
  662. #  ifdef __TURBOC__
  663.       "Turbo C", (sprintf(buf, " (0x%04x = %d)", __TURBOC__, __TURBOC__), buf),
  664. #  else
  665.       "unknown compiler", "",
  666. #  endif
  667. #  endif
  668. #endif
  669. #ifdef __MINT__
  670.       "Atari TOS/MiNT",
  671. #else
  672.       "Atari TOS",
  673. #endif
  674.       " (Atari ST/TT/Falcon030)",
  675. #ifdef __DATE__
  676.       " on ", __DATE__
  677. #else
  678.       "", ""
  679. #endif
  680.     );
  681.     (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
  682. } /* end function version() */
  683. #endif /* !SFX */