home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / mpwtools.cpt / misc src / mtar.c < prev    next >
Encoding:
Text File  |  1991-01-02  |  11.3 KB  |  440 lines

  1. /* Copyright 1988, Gail Zacharias.  All rights reserved.
  2.  * Permission is hereby granted to copy, reproduce, redistribute or
  3.  * otherwise use this software provided there is no monetary profit
  4.  * gained specifically from its use or reproduction, it is not sold,
  5.  * rented, traded or otherwise marketed, and this copyright notice 
  6.  * and the software version number is included prominently in any copy
  7.  * made.
  8.  * This is mtar version 1.0.
  9.  *
  10.  * Send comments, suggestions, bug reports (not bloody likely), feature
  11.  * requests, etc. to gz@entity.com.
  12.  *
  13.  * Modified by Sak W (sw@network-analysis-ltd.co.uk) to compile with
  14.  * MPW 3.2 (mtar version 1.0.1).
  15.  */
  16.  
  17. char *Program, *Version = "1.0.1";
  18.  
  19. #include <stdio.h>
  20. #include <files.h>
  21. #include <errors.h>
  22. #include <errno.h>
  23. #include <ioctl.h>
  24.  
  25. StringPtr c2pstr();
  26. char *strchr(), *strcpy(), *strncpy(), *p2cstr();
  27.  
  28. /* Sak W mod */
  29. #define TEXT 'TEXT'
  30.  
  31. /* The do {} while(0) is for syntactic reasons. MPW C will optimize it out. */
  32. #define mcopy(dest, src, len) \
  33.   do { char *_dp = (char *)(dest), *_sp = (char *)(src); \
  34.        int _i = (len); \
  35.        while (--_i>=0) *_dp++ = *_sp++; \
  36.   } while(0)
  37.  
  38. #define fillmem(dest, ch, len) \
  39.   do { char *_dp = (char *)(dest); \
  40.        int _i = (len); \
  41.        while (--_i>=0) *_dp++ = (ch); \
  42.   } while (0)
  43.  
  44. struct {
  45.     char name[100];
  46.     char mode[8];
  47.     char uid[8];
  48.     char gid[8];
  49.     char size[12];
  50.     char mtime[12];
  51.     char chksum[8];
  52.     char linkflag;
  53.     char linkname[100];
  54.     char magic[8];
  55.     char uname[32];
  56.     char gname[32];
  57.     char devmajor[8];
  58.     char devminor[8];
  59.     char fill[167];
  60. } tarh;
  61.  
  62. #define tarsz(n)    (((n)+511L) & -512L)
  63.  
  64. struct {
  65.     unsigned char nlen;
  66.     char name[63];
  67.     FInfo finfo;
  68.     char protected;
  69.     char zero;
  70.     long dflen;
  71.     long rflen;
  72.     long cdate;
  73.     long mdate;
  74. /*  char unused[29]; */
  75. } macbinh;
  76.  
  77. #define macbinsz(n)    (((n)+127L) & -128L)
  78.  
  79. static HFileInfo statb;
  80.  
  81. int binary = 0,
  82.     dataonly = 0,
  83.     verbose = 0;
  84.  
  85. int dirmode = 0777,
  86.     filemode = 0666;
  87.  
  88. char *uname = "root",
  89.      *gname = "group";
  90.  
  91. FILE *tarf = (FILE *) NULL;
  92.  
  93. #define writeblock(p,len)    fwrite((p), 1, (len), tarf)
  94.  
  95. /* Unfortunately, the Mac keeps only local time, so this will be off by
  96.    the time zone... */
  97. #define UNIXTIME    2082844800L  /* Jan 1, 1970 00:00:00 */
  98.  
  99.  
  100. main (argc, argv)
  101.   char **argv;
  102. {
  103.   char *defalt[2];
  104.   Program = argv[0];
  105.   while (--argc > 0 && **++argv == '-') {
  106.     char *argp = &argv[0][1];
  107.     do switch (*argp++) {
  108.       case 'b': dataonly = 1; binary = 1; break;
  109.       case 'u': dataonly = 1; binary = 0; break;
  110.       case 'v': verbose = 1; break;
  111.       case 'o': if (*argp == '\0') {
  112.                   if (--argc == 0) goto badarg;
  113.           argp = *++argv;
  114.         }
  115.         uname = argp;
  116.         argp = "";
  117.         break;
  118.       case 'g': if (*argp == '\0') {
  119.                   if (--argc == 0) goto badarg;
  120.           argp = *++argv;
  121.         }
  122.         gname = argp;
  123.         argp = "";
  124.         break;
  125.       case 'f':    if (tarf) goto badarg;
  126.         if (*argp == '\0') {
  127.                   if (--argc == 0) goto badarg;
  128.           argp = *++argv;
  129.         }
  130.         if (!strcmp(argp, "-")) tarf = stdout;
  131.         else if (!(tarf = fopen(argp, "w")))
  132.            fatal("Cannot open %s for writing.", argp);
  133.         argp = "";
  134.         break;
  135.       default: goto badarg;
  136.     } while (*argp);
  137.   }
  138.   if (argc <= 0) {
  139.     defalt[0] = ":";
  140.     defalt[1] = (char *) NULL;
  141.     argv = defalt;
  142.   }
  143.   if (!tarf) tarf = stdout;
  144.   tarfiles(argv);
  145.   fflush(tarf);
  146.   if (ferror(tarf)) {
  147.      if (errno == ENOSPC) fatal("Out of disk space");
  148.      else fatal("Write error");
  149.   }
  150.   if (tarf != stdout) fclose(tarf);
  151.   return 0;
  152.  
  153. badarg:
  154.   fprintf(stderr, "mtar Version %s, by gz@entity.com.  Usage: \n", Version);
  155.   fprintf(stderr, "%s [-vbu] [-o uname] [-g gname] [-f tarfile] files and dirs...\n", Program);
  156.   fprintf(stderr, "Creates a tar archive of the named files.\n\
  157.  -v = verbose: list names of files as store them.\n\
  158.  -b = store only data forks of files.\n\
  159.  -u = like -b, but convert CR to LF in TEXT files.\n\
  160.  -o = set unix owner of files to uname (default 'root').\n");
  161.   fprintf(stderr, " -g = set unix group of files to gname (default 'group').\n\
  162.  -f tarfile = write output to tarfile (instead of standard output).\n\
  163.  -H = show this help message.\n\
  164. If neither -u nor -b flags are given, stores both forks of each file (as well\n\
  165. as the mac name, type, creator and dates) using macbinary format.\n\
  166. If no files are specified, tars the current default directory.\n\n\
  167. This is freeware.  If you paid money for this program, you got ripped off.\n");
  168.   return 2;
  169. }
  170.  
  171. tarfiles (files)
  172.   char **files;
  173. {
  174.   while (*files) {
  175.     if (strlen(*files) >= 100) nametoolong(*files);
  176.     statf(*files);
  177.     if (statb.ioFlAttrib & ioDirMask) {
  178.       statb.ioVRefNum = getvrefnum(*files);
  179.       tardir(*files);
  180.     }
  181.     else {
  182.       char *cp = *files+strlen(*files);
  183.       while (cp != *files && cp[-1] != ':') --cp;
  184.       if ((macbinh.nlen = strlen(cp)) >= 64) nametoolong(*files);
  185.       strcpy(macbinh.name, cp);
  186.       tarfile(*files);
  187.     }
  188.     ++files;
  189.   }
  190.   fillmem(&tarh, 0, 512);
  191.   writeblock(&tarh, 512);
  192. }
  193.  
  194. tardir (dname)
  195.   char *dname;
  196. {
  197.   char name[256];
  198.   long dirid = statb.ioDirID;
  199.   int index = 0;
  200.   int dlen = strlen(dname);
  201.   tarheader(dname, 0);
  202.   if (strchr(dname, ':')) strcpy(name, dname);
  203.   else {
  204.     name[0] = ':';
  205.     strcpy(&name[1], dname);
  206.     dlen++;
  207.   }
  208.   if (name[dlen-1] != ':') name[dlen++] = ':';
  209.   while (1) {
  210.     statb.ioFDirIndex = ++index;
  211.     statb.ioDirID = dirid;
  212.     statb.ioNamePtr = &macbinh.nlen;
  213.     if (PBGetCatInfo((CInfoPBPtr)&statb, 0) || statb.ioResult) {
  214.       if (statb.ioResult != fnfErr) pbsyserr(&statb);
  215.       break;
  216.     }
  217.     strncpy(&name[dlen], macbinh.name, macbinh.nlen);
  218.     name[dlen+macbinh.nlen] = '\0';
  219.     if (macbinh.nlen >= 64 || (dlen + macbinh.nlen) >= 100) nametoolong(name);
  220.     if (statb.ioFlAttrib & ioDirMask) tardir(name);
  221.     else tarfile(name);
  222.   }
  223. }
  224.  
  225. tarfile (fname)
  226.   char *fname;
  227. {
  228.   if (statb.ioFRefNum) {
  229.     long refnum;
  230.     if (ioctl(fileno(tarf), FIOREFNUM, &refnum) >= 0 && refnum == (long) statb.ioFRefNum)
  231.        return 0;
  232.     fprintf(stderr, "%s: Warning: Somebody has \"%s\" open. You may lose.\n", Program, fname);
  233.   }
  234.   if (dataonly) tardata(fname);
  235.   else tarmacbin(fname);
  236. }
  237.  
  238. tardata (fname)
  239.   char *fname;
  240. {
  241.   IOParam pb;
  242.   tarheader(fname, statb.ioFlLgLen);
  243.   if (verbose) fprintf(stderr, "X %s (%ld bytes)\n", tarh.name, statb.ioFlLgLen);
  244.   pb.ioVRefNum = 0;
  245.   pb.ioVersNum = 0;
  246.   pb.ioPermssn = fsRdPerm;
  247.   pb.ioMisc = 0;
  248.   pb.ioNamePtr = c2pstr(fname);
  249.   if (PBOpen((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
  250.   writefork(&pb, statb.ioFlLgLen, 0);
  251.   p2cstr(fname);
  252. }
  253.  
  254. tarmacbin(fname)
  255.   char *fname;
  256. {
  257.   IOParam pb;
  258.   long fsize = macbinsz(statb.ioFlLgLen)+macbinsz(statb.ioFlRLgLen)+128L;
  259.   tarheader(fname, fsize);
  260.   if (verbose) 
  261.    fprintf(stderr, "Macbin %s (%ld+%ld bytes)\n",
  262.                tarh.name, statb.ioFlLgLen, statb.ioFlRLgLen);
  263.   macbinheader();
  264.   pb.ioVRefNum = 0;
  265.   pb.ioVersNum = 0;
  266.   pb.ioPermssn = fsRdPerm;
  267.   pb.ioMisc = 0;
  268.   pb.ioNamePtr = c2pstr(fname);
  269.   if (PBOpen((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
  270.   writefork(&pb, statb.ioFlLgLen, 1);
  271.   pb.ioVRefNum = 0;
  272.   pb.ioVersNum = 0;
  273.   pb.ioPermssn = fsRdPerm;
  274.   pb.ioMisc = 0;
  275.   if (PBOpenRF((ParmBlkPtr)&pb, 0)) pbsyserr(&pb);
  276.   writefork(&pb, statb.ioFlRLgLen, 1);
  277.   if (fsize & 511L) writeblock(&tarh, 512 - (fsize & 511L));
  278.   p2cstr(fname);
  279. }
  280.  
  281. macbinheader()
  282. {
  283.   fillmem(&macbinh.name[macbinh.nlen], 0, 63-macbinh.nlen);
  284.   mcopy(&macbinh.finfo, &statb.ioFlFndrInfo, sizeof(FInfo));
  285.   macbinh.protected = 0;
  286.   macbinh.zero = 0;
  287.   macbinh.dflen = statb.ioFlLgLen;
  288.   macbinh.rflen = statb.ioFlRLgLen;
  289.   macbinh.cdate = statb.ioFlCrDat;
  290.   macbinh.mdate = statb.ioFlMdDat;
  291.   fillmem(&tarh, 0, 128);
  292.   mcopy(&tarh.name[1], &macbinh, sizeof(macbinh));
  293.   writeblock(&tarh, 128);
  294. }
  295.  
  296. writefork (pb, fsize, macbinp)
  297.   IOParam *pb;
  298.   long fsize;
  299. {
  300.   int blocksz = (macbinp ? 128 : 512);
  301.   pb->ioPosMode = fsAtMark;
  302.   pb->ioBuffer = (Ptr)&tarh;
  303.   pb->ioReqCount = blocksz;
  304.   while (fsize) {
  305.     if (fsize < pb->ioReqCount) pb->ioReqCount = fsize;
  306.     fsize -= pb->ioReqCount;
  307.     if (PBRead((ParmBlkPtr)pb, 0) || pb->ioActCount != pb->ioReqCount) {
  308.       int err = pb->ioResult;
  309.       (void) PBClose((ParmBlkPtr)pb, 0);
  310.       pb->ioResult = err;
  311.       pbsyserr(pb);
  312.     }
  313.     if (!macbinp && !binary && statb.ioFlFndrInfo.fdType == TEXT) {
  314.       char *cp = pb->ioBuffer;
  315.       int i = pb->ioActCount;
  316.       while (i) {
  317.         if (*cp == ('M'-'@')) *cp = ('J'-'@');
  318.     --i, ++cp;
  319.       }
  320.     }
  321.     writeblock(pb->ioBuffer, blocksz);
  322.   }
  323.   if (PBClose((ParmBlkPtr)pb, 0)) pbsyserr(pb);
  324. }
  325.  
  326. tarheader (fname, fsize)
  327.   char *fname;
  328.   long fsize;
  329. {
  330.   int chksum = 0, i;
  331.   fillmem(&tarh, 0, 512);
  332.   mac2unix(tarh.name, fname);
  333.   if (statb.ioFlAttrib & ioDirMask) 
  334.     if (tarh.name[strlen(tarh.name)-1] != '/')
  335.       tarh.name[strlen(tarh.name)] = '/';
  336.   numstr(tarh.mode, ((statb.ioFlAttrib & ioDirMask) ? dirmode : filemode), 8);
  337.   numstr(tarh.uid, 0, 8);
  338.   numstr(tarh.gid, 0, 8);
  339.   numstr(tarh.size, fsize, 12);
  340.   numstr(tarh.mtime, statb.ioFlMdDat - UNIXTIME, 12);
  341.   fillmem(tarh.chksum, ' ', 8);
  342.   tarh.linkflag = ((statb.ioFlAttrib & ioDirMask) ? '5' : '0');
  343.   strcpy(tarh.magic, "ustar  ");
  344.   strcpy(tarh.uname, uname);
  345.   strcpy(tarh.gname, gname);
  346.   for(i=0; i<512; ++i) chksum += (unsigned char)tarh.name[i];
  347.   numstr(tarh.chksum, chksum, 8);
  348.   writeblock(&tarh, 512);
  349. }
  350.  
  351. /* Don't allow absolute names.   "HD:foo:bar" becomes "./foo/bar" */
  352. mac2unix(uname, mname)
  353.  char *uname, *mname;
  354. {
  355.   char *dp = uname, *cp;
  356.   if (cp = strchr(mname, ':')) *dp++ = '.', *dp++ = '/', ++cp;
  357.   else cp = mname;
  358.   while (1) {
  359.     while (*cp == ':') *dp++ = '.', *dp++ = '.', *dp++ = '/', ++cp;
  360.     while (*cp && *cp != ':') if ((*dp++ = *cp++) == '/') dp[-1] = ':';
  361.     if (!*cp++) break;
  362.     *dp++ = '/';
  363.   }
  364.   for (dp = uname; *dp; ++dp) if (*dp == ' ') *dp = '_';
  365.   if (strlen(uname) >= 100) nametoolong(mname);
  366. }
  367.  
  368. numstr (p, num, count)
  369.   char *p;
  370. {
  371.   p[--count] = '\0';
  372.   if (count != 11) p[--count] = ' ';
  373.   if (num < 0) {
  374.     *p++ = '-';
  375.     --count;
  376.     num = -num;
  377.   }
  378.   while (count) {
  379.     p[--count] = '0' + (num & 7);
  380.     num >>= 3;
  381.   }
  382. }
  383.  
  384. statf (fname)
  385.   char *fname;
  386. {
  387.   char name[256];
  388.   statb.ioNamePtr = c2pstr(strcpy(name, fname));
  389.   statb.ioFVersNum = 0;
  390.   statb.ioVRefNum = 0;
  391.   statb.ioFDirIndex = 0;
  392.   statb.ioDirID = 0;
  393.   if (PBGetCatInfo((CInfoPBPtr)&statb, 0) || statb.ioResult) pbsyserr(&statb);
  394.   statb.ioNamePtr = NULL;
  395. }
  396.  
  397. getvrefnum (fname)
  398.   char *fname;
  399. {
  400.   HVolumeParam pb;
  401.   char name[256];
  402.   pb.ioNamePtr = c2pstr(strcpy(name, fname));
  403.   pb.ioVRefNum = 0;
  404.   pb.ioVolIndex = 0;
  405.   if (PBHGetVInfo((HParmBlkPtr)&pb, 0) || pb.ioResult) pbsyserr(&pb);
  406.   return pb.ioVRefNum;
  407. }
  408.  
  409. nametoolong (name)
  410.   char *name;
  411. {
  412.   fatal("\"%s\" - name too long", name);
  413. }
  414.  
  415. pbsyserr (pb)
  416.   IOParam *pb;
  417. {
  418.   int err = pb->ioResult;
  419.   char *name = pb->ioNamePtr;
  420.   p2cstr(name);
  421.   if (err == fnfErr) fatal("%s - File not found", name);
  422.   else if (err == nsvErr) fatal("%s - No such volume", name);
  423.   else if (err == tmfoErr) fatal("%s - Too many files open", name);
  424.   else if (err == permErr) fatal("%s - Permissions error", name);
  425.   else if (err == dupFNErr) fatal("%s - Duplicate filename", name);
  426.   else if (err == eofErr) fatal("%s - Premature end of file", name);
  427.   else fatal("%s - Error #%d", name, err);
  428. }
  429.  
  430. fatal(fmt, arg1, arg2, arg3, arg4, arg5, arg6)
  431.   char *fmt, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
  432. {
  433.   if (tarf && tarf != stdout) fclose(tarf);
  434.   fprintf(stderr, "%s: ", Program);
  435.   fprintf(stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
  436.   fprintf(stderr, "\n");
  437.   exit(2);
  438. }
  439.  
  440.