home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip532.zip / mac / mac.c < prev    next >
C/C++ Source or Header  |  1997-10-21  |  35KB  |  1,161 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   mac.c
  4.  
  5.   Macintosh-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  6.  
  7.   This source file incorporates the contents of what was formerly macfile.c,
  8.   which supported commands (such as mkdir()) not available directly on the
  9.   Mac, and which also determined whether HFS (Hierarchical File System) or
  10.   MFS (Macintosh File System) was in use.
  11.  
  12.   Contains:  do_wild()
  13.              mapattr()
  14.              mapname()
  15.              checkdir()
  16.              close_outfile()
  17.              version()
  18.              IsHFSDisk()
  19.              MacFSTest()
  20.              macmkdir()
  21.              ResolveMacVol()
  22.              macopen()
  23.              macfopen()
  24.              maccreat()
  25.              macread()
  26.              macwrite()
  27.              macclose()
  28.              maclseek()
  29.  
  30.   ---------------------------------------------------------------------------*/
  31.  
  32.  
  33.  
  34. #define UNZIP_INTERNAL
  35. #include "unzip.h"
  36.  
  37. #ifdef MACOS
  38. #ifndef FSFCBLen
  39. #  define FSFCBLen  (*(short *)0x3F6)
  40. #endif
  41.  
  42. #define read_only   file_attr   /* for readability only */
  43.  
  44. static short wAppVRefNum;
  45. static long lAppDirID;
  46. /* int HFSFlag;            /* set if disk has hierarchical file system */
  47.  
  48. static int created_dir;        /* used in mapname(), checkdir() */
  49. static int renamed_fullpath;   /* ditto */
  50.  
  51. #define MKDIR(path)     macmkdir(path, G.gnVRefNum, G.glDirID)
  52.  
  53.  
  54.  
  55. #ifndef SFX
  56.  
  57. /**********************/
  58. /* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  59. /**********************/
  60.  
  61. char *do_wild(__G__ wildspec)
  62.     __GDEF
  63.     char *wildspec;         /* only used first time on a given dir */
  64. {
  65.     static DIR *dir = (DIR *)NULL;
  66.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  67.     static int firstcall=TRUE, have_dirname, dirnamelen;
  68.     struct direct *file;
  69.  
  70.  
  71.     /* Even when we're just returning wildspec, we *always* do so in
  72.      * matchname[]--calling routine is allowed to append four characters
  73.      * to the returned string, and wildspec may be a pointer to argv[].
  74.      */
  75.     if (firstcall) {        /* first call:  must initialize everything */
  76.         firstcall = FALSE;
  77.  
  78.         /* break the wildspec into a directory part and a wildcard filename */
  79.         if ((wildname = strrchr(wildspec, ':')) == (char *)NULL) {
  80.             dirname = ":";
  81.             dirnamelen = 1;
  82.             have_dirname = FALSE;
  83.             wildname = wildspec;
  84.         } else {
  85.             ++wildname;     /* point at character after ':' */
  86.             dirnamelen = wildname - wildspec;
  87.             if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  88.                 Info(slide, 0x201, ((char *)slide,
  89.                   "warning:  cannot allocate wildcard buffers\n"));
  90.                 strcpy(matchname, wildspec);
  91.                 return matchname;   /* but maybe filespec was not a wildcard */
  92.             }
  93.             strncpy(dirname, wildspec, dirnamelen);
  94.             dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
  95.             have_dirname = TRUE;
  96.         }
  97.  
  98.         if ((dir = opendir(dirname)) != (DIR *)NULL) {
  99.             while ((file = readdir(dir)) != (struct direct *)NULL) {
  100.                 if (match(file->d_name, wildname, 0)) {  /* 0 == case sens. */
  101.                     if (have_dirname) {
  102.                         strcpy(matchname, dirname);
  103.                         strcpy(matchname+dirnamelen, file->d_name);
  104.                     } else
  105.                         strcpy(matchname, file->d_name);
  106.                     return matchname;
  107.                 }
  108.             }
  109.             /* if we get to here directory is exhausted, so close it */
  110.             closedir(dir);
  111.             dir = (DIR *)NULL;
  112.         }
  113.  
  114.         /* return the raw wildspec in case that works (e.g., directory not
  115.          * searchable, but filespec was not wild and file is readable) */
  116.         strcpy(matchname, wildspec);
  117.         return matchname;
  118.     }
  119.  
  120.     /* last time through, might have failed opendir but returned raw wildspec */
  121.     if (dir == (DIR *)NULL) {
  122.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  123.         if (have_dirname)
  124.             free(dirname);
  125.         return (char *)NULL;
  126.     }
  127.  
  128. #ifndef THINK_C            /* Think C only matches one at most (for now) */
  129. #ifndef __MWERKS__
  130.     /* If we've gotten this far, we've read and matched at least one entry
  131.      * successfully (in a previous call), so dirname has been copied into
  132.      * matchname already.
  133.      */
  134.     while ((file = readdir(dir)) != (struct direct *)NULL)
  135.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  136.             if (have_dirname) {
  137.                 /* strcpy(matchname, dirname); */
  138.                 strcpy(matchname+dirnamelen, file->d_name);
  139.             } else
  140.                 strcpy(matchname, file->d_name);
  141.             return matchname;
  142.         }
  143. #endif
  144. #endif
  145.  
  146.     closedir(dir);     /* have read at least one dir entry; nothing left */
  147.     dir = (DIR *)NULL;
  148.     firstcall = TRUE;  /* reset for new wildspec */
  149.     if (have_dirname)
  150.         free(dirname);
  151.     return (char *)NULL;
  152.  
  153. } /* end function do_wild() */
  154.  
  155. #endif /* !SFX */
  156.  
  157.  
  158.  
  159.  
  160.  
  161. /**********************/
  162. /* Function mapattr() */
  163. /**********************/
  164.  
  165. int mapattr(__G)
  166.     __GDEF
  167. {
  168.     /* only care about read-only bit, so just look at MS-DOS side of attrs */
  169.     G.pInfo->read_only = (unsigned)(G.crec.external_file_attributes & 1);
  170.     return 0;
  171.  
  172. } /* end function mapattr() */
  173.  
  174.  
  175.  
  176.  
  177.  
  178. /************************/
  179. /*  Function mapname()  */
  180. /************************/
  181.                              /* return 0 if no error, 1 if caution (filename */
  182. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  183.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  184.     int renamed;             /*  or 10 if out of memory (skip file) */
  185. {                            /*  [also IZ_CREATED_DIR] */
  186.     char pathcomp[FILNAMSIZ];    /* path-component buffer */
  187.     char *pp, *cp=(char *)NULL;  /* character pointers */
  188.     char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  189.     int quote = FALSE;           /* flags */
  190.     int error = 0;
  191.     register unsigned workch;    /* hold the character being tested */
  192.  
  193.  
  194. /*---------------------------------------------------------------------------
  195.     Initialize various pointers and counters and stuff.
  196.   ---------------------------------------------------------------------------*/
  197.  
  198.     /* can create path as long as not just freshening, or if user told us */
  199.     G.create_dirs = (!G.fflag || renamed);
  200.  
  201.     created_dir = FALSE;        /* not yet */
  202.  
  203.     /* user gave full pathname:  don't prepend rootpath */
  204.     renamed_fullpath = (renamed && (*G.filename == '/'));
  205.  
  206.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  207.         return 10;              /* initialize path buffer, unless no memory */
  208.  
  209.     pp = pathcomp;              /* point to translation buffer */
  210.     if (!(renamed_fullpath || G.jflag))
  211.         *pp++ = ':';
  212.     *pp = '\0';
  213.  
  214.     if (G.jflag)                /* junking directories */
  215.         cp = (char *)strrchr(G.filename, '/');
  216.     if (cp == (char *)NULL)     /* no '/' or not junking dirs */
  217.         cp = G.filename;        /* point to internal zipfile-member pathname */
  218.     else
  219.         ++cp;                   /* point to start of last component of path */
  220.  
  221. /*---------------------------------------------------------------------------
  222.     Begin main loop through characters in filename.
  223.   ---------------------------------------------------------------------------*/
  224.  
  225.     while ((workch = (uch)*cp++) != 0) {
  226.  
  227.         if (quote) {                 /* if character quoted, */
  228.             *pp++ = (char)workch;    /*  include it literally */
  229.             quote = FALSE;
  230.         } else
  231.             switch (workch) {
  232.             case '/':             /* can assume -j flag not given */
  233.                 *pp = '\0';
  234.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  235.                     return error;
  236.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  237.                 lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  238.                 break;
  239.  
  240.             case ';':             /* VMS version (or DEC-20 attrib?) */
  241.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  242.                 *pp++ = (char)workch;  /*  later, if requested */
  243.                 break;
  244.  
  245.             case '\026':          /* control-V quote for special chars */
  246.                 quote = TRUE;     /* set flag for next character */
  247.                 break;
  248.  
  249.             default:
  250.                 /* allow European characters in filenames: */
  251.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  252.                     *pp++ = (char)workch;
  253.             } /* end switch */
  254.  
  255.     } /* end while loop */
  256.  
  257.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  258.  
  259.     /* if not saving them, remove VMS version numbers (appended ";###") */
  260.     if (!G.V_flag && lastsemi) {
  261.         pp = lastsemi + 1;
  262.         while (isdigit((uch)(*pp)))
  263.             ++pp;
  264.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  265.             *lastsemi = '\0';
  266.     }
  267.  
  268. /*---------------------------------------------------------------------------
  269.     Report if directory was created (and no file to create:  filename ended
  270.     in '/'), check name to be sure it exists, and combine path and name be-
  271.     fore exiting.
  272.   ---------------------------------------------------------------------------*/
  273.  
  274.     if (G.filename[strlen(G.filename) - 1] == '/') {
  275.         checkdir(__G__ G.filename, GETPATH);
  276.         if (created_dir) {
  277.             if (QCOND2) {
  278.                 Info(slide, 0, ((char *)slide, "   creating: %s\n",
  279.                   G.filename));
  280.             }
  281.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  282.         }
  283.         return 2;   /* dir existed already; don't look for data to extract */
  284.     }
  285.  
  286.     if (*pathcomp == '\0') {
  287.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  288.           G.filename));
  289.         return 3;
  290.     }
  291.  
  292.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  293.     checkdir(__G__ G.filename, GETPATH);
  294.  
  295.     return error;
  296.  
  297. } /* end function mapname() */
  298.  
  299.  
  300.  
  301.  
  302.  
  303. /***********************/
  304. /* Function checkdir() */
  305. /***********************/
  306.  
  307. int checkdir(__G__ pathcomp, flag)
  308.     __GDEF
  309.     char *pathcomp;
  310.     int flag;
  311. /*
  312.  * returns:  1 - (on APPEND_NAME) truncated filename
  313.  *           2 - path doesn't exist, not allowed to create
  314.  *           3 - path doesn't exist, tried to create and failed; or
  315.  *               path exists and is not a directory, but is supposed to be
  316.  *           4 - path is too long
  317.  *          10 - can't allocate memory for filename buffers
  318.  */
  319. {
  320.     static int rootlen = 0;   /* length of rootpath */
  321.     static char *rootpath;    /* user's "extract-to" directory */
  322.     static char *buildpath;   /* full path (so far) to extracted file */
  323.     static char *end;         /* pointer to end of buildpath ('\0') */
  324.  
  325. #   define FN_MASK   7
  326. #   define FUNCTION  (flag & FN_MASK)
  327.  
  328.  
  329.  
  330. /*---------------------------------------------------------------------------
  331.     APPEND_DIR:  append the path component to the path being built and check
  332.     for its existence.  If doesn't exist and we are creating directories, do
  333.     so for this one; else signal success or error as appropriate.
  334.   ---------------------------------------------------------------------------*/
  335.  
  336.     if (FUNCTION == APPEND_DIR) {
  337.         int too_long = FALSE;
  338. #ifdef SHORT_NAMES
  339.         char *old_end = end;
  340. #endif
  341.  
  342.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  343.         while ((*end = *pathcomp++) != '\0')
  344.             ++end;
  345. #ifdef SHORT_NAMES   /* path components restricted to 14 chars, typically */
  346.         if ((end-old_end) > FILENAME_MAX)  /* GRR:  proper constant? */
  347.             *(end = old_end + FILENAME_MAX) = '\0';
  348. #endif
  349.  
  350.         /* GRR:  could do better check, see if overrunning buffer as we go:
  351.          * check end-buildpath after each append, set warning variable if
  352.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  353.          * appending.  Clear variable when begin new path. */
  354.  
  355.         if ((end-buildpath) > FILNAMSIZ-3)  /* need ':', one-char name, '\0' */
  356.             too_long = TRUE;                /* check if extracting directory? */
  357.         if (stat(buildpath, &G.statbuf)) {  /* path doesn't exist */
  358.             if (!G.create_dirs) { /* told not to create (freshening) */
  359.                 free(buildpath);
  360.                 return 2;         /* path doesn't exist:  nothing to do */
  361.             }
  362.             if (too_long) {
  363.                 Info(slide, 1, ((char *)slide,
  364.                   "checkdir error:  path too long: %s\n", buildpath));
  365.                 free(buildpath);
  366.                 return 4;         /* no room for filenames:  fatal */
  367.             }
  368.             if (MKDIR(buildpath) == -1) {   /* create the directory */
  369.                 Info(slide, 1, ((char *)slide,
  370.                   "checkdir error:  cannot create %s\n\
  371.                  unable to process %s.\n", buildpath, G.filename));
  372.                 free(buildpath);
  373.                 return 3;      /* path didn't exist, tried to create, failed */
  374.             }
  375.             created_dir = TRUE;
  376.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  377.             Info(slide, 1, ((char *)slide,
  378.               "checkdir error:  %s exists but is not directory\n\
  379.                  unable to process %s.\n", buildpath, G.filename));
  380.             free(buildpath);
  381.             return 3;          /* path existed but wasn't dir */
  382.         }
  383.         if (too_long) {
  384.             Info(slide, 1, ((char *)slide,
  385.               "checkdir error:  path too long: %s\n", buildpath));
  386.             free(buildpath);
  387.             return 4;         /* no room for filenames:  fatal */
  388.         }
  389.         *end++ = ':';
  390.         *end = '\0';
  391.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  392.         return 0;
  393.  
  394.     } /* end if (FUNCTION == APPEND_DIR) */
  395.  
  396. /*---------------------------------------------------------------------------
  397.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  398.     buildpath.
  399.   ---------------------------------------------------------------------------*/
  400.  
  401.     if (FUNCTION == GETPATH) {
  402.         strcpy(pathcomp, buildpath);
  403.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  404.         free(buildpath);
  405.         buildpath = end = (char *)NULL;
  406.         return 0;
  407.     }
  408.  
  409. /*---------------------------------------------------------------------------
  410.     APPEND_NAME:  assume the path component is the filename; append it and
  411.     return without checking for existence.
  412.   ---------------------------------------------------------------------------*/
  413.  
  414.     if (FUNCTION == APPEND_NAME) {
  415. #ifdef SHORT_NAMES
  416.         char *old_end = end;
  417. #endif
  418.  
  419.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  420.         while ((*end = *pathcomp++) != '\0') {
  421.             ++end;
  422. #ifdef SHORT_NAMES  /* truncate name at 14 characters, typically */
  423.             if ((end-old_end) > FILENAME_MAX)      /* GRR:  proper constant? */
  424.                 *(end = old_end + FILENAME_MAX) = '\0';
  425. #endif
  426.             if ((end-buildpath) >= FILNAMSIZ) {
  427.                 *--end = '\0';
  428.                 Info(slide, 0x201, ((char *)slide,
  429.                   "checkdir warning:  path too long; truncating\n\
  430.                    %s\n                -> %s\n", G.filename, buildpath));
  431.                 return 1;   /* filename truncated */
  432.             }
  433.         }
  434.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  435.         return 0;  /* could check for existence here, prompt for new name... */
  436.     }
  437.  
  438. /*---------------------------------------------------------------------------
  439.     INIT:  allocate and initialize buffer space for the file currently being
  440.     extracted.  If file was renamed with an absolute path, don't prepend the
  441.     extract-to path.
  442.   ---------------------------------------------------------------------------*/
  443.  
  444.     if (FUNCTION == INIT) {
  445.         Trace((stderr, "initializing buildpath to "));
  446.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+2)) ==
  447.             (char *)NULL)
  448.             return 10;
  449.         if ((rootlen > 0) && !renamed_fullpath) {
  450.             strcpy(buildpath, rootpath);
  451.             end = buildpath + rootlen;
  452.         } else {
  453.             *buildpath = '\0';
  454.             end = buildpath;
  455.         }
  456.         Trace((stderr, "[%s]\n", buildpath));
  457.         return 0;
  458.     }
  459.  
  460. /*---------------------------------------------------------------------------
  461.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  462.     sary; else assume it's a zipfile member and return.  This path segment
  463.     gets used in extracting all members from every zipfile specified on the
  464.     command line.
  465.   ---------------------------------------------------------------------------*/
  466.  
  467. #if (!defined(SFX) || defined(SFX_EXDIR))
  468.     if (FUNCTION == ROOT) {
  469.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  470.         if (pathcomp == (char *)NULL) {
  471.             rootlen = 0;
  472.             return 0;
  473.         }
  474.         if ((rootlen = strlen(pathcomp)) > 0) {
  475.             if (pathcomp[rootlen-1] == ':') {
  476.                 pathcomp[--rootlen] = '\0';
  477.             }
  478.             if (rootlen > 0 && (stat(pathcomp, &G.statbuf) ||
  479.                 !S_ISDIR(G.statbuf.st_mode)))       /* path does not exist */
  480.             {
  481.                 if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  482.                     rootlen = 0;
  483.                     return 2;   /* skip (or treat as stored file) */
  484.                 }
  485.                 /* create the directory (could add loop here to scan pathcomp
  486.                  * and create more than one level, but why really necessary?) */
  487.                 if (MKDIR(pathcomp) == -1) {
  488.                     Info(slide, 1, ((char *)slide,
  489.                       "checkdir:  cannot create extraction directory: %s\n",
  490.                       pathcomp));
  491.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  492.                     return 3;  /* failed:  file exists, or 2+ levels required */
  493.                 }
  494.             }
  495.             if ((rootpath = (char *)malloc(rootlen+2)) == (char *)NULL) {
  496.                 rootlen = 0;
  497.                 return 10;
  498.             }
  499.             strcpy(rootpath, pathcomp);
  500.             rootpath[rootlen++] = ':';
  501.             rootpath[rootlen] = '\0';
  502.             Trace((stderr, "rootpath now = [%s]\n", rootpath));
  503.         }
  504.         return 0;
  505.     }
  506. #endif /* !SFX || SFX_EXDIR */
  507.  
  508. /*---------------------------------------------------------------------------
  509.     END:  free rootpath, immediately prior to program exit.
  510.   ---------------------------------------------------------------------------*/
  511.  
  512.     if (FUNCTION == END) {
  513.         Trace((stderr, "freeing rootpath\n"));
  514.         if (rootlen > 0) {
  515.             free(rootpath);
  516.             rootlen = 0;
  517.         }
  518.         return 0;
  519.     }
  520.  
  521.     return 99;  /* should never reach */
  522.  
  523. } /* end function checkdir() */
  524.  
  525.  
  526.  
  527.  
  528.  
  529. /****************************/
  530. /* Function close_outfile() */
  531. /****************************/
  532.  
  533. void close_outfile(__G)    /* GRR: change to return PK-style warning level */
  534.     __GDEF
  535. {
  536. #ifdef USE_EF_UT_TIME
  537.     iztimes z_utime;
  538. #endif
  539.     long m_time;
  540.     DateTimeRec dtr;
  541.     ParamBlockRec pbr;
  542.     HParamBlockRec hpbr;
  543.     OSErr err;
  544.  
  545.  
  546.     if (fileno(G.outfile) == 1)  /* don't attempt to close or set time on stdout */
  547.         return;
  548.  
  549.     fclose(G.outfile);
  550.  
  551.     /*
  552.      * Macintosh bases all file modification times on the number of seconds
  553.      * elapsed since Jan 1, 1904, 00:00:00.  Therefore, to maintain
  554.      * compatibility with MS-DOS archives, which date from Jan 1, 1980,
  555.      * with NO relation to GMT, the following conversions must be made:
  556.      *      the Year (yr) must be incremented by 1980;
  557.      *      and converted to seconds using the Mac routine Date2Secs(),
  558.      *      almost similar in complexity to the Unix version :-)
  559.      *                                     J. Lee
  560.      */
  561.  
  562. #ifdef USE_EF_UT_TIME
  563.     if (G.extra_field &&
  564.         (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  565.                           G.lrec.last_mod_file_date, &z_utime, NULL)
  566.          & EB_UT_FL_MTIME))
  567.     {
  568.         struct tm *t;
  569.  
  570.         TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
  571.           z_utime.mtime));
  572.         t = localtime(&(z_utime.mtime));
  573.  
  574.         dtr.year = t->tm_year;
  575.         dtr.month = t->tm_mon + 1;
  576.         dtr.day = t->tm_mday;
  577.  
  578.         dtr.hour = t->tm_hour;
  579.         dtr.minute = t->tm_min;
  580.         dtr.second = t->tm_sec;
  581.     } else {
  582.         dtr.year = (((G.lrec.last_mod_file_date >> 9) & 0x7f) + 1980);
  583.         dtr.month = ((G.lrec.last_mod_file_date >> 5) & 0x0f);
  584.         dtr.day = (G.lrec.last_mod_file_date & 0x1f);
  585.  
  586.         dtr.hour = ((G.lrec.last_mod_file_time >> 11) & 0x1f);
  587.         dtr.minute = ((G.lrec.last_mod_file_time >> 5) & 0x3f);
  588.         dtr.second = ((G.lrec.last_mod_file_time & 0x1f) * 2);
  589.     }
  590. #else /* !USE_EF_UT_TIME */
  591.     dtr.year = (((G.lrec.last_mod_file_date >> 9) & 0x7f) + 1980);
  592.     dtr.month = ((G.lrec.last_mod_file_date >> 5) & 0x0f);
  593.     dtr.day = (G.lrec.last_mod_file_date & 0x1f);
  594.  
  595.     dtr.hour = ((G.lrec.last_mod_file_time >> 11) & 0x1f);
  596.     dtr.minute = ((G.lrec.last_mod_file_time >> 5) & 0x3f);
  597.     dtr.second = ((G.lrec.last_mod_file_time & 0x1f) * 2);
  598. #endif /* ?USE_EF_UT_TIME */
  599.  
  600.     Date2Secs(&dtr, (unsigned long *)&m_time);
  601.     c2pstr(G.filename);
  602.     if (G.HFSFlag) {
  603.         hpbr.fileParam.ioNamePtr = (StringPtr)G.filename;
  604.         hpbr.fileParam.ioVRefNum = G.gnVRefNum;
  605.         hpbr.fileParam.ioDirID = G.glDirID;
  606.         hpbr.fileParam.ioFDirIndex = 0;
  607.         err = PBHGetFInfoSync(&hpbr);
  608.         hpbr.fileParam.ioFlMdDat = m_time;
  609.         if ( !G.fMacZipped )
  610.             hpbr.fileParam.ioFlCrDat = m_time;
  611.         hpbr.fileParam.ioDirID = G.glDirID;
  612.         if (err == noErr)
  613.             err = PBHSetFInfoSync(&hpbr);
  614.         if (err != noErr)
  615.             printf("error:  cannot set the time for %s\n", G.filename);
  616.     } else {
  617.         pbr.fileParam.ioNamePtr = (StringPtr)G.filename;
  618.         pbr.fileParam.ioVRefNum = pbr.fileParam.ioFVersNum =
  619.           pbr.fileParam.ioFDirIndex = 0;
  620.         err = PBGetFInfoSync(&pbr);
  621.         pbr.fileParam.ioFlMdDat = pbr.fileParam.ioFlCrDat = m_time;
  622.         if (err == noErr)
  623.             err = PBSetFInfoSync(&pbr);
  624.         if (err != noErr)
  625.             printf("error:  cannot set the time for %s\n", G.filename);
  626.     }
  627.  
  628.     /* set read-only perms if needed */
  629.     if ((err == noErr) && G.pInfo->read_only) {
  630.         if (G.HFSFlag) {
  631.             hpbr.fileParam.ioNamePtr = (StringPtr)G.filename;
  632.             hpbr.fileParam.ioVRefNum = G.gnVRefNum;
  633.             hpbr.fileParam.ioDirID = G.glDirID;
  634.             err = PBHSetFLockSync(&hpbr);
  635.         } else
  636.             err = SetFLock((ConstStr255Param)G.filename, 0);
  637.     }
  638.     p2cstr((StringPtr)G.filename);
  639.  
  640. } /* end function close_outfile() */
  641.  
  642.  
  643.  
  644.  
  645.  
  646. #ifndef SFX
  647.  
  648. /************************/
  649. /*  Function version()  */
  650. /************************/
  651.  
  652. void version(__G)
  653.     __GDEF
  654. {
  655. #if 0
  656.     char buf[40];
  657. #endif
  658.  
  659.     sprintf((char *)slide, LoadFarString(CompiledWith),
  660.  
  661. #ifdef __GNUC__
  662.       "gcc ", __VERSION__,
  663. #else
  664. #  if 0
  665.       "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
  666. #  else
  667. #  ifdef __MWERKS__
  668.       "CodeWarrior C", "",
  669. #  else
  670. #  ifdef THINK_C
  671.       "Think C", "",
  672. #  else
  673. #  ifdef MPW
  674.       "MPW C", "",
  675. #  else
  676.       "unknown compiler", "",
  677. #  endif
  678. #  endif
  679. #  endif
  680. #  endif
  681. #endif
  682.  
  683.       "MacOS",
  684.  
  685. #if defined(foobar) || defined(FOOBAR)
  686.       " (Foo BAR)",    /* hardware or OS version */
  687. #else
  688.       "",
  689. #endif /* Foo BAR */
  690.  
  691. #ifdef __DATE__
  692.       " on ", __DATE__
  693. #else
  694.       "", ""
  695. #endif
  696.     );
  697.  
  698.     (*G.message)((zvoid *)&G, slide, (ulg)strlen((char *)slide), 0);
  699.  
  700. } /* end function version() */
  701.  
  702. #endif /* !SFX */
  703.  
  704.  
  705.  
  706.  
  707.  
  708. /************************/
  709. /* Function IsHFSDisk() */
  710. /************************/
  711.  
  712. static int IsHFSDisk(short wRefNum)
  713. {
  714.     /* get info about the specified volume */
  715.     if (G.HFSFlag == true) {
  716.         HParamBlockRec    hpbr;
  717.         Str255 temp;
  718.         short wErr;
  719.  
  720.         hpbr.volumeParam.ioCompletion = 0;
  721.         hpbr.volumeParam.ioNamePtr = temp;
  722.         hpbr.volumeParam.ioVRefNum = wRefNum;
  723.         hpbr.volumeParam.ioVolIndex = 0;
  724.         wErr = PBHGetVInfoSync(&hpbr);
  725.  
  726.         if (wErr == noErr && hpbr.volumeParam.ioVFSID == 0
  727.             && hpbr.volumeParam.ioVSigWord == 0x4244) {
  728.                 return true;
  729.         }
  730.     }
  731.  
  732.     return false;
  733. } /* IsHFSDisk */
  734.  
  735.  
  736.  
  737.  
  738.  
  739. /************************/
  740. /* Function MacFSTest() */
  741. /************************/
  742.  
  743. void MacFSTest(int vRefNum)
  744. {
  745.     Str255 st;
  746.  
  747.     /* is this machine running HFS file system? */
  748.     if (FSFCBLen <= 0) {
  749.         G.HFSFlag = false;
  750.     }
  751.     else
  752.     {
  753.         G.HFSFlag = true;
  754.     }
  755.  
  756.     /* get the file's volume reference number and directory ID */
  757.     if (G.HFSFlag == true) {
  758.         WDPBRec    wdpb;
  759.         OSErr err = noErr;
  760.  
  761.         if (vRefNum != 0) {
  762.             wdpb.ioCompletion = false;
  763.             wdpb.ioNamePtr = st;
  764.             wdpb.ioWDIndex = 0;
  765.             wdpb.ioVRefNum = vRefNum;
  766.             err = PBHGetVolSync(&wdpb);
  767.  
  768.             if (err == noErr) {
  769.                 wAppVRefNum = wdpb.ioWDVRefNum;
  770.                 lAppDirID = wdpb.ioWDDirID;
  771.             }
  772.         }
  773.  
  774.         /* is the disk we're using formatted for HFS? */
  775.         G.HFSFlag = IsHFSDisk(wAppVRefNum);
  776.     }
  777.  
  778.     return;
  779. } /* mactest */
  780.  
  781.  
  782.  
  783.  
  784.  
  785. /***********************/
  786. /* Function macmkdir() */
  787. /***********************/
  788.  
  789. int macmkdir(char *path, short nVRefNum, long lDirID)
  790. {
  791.     OSErr    err = -1;
  792.  
  793.     if (path != 0 && strlen(path)<256 && G.HFSFlag == true) {
  794.         HParamBlockRec    hpbr;
  795.         Str255    st;
  796.  
  797.         c2pstr(path);
  798.         if ((nVRefNum == 0) && (lDirID == 0))
  799.         {
  800.             hpbr.fileParam.ioNamePtr = st;
  801.             hpbr.fileParam.ioCompletion = NULL;
  802.             err = PBHGetVolSync((WDPBPtr)&hpbr);
  803.             nVRefNum = hpbr.wdParam.ioWDVRefNum;
  804.             lDirID = hpbr.wdParam.ioWDDirID;
  805.         }
  806.         else
  807.         {
  808.             err = noErr;
  809.         }
  810.         if (err == noErr) {
  811.             hpbr.fileParam.ioCompletion = NULL;
  812.             hpbr.fileParam.ioVRefNum = nVRefNum;
  813.             hpbr.fileParam.ioDirID = lDirID;
  814.             hpbr.fileParam.ioNamePtr = (StringPtr)path;
  815.             err = PBDirCreateSync(&hpbr);
  816.         }
  817.         p2cstr((StringPtr)path);
  818.     }
  819.  
  820.     return (int)err;
  821. } /* macmkdir */
  822.  
  823.  
  824.  
  825.  
  826.  
  827. /****************************/
  828. /* Function ResolveMacVol() */
  829. /****************************/
  830.  
  831. void ResolveMacVol(short nVRefNum, short *pnVRefNum, long *plDirID, StringPtr pst)
  832. {
  833.     if (G.HFSFlag)
  834.     {
  835.         WDPBRec  wdpbr;
  836.         Str255   st;
  837.         OSErr    err;
  838.  
  839.         wdpbr.ioCompletion = (IOCompletionUPP)NULL;
  840.         wdpbr.ioNamePtr = st;
  841.         wdpbr.ioVRefNum = nVRefNum;
  842.         wdpbr.ioWDIndex = 0;
  843.         wdpbr.ioWDProcID = 0;
  844.         wdpbr.ioWDVRefNum = 0;
  845.         err = PBGetWDInfoSync( &wdpbr );
  846.         if ( err == noErr )
  847.         {
  848.             if (pnVRefNum)
  849.                 *pnVRefNum = wdpbr.ioWDVRefNum;
  850.             if (plDirID)
  851.                 *plDirID = wdpbr.ioWDDirID;
  852.             if (pst)
  853.                 BlockMove( st, pst, st[0]+1 );
  854.         }
  855.     }
  856.     else
  857.     {
  858.         if (pnVRefNum)
  859.             *pnVRefNum = nVRefNum;
  860.         if (plDirID)
  861.             *plDirID = 0;
  862.         if (pst)
  863.             *pst = 0;
  864.     }
  865. }
  866.  
  867.  
  868.  
  869.  
  870.  
  871. /**********************/
  872. /* Function macopen() */
  873. /**********************/
  874.  
  875. short macopen(char *sz, short nFlags, short nVRefNum, long lDirID)
  876. {
  877.     OSErr   err;
  878.     Str255  st;
  879.     char    chPerms = (!nFlags) ? fsRdPerm : fsRdWrPerm;
  880.     short   nFRefNum;
  881.  
  882.     c2pstr( sz );
  883.     BlockMove( sz, st, sz[0]+1 );
  884.     p2cstr( (StringPtr)sz );
  885.     if (G.HFSFlag)
  886.     {
  887.         if (nFlags > 1)
  888.             err = HOpenRF( nVRefNum, lDirID, st, chPerms, &nFRefNum);
  889.         else
  890.             err = HOpen( nVRefNum, lDirID, st, chPerms, &nFRefNum);
  891.     }
  892.     else
  893.     {
  894.         /*
  895.          * Have to use PBxxx style calls since the high level
  896.          * versions don't support specifying permissions
  897.          */
  898.         ParamBlockRec    pbr;
  899.  
  900.         pbr.ioParam.ioNamePtr = st;
  901.         pbr.ioParam.ioVRefNum = G.gnVRefNum;
  902.         pbr.ioParam.ioVersNum = 0;
  903.         pbr.ioParam.ioPermssn = chPerms;
  904.         pbr.ioParam.ioMisc = 0;
  905.         if (nFlags >1)
  906.             err = PBOpenRFSync( &pbr );
  907.         else
  908.             err = PBOpenSync( &pbr );
  909.         nFRefNum = pbr.ioParam.ioRefNum;
  910.     }
  911.     if ( err || (nFRefNum == 1) )
  912.         return -1;
  913.     else {
  914.         if ( nFlags )
  915.             SetEOF( nFRefNum, 0 );
  916.         return nFRefNum;
  917.     }
  918. }
  919.  
  920.  
  921.  
  922.  
  923.  
  924. /***********************/
  925. /* Function macfopen() */
  926. /***********************/
  927.  
  928. FILE *macfopen(char *filename, char *mode, short nVRefNum, long lDirID)
  929. {
  930.     short outfd, fDataFork=TRUE;
  931.     MACINFO mi;
  932.     OSErr err;
  933.  
  934.     G.fMacZipped = FALSE;
  935.     c2pstr(G.filename);
  936.     if (G.extra_field &&
  937.         (G.lrec.extra_field_length > sizeof(MACINFOMIN)) &&
  938.         (G.lrec.extra_field_length <= sizeof(MACINFO)))
  939.     {
  940.         BlockMove(G.extra_field, &mi, G.lrec.extra_field_length);
  941.         if ((makeword((uch *)&mi.header) == 1992) &&
  942.             (makeword((uch *)&mi.data) ==
  943.                 G.lrec.extra_field_length - sizeof(ZIP_EXTRA_HEADER)) &&
  944.             (mi.signature == 'JLEE'))
  945.         {
  946.             G.gostCreator = mi.finfo.fdCreator;
  947.             G.gostType = mi.finfo.fdType;
  948.             fDataFork = (mi.flags & 1) ? TRUE : FALSE;
  949.             G.fMacZipped = true;
  950.             /* If it was Zipped w/Mac version, the filename has either */
  951.             /* a 'd' or 'r' appended.  Remove the d/r when unzipping */
  952.             G.filename[0]-=1;
  953.         }
  954.     }
  955.     if (!G.fMacZipped) {
  956.         if (!G.aflag)
  957.             G.gostType = G.gostCreator = '\?\?\?\?';
  958.         else {
  959.             G.gostCreator = CREATOR;
  960.             G.gostType = 'TEXT';
  961.         }
  962.     }
  963.     p2cstr((StringPtr)G.filename);
  964.  
  965.     if ((outfd = creat(G.filename, 0)) != -1) {
  966.         if (G.fMacZipped) {
  967.             c2pstr(G.filename);
  968.             if (G.HFSFlag) {
  969.                 HParamBlockRec   hpbr;
  970.  
  971.                 hpbr.fileParam.ioNamePtr = (StringPtr)G.filename;
  972.                 hpbr.fileParam.ioVRefNum = G.gnVRefNum;
  973.                 /* GRR:  what about mi.lDirID? never used? */
  974.                 hpbr.fileParam.ioDirID = G.glDirID;
  975.                 hpbr.fileParam.ioFlFndrInfo = mi.finfo;
  976.                 hpbr.fileParam.ioFlCrDat = mi.lCrDat;
  977.                 hpbr.fileParam.ioFlMdDat = mi.lMdDat;
  978.                 err = PBHSetFInfoSync(&hpbr);
  979.             } else {
  980.                 err = SetFInfo((StringPtr)G.filename , 0, &mi.finfo);
  981.             }
  982.             p2cstr((StringPtr)G.filename);
  983.         }
  984.         outfd = open(G.filename, (fDataFork) ? 1 : 2);
  985.     }
  986.  
  987.     if (outfd == -1)
  988.         return NULL;
  989.     else
  990.         return (FILE *)outfd;
  991. }
  992.  
  993.  
  994.  
  995.  
  996.  
  997. /***********************/
  998. /* Function maccreat() */
  999. /***********************/
  1000.  
  1001. short maccreat(char *sz, short nVRefNum, long lDirID, OSType ostCreator, OSType ostType)
  1002. {
  1003.     OSErr   err;
  1004.     Str255  st;
  1005.     FInfo   fi;
  1006.  
  1007.     c2pstr( sz );
  1008.     BlockMove( sz, st, sz[0]+1 );
  1009.     p2cstr( (StringPtr)sz );
  1010.     if (G.HFSFlag)
  1011.     {
  1012.         err = HGetFInfo( nVRefNum, lDirID, st, &fi );
  1013.         if (err == fnfErr)
  1014.             err = HCreate( nVRefNum, lDirID, st, ostCreator, ostType );
  1015.         else if (err == noErr)
  1016.         {
  1017.             err = HRstFLock( nVRefNum, lDirID, st );
  1018.             if ( err == noErr ) {
  1019.                 fi.fdCreator = ostCreator;
  1020.                 fi.fdType = ostType;
  1021.                 err = HSetFInfo( nVRefNum, lDirID, st, &fi );
  1022.             }
  1023.         }
  1024.     }
  1025.     else
  1026.     {
  1027.         err = GetFInfo( st, nVRefNum, &fi );
  1028.         if (err == fnfErr)
  1029.             err = Create( st, nVRefNum, ostCreator, ostType );
  1030.         else if (err == noErr)
  1031.         {
  1032.             err = RstFLock( st, nVRefNum );
  1033.             if ( err == noErr ) {
  1034.                 fi.fdCreator = ostCreator;
  1035.                 fi.fdType = ostType;
  1036.                 err = SetFInfo( st, nVRefNum, &fi );
  1037.             }
  1038.         }
  1039.     }
  1040.     if (err == noErr)
  1041.         return noErr;
  1042.     else
  1043.         return -1;
  1044. }
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050. /**********************/
  1051. /* Function macread() */
  1052. /**********************/
  1053.  
  1054. short macread(short nFRefNum, char *pb, unsigned cb)
  1055. {
  1056.     long    lcb = cb;
  1057.  
  1058.     (void)FSRead( nFRefNum, &lcb, pb );
  1059.  
  1060.     return (short)lcb;
  1061. }
  1062.  
  1063.  
  1064.  
  1065.  
  1066.  
  1067. /***********************/
  1068. /* Function macwrite() */
  1069. /***********************/
  1070.  
  1071. long macwrite(short nFRefNum, char *pb, unsigned cb)
  1072. {
  1073.     long    lcb = cb;
  1074.  
  1075. #ifndef MPW
  1076.     if ( (nFRefNum == 1) || (nFRefNum == 2) )
  1077.         screenDump( pb, lcb );
  1078.     else
  1079. #endif
  1080.         (void)FSWrite( nFRefNum, &lcb, pb );
  1081.  
  1082.     return (long)lcb;
  1083. }
  1084.  
  1085.  
  1086.  
  1087.  
  1088.  
  1089. /***********************/
  1090. /* Function macclose() */
  1091. /***********************/
  1092.  
  1093. short macclose(short nFRefNum)
  1094. {
  1095.     return FSClose( nFRefNum );
  1096. }
  1097.  
  1098.  
  1099.  
  1100.  
  1101.  
  1102. /***********************/
  1103. /* Function maclseek() */
  1104. /***********************/
  1105.  
  1106. long maclseek(short nFRefNum, long lib, short nMode)
  1107. {
  1108.     ParamBlockRec   pbr;
  1109.  
  1110.     if (nMode == SEEK_SET)
  1111.         nMode = fsFromStart;
  1112.     else if (nMode == SEEK_CUR)
  1113.         nMode = fsFromMark;
  1114.     else if (nMode == SEEK_END)
  1115.         nMode = fsFromLEOF;
  1116.     pbr.ioParam.ioRefNum = nFRefNum;
  1117.     pbr.ioParam.ioPosMode = nMode;
  1118.     pbr.ioParam.ioPosOffset = lib;
  1119.     (void)PBSetFPosSync(&pbr);
  1120.     return pbr.ioParam.ioPosOffset;
  1121. }
  1122.  
  1123.  
  1124.  
  1125.  
  1126. /***********************/
  1127. /* Function macgetch() */
  1128. /***********************/
  1129.  
  1130. int macgetch(void)
  1131. {
  1132.     WindowPtr whichWindow;
  1133.     EventRecord theEvent;
  1134.     char c;                     /* one-byte buffer for read() to use */
  1135.  
  1136.     do {
  1137.         SystemTask();
  1138.         if (!GetNextEvent(everyEvent, &theEvent))
  1139.             theEvent.what = nullEvent;
  1140.         else {
  1141.             switch (theEvent.what) {
  1142.             case keyDown:
  1143.                 c = theEvent.message & charCodeMask;
  1144.                 break;
  1145.             case mouseDown:
  1146.                 if (FindWindow(theEvent.where, &whichWindow) ==
  1147.                     inSysWindow)
  1148.                     SystemClick(&theEvent, whichWindow);
  1149.                 break;
  1150.             case updateEvt:
  1151.                 screenUpdate((WindowPtr)theEvent.message);
  1152.                 break;
  1153.             }
  1154.         }
  1155.     } while (theEvent.what != keyDown);
  1156.  
  1157.     return (int)c;
  1158. }
  1159.  
  1160. #endif /* MACOS */
  1161.