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

压缩解压

开发平台:

MultiPlatform

  1. /*---------------------------------------------------------------------------
  2.   qdos.c
  3.   QDOS-specific routines for use with Info-ZIP's UnZip 5.3 and later.
  4.   Contains:  Qstrfix()
  5.              QFilename()
  6.              QMatch()
  7.              chowner()
  8.              Qgetch()
  9.              QReturn()
  10.              LastDir()
  11.              do_wild()           <-- generic enough to put in file_io.c?
  12.              mapattr()
  13.              mapname()
  14.              checkdir()
  15.              qfix()
  16.              close_outfile()
  17.              stamp_file()
  18.              getp()
  19.              version()
  20.   ---------------------------------------------------------------------------*/
  21. #define UNZIP_INTERNAL
  22. #include "unzip.h"
  23. #include "crypt.h"
  24. #include "ttyio.h"
  25. #include <dirent.h>
  26. #include "izqdos.h"
  27. #include "version.h"
  28. #ifndef SFX
  29. char _prog_name[] = "UnZip";
  30. #else
  31. char _prog_name[] = "??Special Flag for unzipsfx hack  ??";
  32. #endif
  33. /* sorrid hack at request of GRR follows; hope the compiler stays kind to us */
  34. char _version[] = {UZ_MAJORVER+'0','.',UZ_MINORVER+'0',PATCHLEVEL+'0'};
  35. char _extra[] = " " BETALEVEL;
  36. char _copyright[] = "(c) Info-ZIP Group";
  37. char *  _endmsg = NULL;
  38. long _stack = 16*1024;         /* huge stack (for qdos) */
  39. extern void consetup_title(chanid_t,struct WINDOWDEF *);
  40. void (*_consetup)(chanid_t,struct WINDOWDEF *) = consetup_title;
  41. struct WINDOWDEF _condetails =
  42. {
  43.     2,
  44.     1,
  45.     0,
  46.     7,
  47.     500,
  48.     220,
  49.     2,
  50.     30
  51. };
  52. static jobid_t chowner(chanid_t chan)
  53. {
  54.     extern char *_sys_var;
  55.     char *scht;
  56.     long *cdb;
  57.     long jid;
  58.     scht = *((char **)(_sys_var + 0x78));
  59.     cdb = *(long **)((long *)scht  + (chan & 0xffff));
  60.     jid = *(cdb + 2);
  61.     return jid;
  62. }
  63. int QReturn(int err)
  64. {
  65.     jobid_t me,you;
  66.     me = getpid();
  67.     you = chowner(getchid(0));
  68.     if((me == you) && ((qlflag & 4) == 0))
  69.     {
  70.         if(isatty(0) && isatty(2) && qlwait)
  71.         {
  72.             char c = 0;
  73.             fputs("Press a key to exit", stderr);
  74.             if((io_fbyte(getchid(0), qlwait, &c) == 0) && c == 27)
  75.             {
  76.                 io_fbyte(getchid(0), -1, &c);
  77.             }
  78.         }
  79.     }
  80.     exit(err);
  81. }
  82. #ifndef FUNZIP
  83. static int created_dir;        /* used in mapname(), checkdir() */
  84. static int renamed_fullpath;   /* ditto */
  85. char *Qstrfix (char *p)
  86. {
  87.     char *q;
  88.     for (q = p; (q = strstr(q, ".zip"));)
  89.     {
  90.         memcpy(q, "_zip", 4);
  91.         q += 4;
  92.     }
  93.     return p;
  94. }
  95. void QFilename(char *f)
  96. {
  97.     char *o,*p,*q = strdup(f);
  98.     p = q;
  99.     if(*q == '.' && *(q+1) == '/') q += 2;
  100.     o = q;
  101.     for(;*q;q++)
  102.     {
  103.         if(*q == '/') *q = '_';
  104.         if((qlflag & 1) == 0)
  105.         {
  106.             if(*q == '.') *q = '_';
  107.         }
  108.     }
  109.     strcpy(f,o);
  110.     free(p);
  111. }
  112. int QMatch(uch c1, uch c2)
  113. {
  114.     int m =0;
  115.     if(c1 != c2)
  116.     {
  117.         if(c1 == '_' && (c2 == '.' || c2 == '/'))
  118.         {
  119.             m = 1;
  120.         }
  121.     }
  122.     else
  123.     {
  124.         m = 1;
  125.     }
  126.     return m;
  127. }
  128. int Qgetch(void)
  129. {
  130.     char ch;
  131.     if(io_fbyte(getchid(0), -1, &ch) < 0)
  132.     {
  133.         return EOF;
  134.     }
  135.     else
  136.     {
  137.         return (int) ch;
  138.     }
  139. }
  140. #ifndef SFX
  141. char *LastDir(char *ws)
  142. {
  143.     char *p;
  144.     char *q = ws;
  145.     struct stat s;
  146.     for(p = ws; *p; p++)
  147.     {
  148.         if(*p == '_')
  149.         {
  150.             char c;
  151.             p++;
  152.             c = *p;
  153.             *p = 0;
  154.             if(stat(ws, &s) == 0 && S_ISDIR(s.st_mode))
  155.             {
  156.                 q = p;
  157.             }
  158.             *p = c;
  159.         }
  160.     }
  161.     return q;
  162. }
  163. /**********************/
  164. /* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  165. /**********************/
  166. char *do_wild(__G__ wildspec)
  167.     __GDEF
  168.     char *wildspec;         /* only used first time on a given dir */
  169. {
  170.     static DIR *dir = (DIR *)NULL;
  171.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  172.     static int firstcall=TRUE, have_dirname, dirnamelen;
  173.     struct dirent *file;
  174.     char basedir[40];
  175.     /* Even when we're just returning wildspec, we *always* do so in
  176.      * matchname[]--calling routine is allowed to append four characters
  177.      * to the returned string, and wildspec may be a pointer to argv[].
  178.      */
  179.     if (firstcall) {        /* first call:  must initialize everything */
  180.         char *ws = NULL, *us = NULL;
  181.         firstcall = FALSE;
  182.         /* break the wildspec into a directory part and a wildcard filename */
  183.         ws = (char *) iswild(wildspec);
  184.         if(ws == NULL)
  185.         {
  186.             strcpy(matchname, wildspec);
  187.             return matchname;
  188.         }
  189.         us = LastDir(wildspec);
  190.         if(us == wildspec)
  191.         {
  192.             dirname = basedir;
  193.             getcwd(basedir, sizeof(basedir)-1);
  194.             dirnamelen = strlen(basedir);
  195.             have_dirname = FALSE;
  196.             wildname = wildspec;
  197.         } else {
  198.             wildname = us;     /* point at character after '/' */
  199.             dirnamelen = wildname - wildspec;
  200.             if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  201.                 Info(slide, 0x201, ((char *)slide,
  202.                   "warning:  cannot allocate wildcard buffersn"));
  203.                 strcpy(matchname, wildspec);
  204.                 return matchname;   /* but maybe filespec was not a wildcard */
  205.             }
  206.             strncpy(dirname, wildspec, dirnamelen);
  207.             dirname[dirnamelen] = '';   /* terminate for strcpy below */
  208.             have_dirname = TRUE;
  209.         }
  210.         if ((dir = opendir(dirname)) != (DIR *)NULL) {
  211.             while ((file = readdir(dir)) != (struct dirent *)NULL) {
  212.                 if (match(file->d_name, wildname, 2)) {  /* 0 == case sens. */
  213.                     if (have_dirname) {
  214.                         strcpy(matchname, dirname);
  215.                         strcpy(matchname+dirnamelen, file->d_name);
  216.                     } else
  217.                         strcpy(matchname, file->d_name);
  218.                     return matchname;
  219.                 }
  220.             }
  221.             /* if we get to here directory is exhausted, so close it */
  222.             closedir(dir);
  223.             dir = (DIR *)NULL;
  224.         }
  225.         /* return the raw wildspec in case that works (e.g., directory not
  226.          * searchable, but filespec was not wild and file is readable) */
  227.         strcpy(matchname, wildspec);
  228.         return matchname;
  229.     }
  230.     /* last time through, might have failed opendir but returned raw wildspec */
  231.     if (dir == (DIR *)NULL) {
  232.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  233.         if (have_dirname)
  234.             free(dirname);
  235.         return (char *)NULL;
  236.     }
  237.     /* If we've gotten this far, we've read and matched at least one entry
  238.      * successfully (in a previous call), so dirname has been copied into
  239.      * matchname already.
  240.      */
  241.     while ((file = readdir(dir)) != (struct dirent *)NULL)
  242.         if (match(file->d_name, wildname, 2)) {   /* 0 == don't ignore case */
  243.             if (have_dirname) {
  244.                 /* strcpy(matchname, dirname); */
  245.                 strcpy(matchname+dirnamelen, file->d_name);
  246.             } else
  247.                 strcpy(matchname, file->d_name);
  248.             return matchname;
  249.         }
  250.     closedir(dir);     /* have read at least one dir entry; nothing left */
  251.     dir = (DIR *)NULL;
  252.     firstcall = TRUE;  /* reset for new wildspec */
  253.     if (have_dirname)
  254.         free(dirname);
  255.     return (char *)NULL;
  256. } /* end function do_wild() */
  257. #endif /* !SFX */
  258. /**********************/
  259. /* Function mapattr() */
  260. /**********************/
  261. int mapattr(__G)
  262.     __GDEF
  263. {
  264.     ulg tmp = G.crec.external_file_attributes;
  265.     switch (G.pInfo->hostnum) {
  266.         case AMIGA_:
  267.             tmp = (unsigned)(tmp>>17 & 7);   /* Amiga RWE bits */
  268.             G.pInfo->file_attr = (unsigned)(tmp<<6 | tmp<<3 | tmp);
  269.             break;
  270.         case QDOS_:
  271.         case UNIX_:
  272.         case VMS_:
  273.         case ACORN_:
  274.         case ATARI_:
  275.         case BEOS_:
  276.             G.pInfo->file_attr = (unsigned)(tmp >> 16);
  277.             if (G.pInfo->file_attr != 0 || !G.extra_field) {
  278.                 return 0;
  279.             } else {
  280.                 /* Some (non-Info-ZIP) implementations of Zip for Unix and
  281.                    VMS (and probably others ??) leave 0 in the upper 16-bit
  282.                    part of the external_file_attributes field. Instead, they
  283.                    store file permission attributes in some extra field.
  284.                    As a work-around, we search for the presence of one of
  285.                    these extra fields and fall back to the MSDOS compatible
  286.                    part of external_file_attributes if one of the known
  287.                    e.f. types has been detected.
  288.                    Later, we might implement extraction of the permission
  289.                    bits from the VMS extra field. But for now, the work-around
  290.                    should be sufficient to provide "readable" extracted files.
  291.                    (For ASI Unix e.f., an experimental remap of the e.f.
  292.                    mode value IS already provided!)
  293.                  */
  294.                 ush ebID;
  295.                 unsigned ebLen;
  296.                 uch *ef = G.extra_field;
  297.                 unsigned ef_len = G.crec.extra_field_length;
  298.                 int r = FALSE;
  299.                 while (!r && ef_len >= EB_HEADSIZE) {
  300.                     ebID = makeword(ef);
  301.                     ebLen = (unsigned)makeword(ef+EB_LEN);
  302.                     if (ebLen > (ef_len - EB_HEADSIZE))
  303.                         /* discoverd some e.f. inconsistency! */
  304.                         break;
  305.                     switch (ebID) {
  306.                       case EF_ASIUNIX:
  307.                         if (ebLen >= (EB_ASI_MODE+2)) {
  308.                             G.pInfo->file_attr =
  309.                               (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
  310.                             /* force stop of loop: */
  311.                             ef_len = (ebLen + EB_HEADSIZE);
  312.                             break;
  313.                         }
  314.                         /* else: fall through! */
  315.                       case EF_PKVMS:
  316.                         /* "found nondecypherable e.f. with perm. attr" */
  317.                         r = TRUE;
  318.                       default:
  319.                         break;
  320.                     }
  321.                     ef_len -= (ebLen + EB_HEADSIZE);
  322.                     ef += (ebLen + EB_HEADSIZE);
  323.                 }
  324.                 if (!r)
  325.                     return 0;
  326.             }
  327.             /* fall through! */
  328.         /* all remaining cases:  expand MSDOS read-only bit into write perms */
  329.         case FS_FAT_:
  330.         case FS_HPFS_:
  331.         case FS_NTFS_:
  332.         case MAC_:
  333.         case TOPS20_:
  334.         default:
  335.             tmp = !(tmp & 1) << 1;   /* read-only bit --> write perms bits */
  336.             G.pInfo->file_attr = (unsigned)(0444 | tmp<<6 | tmp<<3 | tmp);
  337.             break;
  338.     } /* end switch (host-OS-created-by) */
  339.     /* for originating systems with no concept of "group," "other," "system": */
  340.     umask( (int)(tmp=umask(0)) );    /* apply mask to expanded r/w(/x) perms */
  341.     G.pInfo->file_attr &= ~tmp;
  342.     return 0;
  343. } /* end function mapattr() */
  344. /************************/
  345. /*  Function mapname()  */
  346. /************************/
  347.                              /* return 0 if no error, 1 if caution (filename */
  348. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  349.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  350.     int renamed;             /*  or 10 if out of memory (skip file) */
  351. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  352.     char pathcomp[FILNAMSIZ];    /* path-component buffer */
  353.     char *pp, *cp=(char *)NULL;  /* character pointers */
  354.     char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  355.     int quote = FALSE;           /* flags */
  356.     int error = 0;
  357.     register unsigned workch;    /* hold the character being tested */
  358. /*---------------------------------------------------------------------------
  359.     Initialize various pointers and counters and stuff.
  360.   ---------------------------------------------------------------------------*/
  361.     if (G.pInfo->vollabel)
  362.         return IZ_VOL_LABEL;    /* can't set disk volume labels in SMS/QDOS */
  363.     /* can create path as long as not just freshening, or if user told us */
  364.     G.create_dirs = (!uO.fflag || renamed);
  365.     created_dir = FALSE;        /* not yet */
  366.     /* user gave full pathname:  don't prepend rootpath */
  367.     renamed_fullpath = (renamed && (*G.filename == '/'));
  368.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  369.         return 10;              /* initialize path buffer, unless no memory */
  370.     *pathcomp = '';           /* initialize translation buffer */
  371.     pp = pathcomp;              /* point to translation buffer */
  372.     if (uO.jflag)               /* junking directories */
  373.         cp = (char *)strrchr(G.filename, '/');
  374.     if (cp == (char *)NULL)     /* no '/' or not junking dirs */
  375.         cp = G.filename;        /* point to internal zipfile-member pathname */
  376.     else
  377.         ++cp;                   /* point to start of last component of path */
  378. #ifdef QDOS
  379.     if(*cp == '.' && *(cp+1) == '/')
  380.     {
  381.         cp += 2;
  382.     }
  383. #endif
  384. /*---------------------------------------------------------------------------
  385.     Begin main loop through characters in filename.
  386.   ---------------------------------------------------------------------------*/
  387.     while ((workch = (uch)*cp++) != 0) {
  388.         if (quote) {                 /* if character quoted, */
  389.             *pp++ = (char)workch;    /*  include it literally */
  390.             quote = FALSE;
  391.         } else
  392.             switch (workch) {
  393.             case '/':             /* can assume -j flag not given */
  394.                 *pp = '';
  395.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  396.                     return error;
  397.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  398.                 lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  399.                 break;
  400.             case ';':             /* VMS version (or DEC-20 attrib?) */
  401.                 lastsemi = pp;
  402.                 *pp++ = ';';      /* keep for now; remove VMS ";##" */
  403.                 break;            /*  later, if requested */
  404.             case '26':          /* control-V quote for special chars */
  405.                 quote = TRUE;     /* set flag for next character */
  406.                 break;
  407.             case '.':
  408.                 if((qlflag & 1) == 0)
  409.                 {
  410.                     *pp++ = '_';
  411.                 }
  412.                 else
  413.                 {
  414.                     *pp++ = '.';
  415.                 }
  416.                 break;
  417.             default:
  418.                 /* allow European characters in filenames: */
  419.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  420.                     *pp++ = (char)workch;
  421.             } /* end switch */
  422.     } /* end while loop */
  423.     *pp = '';                   /* done with pathcomp:  terminate it */
  424.     /* if not saving them, remove VMS version numbers (appended ";###") */
  425.     if (!uO.V_flag && lastsemi) {
  426.         pp = lastsemi + 1;
  427.         while (isdigit((uch)(*pp)))
  428.             ++pp;
  429.         if (*pp == '')          /* only digits between ';' and end:  nuke */
  430.             *lastsemi = '';
  431.     }
  432. /*---------------------------------------------------------------------------
  433.     Report if directory was created (and no file to create:  filename ended
  434.     in '/'), check name to be sure it exists, and combine path and name be-
  435.     fore exiting.
  436.   ---------------------------------------------------------------------------*/
  437.     if (G.filename[strlen(G.filename) - 1] == '/') {
  438.         G.filename[strlen(G.filename) - 1] = '_';
  439.         checkdir(__G__ G.filename, GETPATH);
  440.         if (created_dir) {
  441.             if (QCOND2) {
  442.                 Info(slide, 0, ((char *)slide, "   creating: %sn",
  443.                   G.filename));
  444.             }
  445.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  446.         }
  447.         return 2;   /* dir existed already; don't look for data to extract */
  448.     }
  449.     if (*pathcomp == '') {
  450.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failedn",
  451.           G.filename));
  452.         return 3;
  453.     }
  454.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  455.     checkdir(__G__ G.filename, GETPATH);
  456.     return error;
  457. } /* end function mapname() */
  458. /***********************/
  459. /* Function checkdir() */
  460. /***********************/
  461. int checkdir(__G__ pathcomp, flag)
  462.     __GDEF
  463.     char *pathcomp;
  464.     int flag;
  465. /*
  466.  * returns:  1 - (on APPEND_NAME) truncated filename
  467.  *           2 - path doesn't exist, not allowed to create
  468.  *           3 - path doesn't exist, tried to create and failed; or
  469.  *               path exists and is not a directory, but is supposed to be
  470.  *           4 - path is too long
  471.  *          10 - can't allocate memory for filename buffers
  472.  */
  473. {
  474.     static int rootlen = 0;   /* length of rootpath */
  475.     static char *rootpath;    /* user's "extract-to" directory */
  476.     static char *buildpath;   /* full path (so far) to extracted file */
  477.     static char *end;         /* pointer to end of buildpath ('') */
  478. #   define FN_MASK   7
  479. #   define FUNCTION  (flag & FN_MASK)
  480. /*---------------------------------------------------------------------------
  481.     APPEND_DIR:  append the path component to the path being built and check
  482.     for its existence.  If doesn't exist and we are creating directories, do
  483.     so for this one; else signal success or error as appropriate.
  484.   ---------------------------------------------------------------------------*/
  485.     if (FUNCTION == APPEND_DIR) {
  486.         int too_long = FALSE;
  487. #ifdef SHORT_NAMES
  488.         char *old_end = end;
  489. #endif
  490.         Trace((stderr, "appending dir segment [%s]n", pathcomp));
  491.         while ((*end = *pathcomp++) != '')
  492.             ++end;
  493. #ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
  494.         if ((end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
  495.             *(end = old_end + FILENAME_MAX) = '';
  496. #endif
  497.         /* GRR:  could do better check, see if overrunning buffer as we go:
  498.          * check end-buildpath after each append, set warning variable if
  499.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  500.          * appending.  Clear variable when begin new path. */
  501.         if ((end-buildpath) > FILNAMSIZ-2)  /* need '/', one-char name, '' */
  502.             too_long = TRUE;                /* check if extracting directory? */
  503.         if (stat(buildpath, &G.statbuf)) {    /* path doesn't exist */
  504.             if (!G.create_dirs) {   /* told not to create (freshening) */
  505.                 free(buildpath);
  506.                 return 2;         /* path doesn't exist:  nothing to do */
  507.             }
  508.             if (too_long) {
  509.                 Info(slide, 1, ((char *)slide,
  510.                   "checkdir error:  path too long: %sn", buildpath));
  511.                 free(buildpath);
  512.                 return 4;         /* no room for filenames:  fatal */
  513.             }
  514.             if (mkdir(buildpath, 0777) == -1) {   /* create the directory */
  515.                 Info(slide, 1, ((char *)slide,
  516.                   "checkdir error:  cannot create %sn
  517.                  unable to process %s.n", buildpath, G.filename));
  518.                 free(buildpath);
  519.                 return 3;      /* path didn't exist, tried to create, failed */
  520.             }
  521.             created_dir = TRUE;
  522.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  523.             Info(slide, 1, ((char *)slide,
  524.               "checkdir error:  %s exists but is not directoryn
  525.                  unable to process %s.n", buildpath, G.filename));
  526.             free(buildpath);
  527.             return 3;          /* path existed but wasn't dir */
  528.         }
  529.         if (too_long) {
  530.             Info(slide, 1, ((char *)slide,
  531.               "checkdir error:  path too long: %sn", buildpath));
  532.             free(buildpath);
  533.             return 4;         /* no room for filenames:  fatal */
  534.         }
  535.         *end++ = '_';
  536.         *end = '';
  537.         Trace((stderr, "buildpath now = [%s]n", buildpath));
  538.         return 0;
  539.     } /* end if (FUNCTION == APPEND_DIR) */
  540. /*---------------------------------------------------------------------------
  541.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  542.     buildpath.
  543.   ---------------------------------------------------------------------------*/
  544.     if (FUNCTION == GETPATH) {
  545.         strcpy(pathcomp, buildpath);
  546.         Trace((stderr, "getting and freeing path [%s]n", pathcomp));
  547.         free(buildpath);
  548.         buildpath = end = (char *)NULL;
  549.         return 0;
  550.     }
  551. /*---------------------------------------------------------------------------
  552.     APPEND_NAME:  assume the path component is the filename; append it and
  553.     return without checking for existence.
  554.   ---------------------------------------------------------------------------*/
  555.     if (FUNCTION == APPEND_NAME) {
  556. #ifdef SHORT_NAMES
  557.         char *old_end = end;
  558. #endif
  559.         short dlen;
  560.         Trace((stderr, "appending filename [%s]n", pathcomp));
  561.         while ((*end = *pathcomp++) != '') {
  562.             ++end;
  563. #ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
  564.             if ((end-old_end) > FILENAME_MAX)      /* GRR:  proper constant? */
  565.                 *(end = old_end + FILENAME_MAX) = '';
  566. #endif
  567.             if(isdirdev(buildpath))
  568.             {
  569.                 dlen = 5;
  570.             }
  571.             else
  572.             {
  573.                 dlen = 0;
  574.             }
  575.             if ((end-buildpath-dlen) >= FILNAMSIZ) {
  576.                 *--end = '';
  577.                 Info(slide, 0x201, ((char *)slide,
  578.                   "checkdir warning:  path too long; truncatingn
  579.                    %sn                -> %sn", G.filename, buildpath));
  580.                 return 1;   /* filename truncated */
  581.             }
  582.         }
  583.         Trace((stderr, "buildpath now = [%s]n", buildpath));
  584.         return 0;  /* could check for existence here, prompt for new name... */
  585.     }
  586. /*---------------------------------------------------------------------------
  587.     INIT:  allocate and initialize buffer space for the file currently being
  588.     extracted.  If file was renamed with an absolute path, don't prepend the
  589.     extract-to path.
  590.   ---------------------------------------------------------------------------*/
  591. /* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  592.     if (FUNCTION == INIT) {
  593.         Trace((stderr, "initializing buildpath to "));
  594.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1)) ==
  595.             (char *)NULL)
  596.             return 10;
  597.         if ((rootlen > 0) && !renamed_fullpath) {
  598.             strcpy(buildpath, rootpath);
  599.             end = buildpath + rootlen;
  600.         } else {
  601.             *buildpath = '';
  602.             end = buildpath;
  603.         }
  604.         Trace((stderr, "[%s]n", buildpath));
  605.         return 0;
  606.     }
  607. /*---------------------------------------------------------------------------
  608.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  609.     sary; else assume it's a zipfile member and return.  This path segment
  610.     gets used in extracting all members from every zipfile specified on the
  611.     command line.
  612.   ---------------------------------------------------------------------------*/
  613. #if (!defined(SFX) || defined(SFX_EXDIR))
  614.     if (FUNCTION == ROOT) {
  615.         Trace((stderr, "initializing root path to [%s]n", pathcomp));
  616.         if (pathcomp == (char *)NULL) {
  617.             rootlen = 0;
  618.             return 0;
  619.         }
  620.         if ((rootlen = strlen(pathcomp)) > 0) {
  621.             if (rootlen > 0 && (stat(pathcomp, &G.statbuf) ||
  622.                 !S_ISDIR(G.statbuf.st_mode)))          /* path does not exist */
  623.             {
  624.                 if (!G.create_dirs                     /* || iswild(pathcomp) */
  625. #ifdef OLD_EXDIR
  626.                                  || !had_trailing_pathsep
  627. #endif
  628.                                                          ) {
  629.                     rootlen = 0;
  630.                     return 2;   /* skip (or treat as stored file) */
  631.                 }
  632.                 /* create the directory (could add loop here to scan pathcomp
  633.                  * and create more than one level, but why really necessary?) */
  634.                 if (mkdir(pathcomp, 0777) == -1) {
  635.                     Info(slide, 1, ((char *)slide,
  636.                       "checkdir:  cannot create extraction directory: %sn",
  637.                       pathcomp));
  638.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  639.                     return 3;  /* failed:  file exists, or 2+ levels required */
  640.                 }
  641.             }
  642.             if (pathcomp[rootlen-1] == '/' || pathcomp[rootlen-1] == '_') {
  643.                 pathcomp[--rootlen] = '';
  644.             }
  645.             if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
  646.                 rootlen = 0;
  647.                 return 10;
  648.             }
  649.             strcpy(rootpath, pathcomp);
  650.             rootpath[rootlen++] = '_';
  651.             rootpath[rootlen] = '';
  652.         }
  653.         Trace((stderr, "rootpath now = [%s]n", rootpath));
  654.         return 0;
  655.     }
  656. #endif /* !SFX || SFX_EXDIR */
  657. /*---------------------------------------------------------------------------
  658.     END:  free rootpath, immediately prior to program exit.
  659.   ---------------------------------------------------------------------------*/
  660.     if (FUNCTION == END) {
  661.         Trace((stderr, "freeing rootpathn"));
  662.         if (rootlen > 0) {
  663.             free(rootpath);
  664.             rootlen = 0;
  665.         }
  666.         return 0;
  667.     }
  668.     return 99;  /* should never reach */
  669. } /* end function checkdir() */
  670. static void qfix(__G__ ef_ptr, ef_len)
  671.     __GDEF
  672.     uch *ef_ptr;
  673.     unsigned ef_len;
  674. {
  675.     qdosextra qextra;
  676.     while (ef_len >= EB_HEADSIZE)
  677.     {
  678.         qdosextra   *extra = &qextra;
  679.         jbextra     *jbp   = (jbextra *)&qextra;
  680.         unsigned    eb_len = makeword(EB_LEN + ef_ptr);
  681.         if (eb_len > (ef_len - EB_HEADSIZE)) {
  682.             /* discovered some extra field inconsistency! */
  683.             Trace((stderr,
  684.               "qfix: block length %u > rest ef_size %un", eb_len,
  685.               ef_len - EB_HEADSIZE));
  686.             break;
  687.         }
  688.         /* Must ensure that we don't use ODD addresses here */
  689.         memcpy(&qextra, ef_ptr, sizeof(qdosextra));
  690.         switch (extra->shortid) {
  691.           case SHORTID:
  692.             if (!strncmp(extra->longid, LONGID, strlen(LONGID)))
  693.             {
  694.                 if (eb_len != EXTRALEN)
  695.                     fputs("warning: invalid length in Qdos field", stderr);
  696.                 if (extra->header.d_type)
  697.                 {
  698.                     fs_heads(fgetchid(G.outfile), (timeout_t)-1,
  699.                              &extra->header, 14);
  700.                     G.pInfo->file_attr |= S_IXUSR;
  701.                 }
  702.             }
  703.             if (!strncmp(jbp->longid, JBLONGID, strlen(JBLONGID)))
  704.             {
  705.                 if (eb_len != JBEXTRALEN)
  706.                     fputs("warning: invalid length in QZ field", stderr);
  707.                 if (jbp->header.d_type)
  708.                 {
  709.                     fs_heads(fgetchid(G.outfile), (timeout_t)-1,
  710.                              &jbp->header, 14);
  711.                     G.pInfo->file_attr |= S_IXUSR;
  712.                 }
  713.             }
  714.             break;
  715.           default:
  716.             Trace((stderr,"qfix: unknown extra field block, ID=%dn",
  717.                extra->shortid));
  718.             break;
  719.         }
  720.         /* Skip this extra field block */
  721.         ef_ptr += (eb_len + EB_HEADSIZE);
  722.         ef_len -= (eb_len + EB_HEADSIZE);
  723.     }
  724. }
  725. #ifdef QDOS
  726. #  include <utime.h>
  727.    long timezone = 0;
  728. #endif
  729. /****************************/
  730. /* Function close_outfile() */
  731. /****************************/
  732. void close_outfile(__G)
  733.     __GDEF
  734. {
  735.     iztimes zt;
  736. #ifdef USE_EF_UT_TIME
  737.     unsigned eb_izux_flg;
  738. #endif
  739.     if (G.extra_field) {
  740.         qfix(__G__ G.extra_field, G.lrec.extra_field_length);
  741.     }
  742.     fclose(G.outfile);
  743. /*---------------------------------------------------------------------------
  744.     Change the file permissions from default ones to those stored in the
  745.     zipfile.
  746.   ---------------------------------------------------------------------------*/
  747. #ifndef NO_CHMOD
  748.     if (chmod(G.filename, 0xffff & G.pInfo->file_attr))
  749.         perror("chmod (file attributes) error");
  750. #endif
  751. /*---------------------------------------------------------------------------
  752.     Convert from MSDOS-format local time and date to Unix-format 32-bit GMT
  753.     time:  adjust base year from 1980 to 1970, do usual conversions from
  754.     yy/mm/dd hh:mm:ss to elapsed seconds, and account for timezone and day-
  755.     light savings time differences.  If we have a Unix extra field, however,
  756.     we're laughing:  both mtime and atime are ours.
  757.   ---------------------------------------------------------------------------*/
  758. #ifdef USE_EF_UT_TIME
  759.     eb_izux_flg = (G.extra_field ? ef_scan_for_izux(G.extra_field,
  760.                    G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
  761. #ifdef IZ_CHECK_TZ
  762.                    (G.tz_is_valid ? &zt : NULL),
  763. #else
  764.                    &zt,
  765. #endif
  766.                    z_uidgid) : 0);
  767.     if (eb_izux_flg & EB_UT_FL_MTIME) {
  768.         TTrace((stderr, "nclose_outfile:  Unix e.f. modif. time = %ldn",
  769.           zt.mtime));
  770.     } else {
  771.         zt.mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  772.     }
  773.     if (eb_izux_flg & EB_UT_FL_ATIME) {
  774.         TTrace((stderr, "close_outfile:  Unix e.f. access time = %ldn",
  775.           zt.atime));
  776.     } else {
  777.         zt.atime = zt.mtime;
  778.         TTrace((stderr, "nclose_outfile:  modification/access times = %ldn",
  779.           zt.mtime));
  780.     }
  781. #else
  782.     zt.atime = zt.mtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  783. #endif
  784.     /* set the file's access and modification times */
  785.     if (utime(G.filename, (struct utimbuf *)&zt)) {
  786.         Info(slide, 0x201, ((char *)slide,
  787.           "warning:  cannot set the time for %sn", G.filename));
  788.     }
  789. } /* end function close_outfile() */
  790. #ifdef TIMESTAMP
  791. /***************************/
  792. /*  Function stamp_file()  */
  793. /***************************/
  794. int stamp_file(fname, modtime)
  795.     ZCONST char *fname;
  796.     time_t modtime;
  797. {
  798.     struct utimbuf tp;
  799.     tp.modtime = tp.actime = modtime;
  800.     return (utime(fname, &tp));
  801. } /* end function stamp_file() */
  802. #endif /* TIMESTAMP */
  803. #ifndef SFX
  804. /************************/
  805. /*  Function version()  */
  806. /************************/
  807. void version(__G)
  808.     __GDEF
  809. {
  810.     sprintf((char *)slide, LoadFarString(CompiledWith),
  811.            "c68", " v4.2x", "SMS/QDOS",
  812.             " on ", __DATE__, "","");
  813.     (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
  814. } /* end function version() */
  815. #endif /* !SFX */
  816. #endif /* !FUNZIP */
  817. #if CRYPT
  818. char *getp(__G__ m, p, n)
  819.     __GDEF
  820.     const char *m;              /* prompt for password */
  821.     char *p;                    /* return value: line input */
  822.     int n;                      /* bytes available in p[] */
  823. {
  824.     int c;                      /* one-byte buffer for read() to use */
  825.     int i;                      /* number of characters input */
  826.     char *w;                    /* warning on retry */
  827.     /* get password */
  828.     w = "";
  829.     sd_cure(getchid(0), -1);    /* enable cursor */
  830.     do {
  831.         fputs(w, stderr);       /* warning if back again */
  832.         fputs(m, stderr);       /* display prompt and flush */
  833.         fflush(stderr);
  834.         i = 0;
  835.         do {
  836.             c = getch();
  837.             if (c == 0xc2) {
  838.                 if (i > 0) {
  839.                     i--; /* the `del' keys works */
  840.                     fputs("b b", stderr);
  841.                 }
  842.             }
  843.             else if (i < n) {
  844.                 p[i++] = c;     /* truncate past n */
  845.                 if(c != 'n') putc('*', stderr);
  846.             }
  847.         } while (c != 'n');
  848.         putc('n', stderr);  fflush(stderr);
  849.         w = "(line too long--try again)n";
  850.     } while (p[i-1] != 'n');
  851.     p[i-1] = 0;                 /* terminate at newline */
  852.     sd_curs(getchid(0), -1);    /* suppress cursor */
  853.     return p;                   /* return pointer to password */
  854. } /* end function getp() */
  855. #endif /* CRYPT */