home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip540.zip / amiga / amiga.c next >
C/C++ Source or Header  |  1998-11-17  |  33KB  |  957 lines

  1. /*------------------------------------------------------------------------
  2.  
  3.   amiga.c
  4.  
  5.   Amiga-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  6.   See History.5xx for revision history.
  7.  
  8.   Contents:   do_wild()
  9.               mapattr()
  10.               mapname()
  11.               checkdir()
  12.               close_outfile()
  13.               stamp_file()
  14.               _abort()                (Aztec C only)
  15.              [dateformat()]           (currently not used)
  16.               windowheight()
  17.               version()
  18.  
  19.   ------------------------------------------------------------------------*/
  20.  
  21.  
  22. #define UNZIP_INTERNAL
  23. #ifdef AZTEC_C
  24. #  define NO_FCNTL_H
  25. #endif
  26. #include "unzip.h"
  27.  
  28. /* Globular varibundus -- now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h */
  29.  
  30. /* static int created_dir; */      /* used in mapname(), checkdir() */
  31. /* static int renamed_fullpath; */ /* ditto */
  32.  
  33. #define PERMS   0777
  34. #define MKDIR(path,mode) mkdir(path)
  35.  
  36.  
  37. #ifndef S_ISCRIPT          /* not having one implies you have none */
  38. #  define S_IARCHIVE 0020  /* not modified since this bit was last set */
  39. #  define S_IREAD    0010  /* can be opened for reading */
  40. #  define S_IWRITE   0004  /* can be opened for writing */
  41. #  define S_IDELETE  0001  /* can be deleted */
  42. #endif /* S_ISCRIPT */
  43.  
  44. #ifndef S_IRWD
  45. #  define S_IRWD     0015  /* useful combo of Amiga privileges */
  46. #endif /* !S_IRWD */
  47.  
  48. #ifndef S_IHIDDEN
  49. #  define S_IHIDDEN  0200  /* hidden supported in future AmigaDOS (someday) */
  50. #endif /* !S_HIDDEN */
  51.  
  52. #ifndef SFX
  53. /* Make sure the number here matches version.h in the *EXACT* form */
  54. /* UZ_MAJORVER "." UZ_MINORVER PATCHLEVEL vvvv     No non-digits!  */
  55. const char version_id[]  = "\0$VER: UnZip 5.4 ("
  56. #include "env:VersionDate"
  57.    ")\r\n";
  58. #endif /* SFX */
  59.  
  60.  
  61. static int ispattern(char *p)
  62. {
  63.     register char c;
  64.     while (c = *p++)
  65.         if (c == '\\') {
  66.             if (!*++p)
  67.                 return FALSE;
  68.         } else if (c == '?' || c == '*')
  69.             return TRUE;
  70.         else if (c == '[') {
  71.             for (;;) {
  72.                 if (!(c = *p++))
  73.                     return FALSE;
  74.                 else if (c == '\\') {
  75.                     if (!*++p)
  76.                         return FALSE;
  77.                 } else if (c == ']')
  78.                     return TRUE;
  79.             }
  80.         }
  81.     return FALSE;
  82. }
  83.  
  84. /**********************/
  85. /* Function do_wild() */
  86. /**********************/
  87.  
  88. char *do_wild(__G__ wildspec)
  89.     __GDEF
  90.     char *wildspec;         /* only used first time on a given dir */
  91. {
  92. /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h:
  93.     static DIR *wild_dir = NULL;
  94.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  95.     static int notfirstcall = FALSE, dirnamelen;
  96. */
  97.     struct dirent *file;
  98.     BPTR lok = 0;
  99.  
  100.     /* Even when we're just returning wildspec, we *always* do so in
  101.      * matchname[]--calling routine is allowed to append four characters
  102.      * to the returned string, and wildspec may be a pointer to argv[].
  103.      */
  104.     if (!G.notfirstcall) {      /* first call:  must initialize everything */
  105.         G.notfirstcall = TRUE;
  106.  
  107.         /* avoid needless readdir() scans: */
  108.         if (!ispattern(wildspec) || (lok = Lock(wildspec, ACCESS_READ))) {
  109.             if (lok) UnLock(lok);       /* ^^ we ignore wildcard chars if */
  110.             G.dirnamelen = 0;           /* the name matches a real file   */
  111.             strcpy(G.matchname, wildspec);
  112.             return G.matchname;
  113.         }
  114.  
  115.         /* break the wildspec into a directory part and a wildcard filename */
  116.         if ((G.wildname = strrchr(wildspec, '/')) == NULL
  117.                         && (G.wildname = strrchr(wildspec, ':')) == NULL) {
  118.             G.dirname = "";             /* current dir */
  119.             G.dirnamelen = 0;
  120.             G.wildname = wildspec;
  121.         } else {
  122.             ++G.wildname;     /* point at character after '/' or ':' */
  123.             G.dirnamelen = G.wildname - wildspec;
  124.             if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
  125.                 Info(slide, 1, ((char *)slide,
  126.                      "warning:  cannot allocate wildcard buffers\n"));
  127.                 strcpy(G.matchname, wildspec);
  128.                 return G.matchname; /* but maybe filespec was not a wildcard */
  129.             }
  130.             strncpy(G.dirname, wildspec, G.dirnamelen);
  131.             G.dirname[G.dirnamelen] = 0;
  132.         }
  133.  
  134.         if ((G.wild_dir = opendir(G.dirname)) != NULL) {
  135.             while ((file = readdir(G.wild_dir)) != NULL) {
  136.                 if (match(file->d_name, G.wildname, 1)) {  /* ignore case */
  137.                     strcpy(G.matchname, G.dirname);
  138.                     strcpy(G.matchname + G.dirnamelen, file->d_name);
  139.                     return G.matchname;
  140.                 }
  141.             }
  142.             /* if we get to here directory is exhausted, so close it */
  143.             closedir(G.wild_dir);
  144.             G.wild_dir = NULL;
  145.         }
  146.  
  147.         /* return the raw wildspec in case that works (e.g., directory not
  148.          * searchable, but filespec was not wild and file is readable) */
  149.         strcpy(G.matchname, wildspec);
  150.         return G.matchname;
  151.     }
  152.  
  153.     /* last time through, might have failed opendir but returned raw wildspec */
  154.     if (G.wild_dir == NULL) {
  155.         G.notfirstcall = FALSE;    /* nothing left to try -- reset */
  156.         if (G.dirnamelen > 0)
  157.             free(G.dirname);
  158.         return (char *)NULL;
  159.     }
  160.  
  161.     /* If we've gotten this far, we've read and matched at least one entry
  162.      * successfully (in a previous call), so dirname has been copied into
  163.      * matchname already.
  164.      */
  165.     while ((file = readdir(G.wild_dir)) != NULL)
  166.         if (match(file->d_name, G.wildname, 1)) {   /* 1 == ignore case */
  167.             /* strcpy(G.matchname, dirname); */
  168.             strcpy(G.matchname + G.dirnamelen, file->d_name);
  169.             return G.matchname;
  170.         }
  171.  
  172.     closedir(G.wild_dir);  /* have read at least one dir entry; nothing left */
  173.     G.wild_dir = NULL;
  174.     G.notfirstcall = FALSE;  /* reset for new wildspec */
  175.     if (G.dirnamelen > 0)
  176.         free(G.dirname);
  177.     return (char *)NULL;
  178.  
  179. } /* end function do_wild() */
  180.  
  181.  
  182.  
  183.  
  184. /**********************/
  185. /* Function mapattr() */
  186. /**********************/
  187.  
  188. int mapattr(__G)      /* Amiga version */
  189.     __GDEF
  190. {
  191.     ulg  tmp = G.crec.external_file_attributes;
  192.  
  193.  
  194.     /* Amiga attributes = hsparwed = hidden, script, pure, archive,
  195.      * read, write, execute, delete */
  196.  
  197.     switch (G.pInfo->hostnum) {
  198.         case AMIGA_:
  199.             if ((tmp & 1) == (tmp>>18 & 1))
  200.                 tmp ^= 0x000F0000;      /* PKAZip compatibility kluge */
  201.             /* turn off archive bit for restored Amiga files */
  202.             G.pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE));
  203.             break;
  204.  
  205.         case UNIX_:   /* preserve read, write, execute:  use logical-OR of */
  206.         case VMS_:    /* user, group, and other; if writable, set delete bit */
  207.         case ACORN_:
  208.         case ATARI_:
  209.         case BEOS_:
  210.         case QDOS_:
  211.         case TANDEM_:
  212.             {
  213.               unsigned uxattr = (unsigned)(tmp >> 16);
  214.               int r = FALSE;
  215.  
  216.               if (uxattr == 0 && G.extra_field) {
  217.                 /* Some (non-Info-ZIP) implementations of Zip for Unix and
  218.                    VMS (and probably others ??) leave 0 in the upper 16-bit
  219.                    part of the external_file_attributes field. Instead, they
  220.                    store file permission attributes in some extra field.
  221.                    As a work-around, we search for the presence of one of
  222.                    these extra fields and fall back to the MSDOS compatible
  223.                    part of external_file_attributes if one of the known
  224.                    e.f. types has been detected.
  225.                    Later, we might implement extraction of the permission
  226.                    bits from the VMS extra field. But for now, the work-around
  227.                    should be sufficient to provide "readable" extracted files.
  228.                    (For ASI Unix e.f., an experimental remap of the e.f.
  229.                    mode value IS already provided!)
  230.                  */
  231.                 ush ebID;
  232.                 unsigned ebLen;
  233.                 uch *ef = G.extra_field;
  234.                 unsigned ef_len = G.crec.extra_field_length;
  235.  
  236.                 while (!r && ef_len >= EB_HEADSIZE) {
  237.                     ebID = makeword(ef);
  238.                     ebLen = (unsigned)makeword(ef+EB_LEN);
  239.                     if (ebLen > (ef_len - EB_HEADSIZE))
  240.                         /* discoverd some e.f. inconsistency! */
  241.                         break;
  242.                     switch (ebID) {
  243.                       case EF_ASIUNIX:
  244.                         if (ebLen >= (EB_ASI_MODE+2)) {
  245.                             uxattr =
  246.                               (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
  247.                             /* force stop of loop: */
  248.                             ef_len = (ebLen + EB_HEADSIZE);
  249.                             break;
  250.                         }
  251.                         /* else: fall through! */
  252.                       case EF_PKVMS:
  253.                         /* "found nondecypherable e.f. with perm. attr" */
  254.                         r = TRUE;
  255.                       default:
  256.                         break;
  257.                     }
  258.                     ef_len -= (ebLen + EB_HEADSIZE);
  259.                     ef += (ebLen + EB_HEADSIZE);
  260.                 }
  261.               }
  262.               if (!r) {
  263.                 uxattr = (( uxattr>>6 | uxattr>>3 | uxattr) & 07) << 1;
  264.                 G.pInfo->file_attr = (unsigned)(uxattr&S_IWRITE ?
  265.                                                 uxattr|S_IDELETE : uxattr);
  266.                 break;
  267.               }
  268.             }
  269.             /* fall through! */
  270.  
  271.         /* all other platforms:  assume read-only bit in DOS half of attribute
  272.          * word is set correctly ==> will become READ or READ+WRITE+DELETE */
  273.         case FS_FAT_:
  274.         case FS_HPFS_:  /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */
  275.         case FS_NTFS_:
  276.         case MAC_:
  277.         case TOPS20_:
  278.         default:
  279.             G.pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD);
  280.             break;
  281.  
  282.     } /* end switch (host-OS-created-by) */
  283.  
  284.     G.pInfo->file_attr &= 0xff;   /* mask off all but lower eight bits */
  285.     return 0;
  286.  
  287. } /* end function mapattr() */
  288.  
  289.  
  290.  
  291.  
  292. /************************/
  293. /*  Function mapname()  */
  294. /************************/
  295.  
  296. int mapname(__G__ renamed)  /* return 0 if no error, 1 if caution (truncate), */
  297.     __GDEF                  /* 2 if warning (skip because dir doesn't exist), */
  298.     int renamed;            /* 3 if error (skip file), 10 if no memory (skip) */
  299. {                           /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  300.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  301.     char *pp, *cp=NULL;         /* character pointers */
  302.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  303.     int error = 0;
  304.     register unsigned workch;   /* hold the character being tested */
  305.  
  306.  
  307. /*---------------------------------------------------------------------------
  308.     Initialize various pointers and counters and stuff.
  309.   ---------------------------------------------------------------------------*/
  310.  
  311.     if (G.pInfo->vollabel)
  312.         return IZ_VOL_LABEL;    /* can't set disk volume labels in AmigaDOS */
  313.  
  314.     /* can create path as long as not just freshening, or if user told us */
  315.     G.create_dirs = (!uO.fflag || renamed);
  316.  
  317.     G.created_dir = FALSE;      /* not yet */
  318.  
  319.     /* user gave full pathname:  don't prepend G.rootpath */
  320. #ifndef OLD_AMIGA_RENAMED
  321.     G.renamed_fullpath = (renamed &&
  322.                           (*G.filename == '/' || *G.filename == ':'));
  323. #else
  324.     /* supress G.rootpath even when user gave a relative pathname */
  325. # if 1
  326.     G.renamed_fullpath = (renamed && strpbrk(G.filename, ":/");
  327. # else
  328.     G.renamed_fullpath = (renamed &&
  329.                           (strchr(G.filename, ':') || strchr(G.filename, '/')));
  330. # endif
  331. #endif
  332.  
  333.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  334.         return 10;              /* initialize path buffer, unless no memory */
  335.  
  336.     *pathcomp = '\0';           /* initialize translation buffer */
  337.     pp = pathcomp;              /* point to translation buffer */
  338.     if (uO.jflag)               /* junking directories */
  339.         cp = (char *)strrchr(G.filename, '/');
  340.     if (cp == NULL)             /* no '/' or not junking dirs */
  341.         cp = G.filename;        /* point to internal zipfile-member pathname */
  342.     else
  343.         ++cp;                   /* point to start of last component of path */
  344.  
  345. /*---------------------------------------------------------------------------
  346.     Begin main loop through characters in filename.
  347.   ---------------------------------------------------------------------------*/
  348.  
  349.     while ((workch = (uch)*cp++) != 0) {
  350.  
  351.         switch (workch) {
  352.         case '/':             /* can assume -j flag not given */
  353.             *pp = '\0';
  354.             if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  355.                 return error;
  356.             pp = pathcomp;    /* reset conversion buffer for next piece */
  357.             lastsemi = NULL;  /* leave directory semi-colons alone */
  358.             break;
  359.  
  360.         case ';':             /* VMS version (or DEC-20 attrib?) */
  361.             lastsemi = pp;         /* keep for now; remove VMS ";##" */
  362.             *pp++ = (char)workch;  /*  later, if requested */
  363.             break;
  364.  
  365.         default:
  366.             /* allow ISO European characters in filenames: */
  367.             if (isprint(workch) || (160 <= workch && workch <= 255))
  368.                 *pp++ = (char)workch;
  369.         } /* end switch */
  370.     } /* end while loop */
  371.  
  372.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  373.  
  374.     /* if not saving them, remove with VMS version numbers (appended ";###") */
  375.     if (!uO.V_flag && lastsemi) {
  376.         pp = lastsemi + 1;
  377.         while (isdigit((uch)(*pp)))
  378.             ++pp;
  379.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  380.             *lastsemi = '\0';
  381.     }
  382.  
  383. /*---------------------------------------------------------------------------
  384.     Report if directory was created (and no file to create:  filename ended
  385.     in '/'), check name to be sure it exists, and combine path and name be-
  386.     fore exiting.
  387.   ---------------------------------------------------------------------------*/
  388.  
  389.     if (G.filename[strlen(G.filename) - 1] == '/') {
  390.         checkdir(__G__ G.filename, GETPATH);
  391.         if (G.created_dir) {
  392.             if (QCOND2) {
  393.                 Info(slide, 0, ((char *)slide, "   creating: %s\n",
  394.                   G.filename));
  395.             }
  396.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  397.         }
  398.         return 2;   /* dir existed already; don't look for data to extract */
  399.     }
  400.  
  401.     if (*pathcomp == '\0') {
  402.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  403.              G.filename));
  404.         return 3;
  405.     }
  406.  
  407.     if ((error = checkdir(__G__ pathcomp, APPEND_NAME)) == 1) {
  408.         /* GRR:  OK if truncated here:  warn and continue */
  409.         /* (warn in checkdir?) */
  410.     }
  411.     checkdir(__G__ G.filename, GETPATH);
  412.  
  413.     return error;
  414.  
  415. } /* end function mapname() */
  416.  
  417.  
  418.  
  419.  
  420. /***********************/
  421. /* Function checkdir() */
  422. /***********************/
  423.  
  424. int checkdir(__G__ pathcomp, flag)
  425.     __GDEF
  426.     char *pathcomp;
  427.     int flag;
  428. /*
  429.  * returns:  1 - (on APPEND_xxx) truncated path component
  430.  *           2 - path doesn't exist, not allowed to create
  431.  *           3 - path doesn't exist, tried to create and failed; or
  432.  *               path exists and is not a directory, but is supposed to be
  433.  *           4 - path is too long
  434.  *          10 - can't allocate memory for filename buffers
  435.  */
  436. {
  437. /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h: */
  438. /*  static int rootlen = 0; */   /* length of rootpath */
  439. /*  static char *rootpath;  */   /* user's "extract-to" directory */
  440. /*  static char *buildpath; */   /* full path (so far) to extracted file */
  441. /*  static char *end;       */   /* pointer to end of buildpath ('\0') */
  442.  
  443. #   define FN_MASK   7
  444. #   define FUNCTION  (flag & FN_MASK)
  445.  
  446.  
  447.  
  448. /*---------------------------------------------------------------------------
  449.     APPEND_DIR:  append the path component to the path being built and check
  450.     for its existence.  If doesn't exist and we are creating directories, do
  451.     so for this one; else signal success or error as appropriate.
  452.   ---------------------------------------------------------------------------*/
  453.  
  454. /* GRR:  check path length after each segment:  warn about truncation */
  455.  
  456.     if (FUNCTION == APPEND_DIR) {
  457.         int too_long = FALSE;
  458.  
  459.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  460.         while ((*G.build_end = *pathcomp++))
  461.             ++G.build_end;
  462.         /* Truncate components over 30 chars? Nah, the filesystem handles it. */
  463.         if ((G.build_end-G.buildpath) > FILNAMSIZ-3)       /* room for "/a\0" */
  464.             too_long = TRUE;                /* check if extracting directory? */
  465.         if (stat(G.buildpath, &G.statbuf)) {  /* path doesn't exist */
  466.             if (!G.create_dirs) { /* told not to create (freshening) */
  467.                 free(G.buildpath);
  468.                 return 2;         /* path doesn't exist:  nothing to do */
  469.             }
  470.             if (too_long) {
  471.                 Info(slide, 1, ((char *)slide,
  472.                   "checkdir error:  path too long: %s\n", G.buildpath));
  473.                 free(G.buildpath);
  474.                 return 4;         /* no room for filenames:  fatal */
  475.             }
  476.             if (MKDIR(G.buildpath, 0777) == -1) {   /* create the directory */
  477.                 Info(slide, 1, ((char *)slide,
  478.                  "checkdir error:  cannot create %s\n\
  479.                  unable to process %s.\n", G.buildpath, G.filename));
  480.                 free(G.buildpath);
  481.                 return 3;      /* path didn't exist, tried to create, failed */
  482.             }
  483.             G.created_dir = TRUE;
  484.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  485.             Info(slide, 1, ((char *)slide,
  486.                  "checkdir error:  %s exists but is not a directory\n\
  487.                  unable to process %s.\n", G.buildpath, G.filename));
  488.             free(G.buildpath);
  489.             return 3;          /* path existed but wasn't dir */
  490.         }
  491.         if (too_long) {
  492.             Info(slide, 1, ((char *)slide,
  493.                  "checkdir error:  path too long: %s\n", G.buildpath));
  494.             free(G.buildpath);
  495.             return 4;         /* no room for filenames:  fatal */
  496.         }
  497.         *G.build_end++ = '/';
  498.         *G.build_end = '\0';
  499.         Trace((stderr, "buildpath now = [%s]\n", G.buildpath));
  500.         return 0;
  501.  
  502.     } /* end if (FUNCTION == APPEND_DIR) */
  503.  
  504. /*---------------------------------------------------------------------------
  505.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  506.     G.buildpath.  Not our responsibility to worry whether pathcomp has room.
  507.   ---------------------------------------------------------------------------*/
  508.  
  509.     if (FUNCTION == GETPATH) {
  510.         strcpy(pathcomp, G.buildpath);
  511.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  512.         free(G.buildpath);
  513.         G.buildpath = G.build_end = NULL;
  514.         return 0;
  515.     }
  516.  
  517. /*---------------------------------------------------------------------------
  518.     APPEND_NAME:  assume the path component is the filename; append it and
  519.     return without checking for existence.
  520.   ---------------------------------------------------------------------------*/
  521.  
  522.     if (FUNCTION == APPEND_NAME) {
  523.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  524.         while ((*G.build_end = *pathcomp++)) {
  525.             ++G.build_end;
  526.             if ((G.build_end-G.buildpath) >= FILNAMSIZ) {
  527.                 *--G.build_end = '\0';
  528.                 Info(slide, 1, ((char *)slide,
  529.                    "checkdir warning:  path too long; truncating\n\
  530.                    %s\n                -> %s\n", G.filename, G.buildpath));
  531.                 return 1;   /* filename truncated */
  532.             }
  533.         }
  534.         Trace((stderr, "buildpath static now = [%s]\n", G.buildpath));
  535.         return 0;  /* could check for existence here, prompt for new name... */
  536.     }
  537.  
  538. /*---------------------------------------------------------------------------
  539.     INIT:  allocate and initialize buffer space for the file currently being
  540.     extracted.  If file was renamed with an absolute path, don't prepend the
  541.     extract-to path.
  542.   ---------------------------------------------------------------------------*/
  543.  
  544.     if (FUNCTION == INIT) {
  545.         Trace((stderr, "initializing buildpath static to "));
  546.         if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
  547.               == NULL)
  548.             return 10;
  549.         if ((G.rootlen > 0) && !G.renamed_fullpath) {
  550.             strcpy(G.buildpath, G.rootpath);
  551.             G.build_end = G.buildpath + G.rootlen;
  552.         } else {
  553.             *G.buildpath = '\0';
  554.             G.build_end = G.buildpath;
  555.         }
  556.         Trace((stderr, "[%s]\n", G.buildpath));
  557.         return 0;
  558.     }
  559.  
  560. /*---------------------------------------------------------------------------
  561.     ROOT:  if appropriate, store the path in G.rootpath and create it if
  562.     necessary; else assume it's a zipfile member and return.  This path
  563.     segment gets used in extracting all members from every zipfile specified
  564.     on the command line.
  565.   ---------------------------------------------------------------------------*/
  566.  
  567. #if (!defined(SFX) || defined(SFX_EXDIR))
  568.     if (FUNCTION == ROOT) {
  569.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  570.         if (pathcomp == NULL) {
  571.             G.rootlen = 0;
  572.             return 0;
  573.         }
  574.         if ((G.rootlen = strlen(pathcomp)) > 0) {
  575.             if (stat(pathcomp, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) {
  576.                 /* path does not exist */
  577.                 if (!G.create_dirs) {
  578.                     G.rootlen = 0;
  579.                     return 2;   /* treat as stored file */
  580.                 }
  581.                 /* create the directory (could add loop here to scan pathcomp
  582.                  * and create more than one level, but why really necessary?) */
  583.                 if (MKDIR(pathcomp, 0777) == -1) {
  584.                     Info(slide, 1, ((char *)slide,
  585.                          "checkdir:  cannot create extraction directory: %s\n",
  586.                          pathcomp));
  587.                     G.rootlen = 0; /* path didn't exist, tried to create, and */
  588.                     return 3;  /* failed:  file exists, or 2+ levels required */
  589.                 }
  590.             }
  591.             if ((G.rootpath = (char *)malloc(G.rootlen+2)) == NULL) {
  592.                 G.rootlen = 0;
  593.                 return 10;
  594.             }
  595.             strcpy(G.rootpath, pathcomp);
  596.             if (G.rootpath[G.rootlen-1] != ':' && G.rootpath[G.rootlen-1] != '/')
  597.                 G.rootpath[G.rootlen++] = '/';
  598.             G.rootpath[G.rootlen] = '\0';
  599.             Trace((stderr, "rootpath now = [%s]\n", G.rootpath));
  600.         }
  601.         return 0;
  602.     }
  603. #endif /* !SFX || SFX_EXDIR */
  604.  
  605. /*---------------------------------------------------------------------------
  606.     END:  free G.rootpath, immediately prior to program exit.
  607.   ---------------------------------------------------------------------------*/
  608.  
  609.     if (FUNCTION == END) {
  610.         Trace((stderr, "freeing rootpath\n"));
  611.         if (G.rootlen > 0) {
  612.             free(G.rootpath);
  613.             G.rootlen = 0;
  614.         }
  615.         return 0;
  616.     }
  617.  
  618.     return 99;  /* should never reach */
  619.  
  620. } /* end function checkdir() */
  621.  
  622.  
  623. /**************************************/
  624. /* Function close_outfile() */
  625. /**************************************/
  626. /* this part differs slightly with Zip */
  627. /*-------------------------------------*/
  628.  
  629. void close_outfile(__G)
  630.     __GDEF
  631. {
  632.     time_t m_time;
  633. #ifdef USE_EF_UT_TIME
  634.     iztimes z_utime;
  635. #endif
  636.     LONG FileDate();
  637.  
  638.     if (uO.cflag)               /* can't set time or filenote on stdout */
  639.         return;
  640.  
  641.   /* close the file *before* setting its time under AmigaDOS */
  642.  
  643.     fclose(G.outfile);
  644.  
  645. #ifdef USE_EF_UT_TIME
  646.     if (G.extra_field &&
  647. #ifdef IZ_CHECK_TZ
  648.         G.tz_is_valid &&
  649. #endif
  650.         (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  651.                           G.lrec.last_mod_dos_datetime, &z_utime, NULL)
  652.          & EB_UT_FL_MTIME))
  653.     {
  654.         TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
  655.                          z_utime.mtime));
  656.         m_time = z_utime.mtime;
  657.     } else {
  658.         /* Convert DOS time to time_t format */
  659.         m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  660.     }
  661. #else /* !USE_EF_UT_TIME */
  662.     /* Convert DOS time to time_t format */
  663.     m_time = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
  664. #endif /* ?USE_EF_UT_TIME */
  665.  
  666. #ifdef DEBUG
  667.     Info(slide, 1, ((char *)slide, "\nclose_outfile(): m_time=%s\n",
  668.                          ctime(&m_time)));
  669. #endif
  670.  
  671.     if (!FileDate(G.filename, &m_time))
  672.         Info(slide, 1, ((char *)slide,
  673.              "warning:  cannot set the time for %s\n", G.filename));
  674.  
  675.   /* set file perms after closing (not done at creation)--see mapattr() */
  676.  
  677.     chmod(G.filename, G.pInfo->file_attr);
  678.  
  679.   /* give it a filenote from the zipfile comment, if appropriate */
  680.  
  681.     if (uO.N_flag && G.filenotes[G.filenote_slot]) {
  682.         SetComment(G.filename, G.filenotes[G.filenote_slot]);
  683.         free(G.filenotes[G.filenote_slot]);
  684.         G.filenotes[G.filenote_slot] = NULL;
  685.     }
  686.  
  687. } /* end function close_outfile() */
  688.  
  689.  
  690. #ifdef TIMESTAMP
  691.  
  692. /*************************/
  693. /* Function stamp_file() */
  694. /*************************/
  695.  
  696. int stamp_file(fname, modtime)
  697.     ZCONST char *fname;
  698.     time_t modtime;
  699. {
  700.     time_t m_time;
  701.     LONG FileDate();
  702.  
  703.     m_time = modtime;
  704.     return (FileDate((char *)fname, &m_time));
  705.  
  706. } /* end function stamp_file() */
  707.  
  708. #endif /* TIMESTAMP */
  709.  
  710.  
  711. #ifndef __SASC
  712. /********************************************************************/
  713. /* Load filedate as a separate external file; it's used by Zip, too.*/
  714. /*                                                                  */
  715. #  include "amiga/filedate.c"                                    /* */
  716. /*                                                                  */
  717. /********************************************************************/
  718.  
  719. /********************* do linewise with stat.c **********************/
  720.  
  721. #  include "amiga/stat.c"
  722. /* this is the exact same stat.c used by Zip */
  723. #endif /* !__SASC */
  724. /* SAS/C makes separate object modules of these; there is less  */
  725. /* trouble that way when redefining standard library functions. */
  726.  
  727. #include <stdio.h>
  728.  
  729. void _abort(void)               /* called when ^C is pressed */
  730. {
  731.     /* echon(); */
  732.     close_leftover_open_dirs();
  733.     fflush(stdout);
  734.     fputs("\n^C\n", stderr);
  735.     exit(1);
  736. }
  737.  
  738.  
  739. /**************************************************************/
  740. /* function windowheight() -- uses sendpkt() from filedate.c: */
  741. /**************************************************************/
  742.  
  743. #include <devices/conunit.h>
  744. #include <dos/dosextens.h>
  745. #include <exec/memory.h>
  746. #include <clib/exec_protos.h>
  747.  
  748. extern long sendpkt(struct MsgPort *pid, long action, long *args, long nargs);
  749.  
  750. int windowheight(BPTR fh)
  751. {
  752.     if (fh && IsInteractive(fh)) {
  753.         struct ConUnit *conunit = NULL;
  754.         void *conp = ((struct FileHandle *) (fh << 2))->fh_Type;
  755.         struct InfoData *ind = AllocMem(sizeof(*ind), MEMF_PUBLIC);
  756.         long argp = ((unsigned long) ind) >> 2;
  757.  
  758.         if (ind && conp && sendpkt(conp, ACTION_DISK_INFO, &argp, 1))
  759.             conunit = (void *) ((struct IOStdReq *) ind->id_InUse)->io_Unit;
  760.         if (ind)
  761.             FreeMem(ind, sizeof(*ind));
  762.         if (conunit)
  763.             return conunit->cu_YMax + 1;
  764.     }
  765.     return INT_MAX;
  766. }
  767.  
  768.  
  769. #ifdef AMIGA_VOLUME_LABELS
  770. /* This function is for if we someday implement -$ on the Amiga. */
  771. #  include <dos/dosextens.h>
  772. #  include <dos/filehandler.h>
  773. #  include <clib/macros.h>
  774.  
  775. BOOL is_floppy(char *path)
  776. {
  777.     BOOL okay = FALSE;
  778.     char devname[32], *debna;
  779.     ushort i;
  780.     BPTR lok = Lock(path, ACCESS_READ), pok;
  781.     struct FileSysStartupMsg *fart;
  782.     struct DeviceNode *debb, devlist = (void *) BADDR((struct DosInfo *)
  783.                                 BADDR(DOSBase->dl_Root->rn_Info)->di_DevInfo);
  784.     if (!lok)
  785.         return FALSE;                   /* should not happen */
  786.     if (pok = ParentDir(path)) {
  787.         UnLock(lok);
  788.         UnLock(pok);
  789.         return FALSE;                   /* it's not a root directory path */
  790.     }
  791.     Forbid();
  792.     for (debb = devlist; debb; debb = BADDR(debb->dn_Next))
  793.         if (debb->dn_Type == DLT_DEVICE && (debb->dn_Task == lick->fl_Task))
  794.             if (fart = BADDR(debb->dn_Startup)) {
  795.                 debna = (char *) BADDR(fart->fssm_Device) + 1;
  796.                 if ((i = debna[-1]) > 31) i = 30;
  797.                 strncpy(devname, debna, i);
  798.                 devname[i] = 0;
  799.                 okay = !strcmp(devname, "trackdisk.device")
  800.                                 || !strcmp(devname, "mfm.device")
  801.                                 || !strcmp(devname, "messydisk.device");
  802.                 break;  /* We only support obvious floppy drives, not tricky */
  803.             }           /* things like removable cartrige hard drives, or    */
  804.     Permit();           /* any unusual kind of floppy device driver.         */
  805.     return okay;
  806. }
  807. #endif /* AMIGA_VOLUME_LABELS */
  808.  
  809.  
  810. #ifndef SFX
  811.  
  812. # if 0
  813. /* As far as I can tell, all the locales AmigaDOS 2.1 knows about all */
  814. /* happen to use DF_MDY ordering, so there's no point in using this.  */
  815.  
  816. /*************************/
  817. /* Function dateformat() */
  818. /*************************/
  819.  
  820. #include <clib/locale_protos.h>
  821. #ifdef AZTEC_C
  822. #  include <pragmas/locale_lib.h>
  823. #endif
  824.  
  825. int dateformat()
  826. {
  827. /*---------------------------------------------------------------------------
  828.     For those operating systems which support it, this function returns a
  829.     value which tells how national convention says that numeric dates are
  830.     displayed.  Return values are DF_YMD, DF_DMY and DF_MDY (the meanings
  831.     should be fairly obvious).
  832.   ---------------------------------------------------------------------------*/
  833.     struct Library *LocaleBase;
  834.     struct Locale *ll;
  835.     int result = DF_MDY;        /* the default */
  836.  
  837.     if ((LocaleBase = OpenLibrary("locale.library", 0))) {
  838.         if (ll = OpenLocale(NULL)) {
  839.             uch *f = ll->loc_ShortDateFormat;
  840.             /* In this string, %y|%Y is year, %b|%B|%h|%m is month, */
  841.             /* %d|%e is day day, and %D|%x is short for mo/da/yr.   */
  842.             if (!strstr(f, "%D") && !strstr(f, "%x")) {
  843.                 uch *da, *mo, *yr;
  844.                 if (!(mo = strstr(f, "%b")) && !(mo = strstr(f, "%B"))
  845.                                     && !(mo = strstr(f, "%h")))
  846.                     mo = strstr(f, "%m");
  847.                 if (!(da = strstr(f, "%d")))
  848.                     da = strstr(f, "%e");
  849.                 if (!(yr = strstr(f, "%y")))
  850.                     yr = strstr(f, "%Y");
  851.                 if (yr && yr < mo)
  852.                     result = DF_YMD;
  853.                 else if (da && da < mo)
  854.                     result = DF_DMY;
  855.             }
  856.             CloseLocale(ll);
  857.         }
  858.         CloseLibrary(LocaleBase);
  859.     }
  860.     return result;
  861. }
  862.  
  863. # endif /* 0 */
  864.  
  865.  
  866. /************************/
  867. /*  Function version()  */
  868. /************************/
  869.  
  870.  
  871. /* NOTE:  the following include depends upon the environment
  872.  *        variable $Workbench to be set correctly.  (Set by
  873.  *        default, by kickstart during startup)
  874.  */
  875. int WBversion = (int)
  876. #include "ENV:Workbench"
  877. ;
  878.  
  879. void version(__G)
  880.    __GDEF
  881. {
  882. /* Define buffers. */
  883.  
  884.    char buf1[16];  /* compiler name */
  885.    char buf2[16];  /* revstamp */
  886.    char buf3[16];  /* OS */
  887.    char buf4[16];  /* Date */
  888. /*   char buf5[16];  /* Time */
  889.  
  890. /* format "with" name strings */
  891.  
  892. #ifdef AMIGA
  893. # ifdef __SASC
  894.    strcpy(buf1,"SAS/C ");
  895. # else
  896. #  ifdef LATTICE
  897.     strcpy(buf1,"Lattice C ");
  898. #  else
  899. #   ifdef AZTEC_C
  900.      strcpy(buf1,"Manx Aztec C ");
  901. #   else
  902.      strcpy(buf1,"UNKNOWN ");
  903. #   endif
  904. #  endif
  905. # endif
  906. /* "under" */
  907.   sprintf(buf3,"AmigaDOS v%d",WBversion);
  908. #else
  909.   strcpy(buf1,"Unknown compiler ");
  910.   strcpy(buf3,"Unknown OS");
  911. #endif
  912.  
  913. /* Define revision, date, and time strings.
  914.  * NOTE:  Do not calculate run time, be sure to use time compiled.
  915.  * Pass these strings via your makefile if undefined.
  916.  */
  917.  
  918. #if defined(__VERSION__) && defined(__REVISION__)
  919.   sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
  920. #else
  921. # ifdef __VERSION__
  922.   sprintf(buf2,"version %d",__VERSION__);
  923. # else
  924.   sprintf(buf2,"unknown version");
  925. # endif
  926. #endif
  927.  
  928. #ifdef __DATE__
  929.   sprintf(buf4," on %s",__DATE__);
  930. #else
  931.   strcpy(buf4," unknown date");
  932. #endif
  933.  
  934. /******
  935. #ifdef __TIME__
  936.   sprintf(buf5," at %s",__TIME__);
  937. #else
  938.   strcpy(buf5," unknown time");
  939. #endif
  940. ******/
  941.  
  942. /* Print strings using "CompiledWith" mask defined in unzip.c (used by all).
  943.  *  ("Compiled with %s%s for %s%s%s%s.")
  944.  */
  945.  
  946.    printf(LoadFarString(CompiledWith),
  947.      buf1,
  948.      buf2,
  949.      buf3,
  950.      buf4,
  951.      "",    /* buf5 not used */
  952.      "" );  /* buf6 not used */
  953.  
  954. } /* end function version() */
  955.  
  956. #endif /* !SFX */
  957.