home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / suntar1.cpt / tar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-13  |  45.7 KB  |  1,554 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 was mtar version 1.0.
  9.  *
  10.  */
  11.  
  12. /* the original mtar program was then altered to become part of suntar: 
  13. */
  14.  
  15. /*******************************************************************************\
  16.  
  17. tar writing module
  18.  
  19. part of suntar, ⌐1991-92 Sauro & Gabriele Speranza
  20.  
  21. This program is public domain, feel free to use it or part of it for anything
  22.  
  23. \*******************************************************************************/
  24.  
  25.  
  26. /*
  27. comments in the text explain which routines were added for suntar by us and
  28. which ones are from mtar, but most of the latter were modified more or less 
  29. heavily by us
  30. */
  31.  
  32. #include "system7.h"
  33. #include "PB_sync.h"
  34. #include "antiglue.h"
  35.  
  36. #include <string.h>
  37. /*#include <FileMgr.h>
  38. #include <OSUtil.h>
  39. #include <HFS.h>*/
  40.  
  41. #include "suntar.h"
  42.  
  43. #include "windows.h"
  44.  
  45.  
  46. void fillmem(dest, ch, len)
  47. register char*dest;
  48. register char ch;
  49. register int len;
  50. {
  51.     while (--len>=0) *dest++ = ch;
  52. }
  53.  
  54.  
  55. #define tarsz(n)    (((n)+511L) & -512L)
  56. #define macbinsz(n)    (((n)+127L) & -128L)
  57.  
  58. static HFileInfo statb;
  59.  
  60. static Boolean binary = false, 
  61.     dataonly = false;
  62.  
  63. #define    dirmode 0777
  64. #define    filemode 0666
  65.  
  66. char *uname,
  67.      *gname;
  68.  
  69. /* Unfortunately, the Mac keeps only local time, so this will be off by
  70.    the time zone... */
  71. #define UNIXTIME    2082844800L  /* Jan 1, 1970 00:00:00 */
  72.  
  73. /*
  74. main (argc, argv)
  75.   char **argv;
  76. {
  77.   fprintf(stderr, 
  78. "This is freeware.  If you paid money for this program, you got ripped off.\n");
  79. }
  80. */
  81. /*********************** start of routines by Speranza **************************/
  82.  
  83. /* dovrÿ riorganizzare un po' le cose: ha senso che, come in untar, ci siano due
  84. modi di chiamare le routine di output: uno per quelli che sanno che esistono i settori
  85. (scrittura header) e uno per quelli che preferiscono vedere un flusso continuo di bytes:
  86. ovviamente ci vuole una routine per riallinearsi al settore dopo una serie di
  87. chiamate del secondo gruppo, ma questa esiste giê, svuota_buffer
  88. -- Beware: the disk handling routines are organized with an external interface
  89. which looks like a continuous stream of bytes (they trasparently handle volume
  90. headers and disk swapping) but in several places the caller must know about
  91. the internal behaviour, about sector and disk numbers (e.g., it must know in
  92. which sector of which disk a file header was written). That makes things a
  93. little tricky, less comprehensible than the untar module where the low level
  94. routines are less clever
  95. */
  96.  
  97. #define ALIAS_BIT 0x8000
  98.  
  99. static sector_t last_header,        /* il settore contenente l'ultimo header di file
  100.                         -- the sector containing the last file header */
  101.     last_sector;    /* il settore vuoto che sarê scritto alla prossima occasione;
  102.                     nota che in questo modulo Å gestito in modo un po' "sotterraneo":
  103.                     eccetto che per cose strane (header speciali, che non riguardano
  104.                     le normali routines) scrivi_settori viene sempre chiamata col
  105.                     tramite di write_next_sector (che si occupa di gestire un eventuale
  106.                     cambio disco: bisogna chiedergli comunque un settore a partire da 0,
  107.                     sa lei che a causa degli header di disco poi non Å detto si vada
  108.                     al 0, ed Å impossibile per bar), ma last_sector va incrementata
  109.                     subito dopo tale chiamata, col che appunto Å sempre il prossimo
  110.                     settore. Attenzione che write_block butta fuori quando ha il buffer
  111.                     pieno (cioÅ non lo lascia con 512 bytes, lo svuota subito) 
  112.                     -- next sector to be written: after a call to write_next_sector
  113.                     which fills a sector, it was already incremented so it points
  114.                     to the next sector (or beyond the end of disk)
  115.                     */
  116. static short more_space;    /* number of free bytes in buffer, that is 512 - number of 
  117.                     bytes currently in the buffer */
  118. static int path_len=0;    /* nell'archivio scrivo solo l'ultima parte del pathname
  119.                         completo che invece uso per aprire i files
  120.                         -- The full path name is used to open files, but the stored name 
  121.                         in the archive is only the last part of it, the partial path
  122.                         from the folder which was selected by the user.
  123.                         */
  124. int inputFile;
  125. /*static IOParam pb;*/
  126. extern ParamBlockRec pb;
  127.                     /* Å diventata una variabile globale per poter chiudere il file in
  128.                     caso di errore; per la veritê non Å necessario, basta un singolo
  129.                     campo, il RefNum... */
  130. unsigned char previousFormat;    /* solo per tar, quelli bar sono sempre multivolume
  131.             -- for tar format only, bar archives are always allowed to become multivolume */
  132. Boolean inf_is_open=false;
  133. static Boolean write_in_corso=0;    /* remembers that I was writing, hence what is in
  134.                 the disk is not correctly terminated by a null header */
  135. static Boolean devo_chiudere_in=false;
  136.  
  137. static Boolean questo_e_un_header;        /* set just before writing an header sector */
  138. extern int floppy_n;
  139. extern unsigned char mac_file_name[];
  140. extern int openfile_vrefnum;
  141. extern long openfile_dirID;
  142.  
  143. static char bar_date[12];
  144. long my_uid,my_gid;
  145.  
  146. void chiedi_altro_disco(void);
  147. void set_bar_date(void);
  148. Boolean surely_not_mac(char*);
  149. void alias_error(short);
  150.  
  151.  
  152. static void chiedi_altro_disco()    /* ask for another disk */
  153. {
  154. int i;
  155. diskEject();
  156.  
  157. for(;;){
  158.     i=aspetta_inserzione(in_Italia?"\pInserisci un altro disco su cui scrivere":
  159.     "\pInsert another disk to be written");
  160.     if(i!=0) raise_error();        /* un annulla... 
  161.                     -- the user clicked the Cancel button
  162.                     */
  163.     if(is_wrprot()){
  164.         printf_protetto();
  165.         }
  166.     else if(di.is_not_initialized)
  167.         disk_format(false);
  168.     else{
  169.         warning_400_800();
  170.         return;
  171.         }
  172.     }
  173. }
  174.  
  175.  
  176. void reset_sector_count()
  177. {
  178. /* viene chiamata quando si dê un comando di create o append, quindi Å il posto
  179. buono per inserire qualunque inizializzazione
  180. -- called for the Create and Append commands, it's the right place for initializing
  181. some variables
  182. */
  183. last_header=last_sector=0;
  184. previousFormat= tar_unknown;
  185. floppy_n=0;
  186. set_bar_date();        /* deve essere comune per tutto l'archivio
  187.                     -- the same value must be used for all volumes in the archive */
  188. }
  189.  
  190. void write_next_sector(void);
  191. static void write_next_sector()
  192. {
  193.  
  194.     if(last_sector>=sectors_on_floppy){
  195.         if(!bar_archive && previousFormat<=tar_singlevol&&tar_version<=tar_singlevol){
  196.             start_of_line();
  197.             printf("Disk full, write aborted !\n");        /* non dovrebbe capitare mai, */
  198.             tronca_archivio();        /* visto che controllo prima, ma nel caso...
  199.                         -- that should never happen, that's checked at every header,
  200.                         but if that check should contain a bug, don't crash
  201.                         */
  202.             raise_error();
  203.             }
  204.         last_sector=0;    /* deve essere =0 perchÄ scrivo sempre tutti 
  205.                 i settori (non per niente questa routine si chiama cosô...) */
  206.         chiedi_altro_disco();
  207.         }
  208.     if(last_sector==0){
  209.         floppy_n++;
  210.         warning_first_write(0);
  211.         if(bar_archive){
  212.             write_bar_volume_header();
  213.             }
  214.         else{
  215.             if(floppy_n!=1 && !questo_e_un_header &&
  216.                (previousFormat==tar_GNU || tar_version==tar_GNU&&previousFormat!=tar_AIX) ){
  217.                        /* scrivi un header di continuazione file 
  218.                     -- write a 'M' header for a file splitted between disks */
  219.                 write_tar_volume_header();
  220.                 }
  221.             }
  222.         }
  223.     scrivi_settore(last_sector,disk_buffer);
  224.     check_wr_err();
  225.     questo_e_un_header=false;
  226.     settori_passati++;
  227. }
  228.  
  229. void warning_400_800()
  230. {
  231. if( (sectors_on_floppy==800 || sectors_on_floppy==1600) && !accetta_GCR){
  232.     unsigned char b[2];
  233.     b[0]=1;
  234.     b[1]= sectors_on_floppy==800 ? '4' : '8';
  235.     if(in_Italia )
  236.         ParamText("\pUn disco da ",b,"\p00K non puÿ essere\rletto su un sistema UNIX",PNS);
  237.     else
  238.         ParamText("\pA ",b,"\p00K disk can\'t be read\ron an UNIX machine",PNS);
  239.     my_alert();
  240.     }
  241. }
  242.  
  243.  
  244. void printf_protetto()
  245. {
  246.     start_of_line();
  247.     printf(in_Italia?"Disco protetto da scrittura !\n":"Write protected disk !\n");
  248.     diskEject();
  249. }
  250.  
  251. static Boolean surely_not_mac(buffer)
  252. char buffer[512];
  253. {
  254. if(di.disk_code!=noErr) return true;
  255. leggi_settore(2,buffer);
  256. return err_code!=0;
  257. }
  258.  
  259. short warning_first_write(n)
  260. /* n=0 if called by a command in the write menu (don't return without a writable disk),
  261. 1 for initialize */
  262. {
  263. /* called before the first write to a disk which is still containing
  264. what it was containing when it was inserted: it's the last chance to
  265. avoid a data loss
  266. returns:
  267. -1: (only if n=1) the user canceled the operation but the disk wasn't ejected yet
  268. 0:    the user approved the operation
  269. 1:    it's not a Mac disk (no dialog)
  270. 2:    it's an empty Mac disk (no dialog)
  271. */
  272.  
  273. static char *loc_titoli[]={"\pEspelli","\pOk"};
  274. char buffer[512];
  275.  
  276. for(;;){
  277.     Boolean guarda_files;
  278.  
  279.     while(surely_not_mac(buffer)){
  280.         short inPlace;
  281.         testa_stato(&inPlace,0);
  282.         if(!n&&di.is_not_initialized){
  283.             disk_format(false);
  284.             if(drive_number){
  285.                 if(testa_stato(&inPlace,1) || !inPlace)
  286.                     diskEject();
  287.                 else if(is_wrprot())
  288.                     printf_protetto();
  289.                 else
  290.                     return 1;
  291.                 }
  292.             chiedi_altro_disco();
  293.             }
  294.         else
  295.             return 1;
  296.         }
  297. /*printf("n files=%d\n",*(int*)&buffer[12]);
  298. printf("n dirs=%d\n",*(int*)&buffer[82]);
  299. printf("n files tot=%ld\n",*(long*)&buffer[84]);
  300. printf("n dirs tot=%ld\n",*(long*)&buffer[88]);
  301. */
  302. /* if it's a Macintosh disk (same test used by is_mac_disk in suntar.c) see if
  303. it contains more than one file (the first one is the desktop) or more than zero folders
  304. */
  305.  
  306.     if( (*(int*) buffer== 0xD2D7 || *(int*) buffer== 0x4244) ){ /* MFS o HFS */
  307.         guarda_files=true;
  308.         if( *(int*) buffer== 0x4244 && ((*(int*)&buffer[10])&0x200)){
  309.             /* see TN 287: System 7 sets that flag if one or more bad sectors were 
  310.             found and marked as unusable */
  311.             ParamText(in_Italia?"\pQuesto disco contiene dei settori marcati difettosi":
  312.             "\pIn this disk some sectors are marked bad",PNS,PNS,PNS);
  313.             if( my_modal_dialog(133,loc_titoli,2) ==1){
  314.                 if(n) return -1;
  315.                 guarda_files=false;
  316.                 }
  317.             }
  318.         if(guarda_files){
  319.             if(*(unsigned char*)&buffer[36]<=27 && /* length of volume name */
  320.                 (*(int*)&buffer[12]>1 ||        /* files in root directory, e il primo Å il Desktop */
  321.                 (*(int*) buffer== 0x4244 &&*(int*)&buffer[82]>0)) ){    /* folders in root directory */
  322.                 ParamText(in_Italia?
  323.                 "\pQuesto disco contiene files in formato Macintosh, verranno sovrascritti":
  324.                 "\pThis disk contains some Macintosh files, their data will be overwritten",
  325.                 PNS,PNS,PNS);
  326.                 if( my_modal_dialog(133,loc_titoli,2) ==2){
  327.                     if(!n)de_Mac_ize(buffer);
  328.                     return 0;
  329.                     }
  330.                 if(n) return -1;
  331.                 }
  332.             else{
  333.                 if(!n) de_Mac_ize(buffer);
  334.                 return 2;
  335.                 }
  336.             }
  337.         chiedi_altro_disco();
  338.         }
  339.     else
  340.         return 1;
  341.     }
  342. }
  343.  
  344. void de_Mac_ize(buffer)
  345. char buffer[512];
  346. /* the Finder keeps a copy of sector 2 in the sector before the last one, and
  347. PBMountVol (called by GetNextEvent) when sees a disk with an invalid sector 2
  348. (what happens for any tar disk with more than 1024 bytes of data on it)
  349. but a valid sector 2878 (or 1598 or whatever) tells it's a Mac disk. (At first,
  350. we believed that the cause were tags, but a technical note explained that tags
  351. are no more required by the file system, hence they do not exist in drive where
  352. the hardware doesn't provide them, and the MFM format doesn't have tags).
  353. So it's better to deMac-ize disks when creating an archive. I prefer NOT to do
  354. that when sector 2 was overwritten by the UNIX tar, which obviously does not know
  355. about the Mac and the Finder, in that case in order to de-Macize I should write
  356. to the disk even if the user asked only to read, not a good thing
  357. */
  358. {
  359. leggi_settore(sectors_on_floppy-2,buffer);
  360. if(err_code) return;
  361. if(*(int*) buffer== 0xD2D7 || *(int*) buffer== 0x4244 )
  362.     buffer[0]++;    /* it's better to preserve everything, only change the
  363.                     code */
  364. write_sectors(sectors_on_floppy-2,buffer,1);    /* non-buffered write */
  365. di.disk_code=noMacDskErr;
  366. }
  367.  
  368. void write_tar_volume_header()
  369. /* writes the 'M' continuation header on GNU tar volumes following the first one */
  370.  
  371. {
  372. tarh_type buffer;
  373. long old_size,delta_size;
  374. int i;
  375.  
  376. /* get the needed data, which were saved when writing the last normal header */
  377. mcopy(&buffer,ultimo_header,sizeof(ultimo_header));
  378. fillmem(&buffer.name[sizeof(ultimo_header)],0,512-sizeof(ultimo_header));
  379. old_size=untar_number(buffer.size,-1);
  380. fillmem(buffer.size, '\0', 12);
  381.  
  382. delta_size = (long)avail_sectors_for_file<<9;
  383. last_offset += delta_size;
  384.  
  385. if(old_size<=delta_size) return;    /* il file terminava proprio 
  386.             nell'ultimo settore del disco precedente
  387.             -- the file happened to end in the last sector of the previous disk,
  388.             hence this disk must not contain an 'M' continuation header
  389.             */
  390.  
  391. numstr(&buffer.size, old_size-delta_size, 12);
  392. numstr(&buffer.offset, last_offset, 12);
  393. buffer.linkflag = 'M';
  394. fill_checksum(&buffer);
  395.  
  396. /* update the saved informations */
  397. copia_ultimo_header(&buffer,(sector_t)1);
  398.  
  399. /* last_offset l'ho giê calcolato */
  400. ultimo_disco_espulso=true;    /* forse... bisogna vedere come ritrovo l'header da 
  401.     azzerare in tronca_archivio !!!
  402.     -- unused variable, but in the future it should serve to help clearing
  403.     the last_header in case of error
  404.     */
  405.  
  406. scrivi_settore(0,&buffer);
  407. check_wr_err();
  408. last_sector=1;
  409. }
  410.  
  411. static void set_bar_date()
  412. /* read the current date an time and store it in the format of the date field
  413. for bar archives */
  414. {
  415. DateTimeRec cdate; 
  416. register char*p = bar_date;
  417. register int i;
  418.  
  419. GetTime (&cdate);
  420. cdate.year %= 100;    /* solo le ultime due cifre dell'anno... */
  421. for(i=0;i<5;i++){
  422.     *p++ = '0'+ ((int*)&cdate.year)[i] /10;
  423.     *p++ = '0'+ ((int*)&cdate.year)[i] %10;
  424.     }
  425. *p='\0';
  426. }
  427.  
  428. void write_bar_volume_header()
  429. {
  430. /* when there were doubts about what should be written (see untar.c)
  431. I preferred to write clean information rather than to follow the
  432. silly rules of the original bar: there seems to be no compatibility
  433. problem, since bar ignores the contents of the fields which it
  434. writes in a silly way
  435. */
  436. barh_type buffer;
  437. register long oldsize;
  438. int i;
  439.  
  440. fillmem(&buffer,0,512);
  441. my_itoa(my_uid,&buffer.uid);
  442. my_itoa(my_gid,&buffer.gid);
  443. buffer.bar_magic[0]='V';
  444. buffer.bar_magic[1]='\0';
  445. my_itoa((long)floppy_n,&buffer.volume_num);
  446. buffer.compressed='0';
  447. mcopy(&buffer.cdate,bar_date,12);
  448.  
  449. if(floppy_n==1)
  450.     oldsize = 0L;
  451. else{
  452.     oldsize = untar_number(((barh_type*)ultimo_header)->size,-1);
  453.     oldsize = (oldsize+511)>>9;        /* numero di settori necessari */
  454.     oldsize -= avail_sectors_for_file;    /* meno quelli giê usati 
  455.             -- size = number of needed sectors at the time of the last header
  456.                 minus number of available sectors on previous disk
  457.             */
  458.     avail_sectors_for_file += sectors_on_floppy-1;
  459.     }
  460.  
  461. numstr(buffer.size, oldsize<<9, 12);
  462. bar_checksum(&buffer);
  463.  
  464. scrivi_settore(0,&buffer);
  465. check_wr_err();
  466. last_sector=1;
  467. }
  468.  
  469. short bar_header(fname, fsize, barh)
  470.   char *fname;
  471.   long fsize;
  472.   register barh_type *barh;
  473. {
  474.     fillmem(barh, 0, 512);
  475.     mac_to_unix(barh->name, fname+path_len);
  476.     if(!strcmp("./",barh->name) || !barh->name[0] ) return -1;        /* succede nel system 7.0 se 
  477.                  come folder da salvare seleziono un volume
  478.                 -- I get that string in System 7, a whole volume such as "HD40"
  479.                 becomes "./", but it's better not to save any entry for "HD40" !
  480.                 */
  481.  
  482.     if (statb.ioFlAttrib & ioDirMask)
  483.         if (barh->name[strlen(barh->name)-1] != '/')
  484.             barh->name[strlen(barh->name)] = '/';
  485.     numstr(barh->mode, (long)((statb.ioFlAttrib & ioDirMask) ? dirmode : filemode), 8);
  486.     numstr(barh->uid, my_uid, 8);
  487.     numstr(barh->gid, my_gid, 8);
  488.     numstr(barh->size, fsize, 12);
  489.     numstr(barh->mtime, (long) statb.ioFlMdDat - UNIXTIME, 12);
  490.     barh->linkflag = ((statb.ioFlAttrib & ioDirMask) ? '\0' : '0');    /* it's not clear
  491.         what I should write here, see the discussion un untar.c */
  492.     bar_checksum(barh);
  493.     questo_e_un_header=true;
  494.     writeblock(barh, 512);
  495.     last_header=last_sector-1;    /* ho bisogno di last_sector NON ancora incrementato
  496.             al settore successivo, ma incrementato degli eventuali header extra !
  497.             -- last_sector was already incremented, and I can't get the value before
  498.             calling write_block since it may add a volume header */
  499.     copia_ultimo_header(barh,last_sector);    /* last_sector incrementato */
  500.     return 0;
  501. }
  502.  
  503. void bar_checksum(buf)
  504. char *buf;
  505. {
  506. register int i;
  507. register long chk= ' '*8;
  508. for(i=0;i<48;++i)
  509.     chk += (unsigned char) buf[i];
  510. for (i+=8; i < 512; ++i)
  511.     chk += (unsigned char) buf[i];
  512. numstr(((barh_type*)buf)->chksum,chk,8);
  513. }
  514.  
  515. void writeblock(p,len)
  516. register char*p;
  517. int len;
  518. {
  519. if(len>=more_space){
  520.     mcopy(&disk_buffer[512-more_space],p,more_space);
  521.     p+=more_space;
  522.     len-=more_space;
  523.     write_next_sector();
  524.     last_sector++;
  525.     more_space=512;
  526.     check_events();
  527.     if(!len) return;
  528.     }
  529. mcopy(&disk_buffer[512-more_space],p,len);
  530. more_space-=len;
  531. }
  532.  
  533. unsigned char get_linkflag(length)
  534. long *length;
  535. {
  536. unsigned char linkflag;
  537.     *length=untar_number( bar_archive ? ((barh_type*)disk_buffer)->size :
  538.         ((tarh_type*)disk_buffer)->size,true);
  539.     if(bar_archive){
  540.         linkflag=guess_bar_linkflag();
  541.         if(linkflag=='1'||linkflag=='5') *length=0;
  542.         }
  543.     else{
  544.         /* for directories, the size field may be used to store some informations,
  545.         hence I can't rely on it being 0 */
  546.         linkflag=((tarh_type*)disk_buffer)->linkflag;
  547.         if(linkflag=='5' || ((tarh_type*)disk_buffer)->name[
  548.             strlen(((tarh_type*)disk_buffer)->name)-1] == '/'){
  549.             linkflag='5';
  550.             *length=0;
  551.             }
  552.         }
  553.     return linkflag;
  554. }
  555.  
  556.  
  557. void cerca_fine()    /* find the end of the archive: used for Append */
  558. {
  559. long length;
  560. enum formats fmt;
  561. Boolean message_given=false;
  562.  
  563. previousFormat=tar_unknown;
  564. listonly=1;        /* don't use buffering */
  565. fmt=identify_format();
  566. if(fmt==tar_format){
  567.     bar_archive=false;
  568.     if( hasVheader || ((tarh_type*)disk_buffer)->linkflag=='M' ) {
  569.         previousFormat=tar_GNU;    /* se Å giê
  570.                 multivolume, vuol dire che il GNU tar Å disponibile...
  571.                 -- if it's already GNU multivolume, later I must not bother the
  572.                 user asking if I may create a multivolume archive, and I must
  573.                 use the GNU format even if the current setting of tar_version
  574.                 is AIX */
  575.         if(hasVheader) last_header=1;
  576.         }
  577.     floppy_n=1;
  578.     }
  579. else if(fmt==bar_format){
  580.     bar_archive=true;
  581.     floppy_n=untar_number( ((barh_type*)disk_buffer)->volume_num,true);
  582.     mcopy(bar_date,((barh_type*)disk_buffer)->cdate,12);
  583.     last_header= (untar_number( ((barh_type*)disk_buffer)->size,true)+1023)>>9;
  584.     }
  585. else
  586.     raise_error();
  587.  
  588. for(;;){
  589.     static char sita[]=" (dovresti assegnare l\'opzione \"tar version\")\n",
  590.                 sing[]=" (you should set the \"tar version\" option)\n",
  591.                 snew[]="\n";
  592.     register unsigned char linkflag;
  593.     while(last_header>=sectors_on_floppy){
  594.         if(fmt==bar_format||previousFormat==tar_GNU||previousFormat!=tar_AIX&&tar_version==tar_GNU){
  595.             Boolean opt_ok= fmt==bar_format||tar_version==tar_GNU;
  596.             if(in_Italia)
  597.                 printf("La fine dell\'archivio non Å in questo disco%s",opt_ok||message_given ? snew : sita);
  598.             else
  599.                 printf("The end of archive is not in this disk%s\n",opt_ok||message_given ? snew : sing);
  600.             message_given=true;
  601.             raise_error();
  602.             }
  603.         else{    /* potrebbe essere AIX...
  604.                 -- it could be AIX, but maybe the user has not set the option
  605.                 and in that case suntar suggests him to do that */
  606.             int i;
  607.             Boolean was_AIX;
  608.             last_header-=sectors_on_floppy;
  609.             do{
  610.                 diskEject();
  611.                 i=aspetta_inserzione(in_Italia?
  612.                     "\pInserisci il prossimo disco tar":"\pInsert next tar disk");
  613.                 if(i) raise_error();
  614.                 }
  615.             while(di.is_not_initialized);
  616.             was_AIX=previousFormat==tar_AIX;
  617.             i = tar_check_settore0(false);
  618.             if(i==-1){        /* bad header, but it's the normal case for AIX disks
  619.                             following the first one */
  620.                 if(previousFormat<=tar_singlevol&&tar_version!=tar_AIX){
  621.                     start_of_line();
  622.                     if(in_Italia)
  623.                         printf("Probabile formato AIX%s",message_given?snew:sita);
  624.                     else
  625.                         printf("Probable AIX format%s",message_given?snew:sing);
  626.                     message_given=true;
  627.                     }
  628.                 previousFormat=tar_AIX;
  629.                 }
  630.             else if(previousFormat==tar_GNU){        /* it was not so when entering in
  631.                     this while, but check_settore_0 may assign it */
  632.                 if(was_AIX) error_message("Not a AIX tar disk !\n");
  633.                 if(in_Italia)
  634.                     printf("Formato GNU tar%s",message_given?snew:sita);
  635.                 else
  636.                     printf("GNU tar format%s",message_given?snew:sing);
  637.                 message_given=true;
  638.                 last_header= hasVheader ? 1 : 0;
  639.                 }
  640.             }
  641.         }
  642.     check_events();
  643.     leggi_settore(last_header,disk_buffer);
  644.     if(check_error()) raise_error();
  645.  
  646.     last_sector=last_header;
  647.     if(check_all_zero(disk_buffer)){
  648.         if(last_header==0||(bar_archive||hasVheader)&&last_header==1)
  649.             printf(in_Italia?"Disco vuoto\n":"No files on disk\n");
  650.         return;
  651.         }
  652.     linkflag= get_linkflag(&length);
  653.     if(linkflag!='1'&&linkflag!='2'&&linkflag!='V'&&linkflag!='M')
  654.         print_info(bar_archive ? ((barh_type*)disk_buffer)->name :
  655.             ((tarh_type*)disk_buffer)->name,length);
  656.     last_header += (length+1023)/512;
  657.     }
  658. }
  659.  
  660. void svuota_buffer()    
  661. /* empty the buffer, used at the end of a file, next data
  662. will be a file header which must be aligned at the start of a sector;
  663. really, it's useful only for MacBinary files, since tardata internally
  664. groups the data in 512 bytes chunks
  665. */
  666. {
  667. if(more_space!=512){
  668.     /* succede solo per MacBinary, visto che tardata scrive comunque in blocchi di 512 */
  669.     fillmem(&disk_buffer[512-more_space],0,more_space);    /* azzera quello che resta: 
  670.                 il tar per UNIX non lo fa, ma non Å bello lasciare della robaccia...
  671.                 -- clear the empty part of the buffer before writing it out: the
  672.                 UNIX tar doesn't do that, but it's not professional to write
  673.                 garbage data (well, the Macintosh too does that, the 128 bytes
  674.                 of reserved data in the resource fork are garbage: but, think
  675.                 what would happen if that garbage happens to be a part of your
  676.                 personal mail, or reserved informations... The reserved bytes in
  677.                 the suntar application often happen to contain a chunk of its source
  678.                 code, which was saved before compiling and is still in the disk 
  679.                 buffer)
  680.                 */
  681.     write_next_sector();
  682.     last_sector++;
  683.     }
  684. more_space=512;
  685. }
  686.  
  687. void azzera_settore()    /* clear a sector, that is write an end of archive header */
  688. {
  689. svuota_buffer();
  690. fillmem(disk_buffer, 0, 512);
  691. questo_e_un_header=true;
  692. write_next_sector();
  693. /* niente last_sector++, per ovvie ragioni
  694. -- don't increment last_sector, another write must overwrite this sector
  695. */
  696. last_header=last_sector;
  697. }
  698.  
  699. void tronca_archivio()
  700. /* truncate an archive, by clearing the last header: used when,
  701. due to an error, what follows that header can't be completed */
  702. {
  703. last_sector=last_header;
  704. /* multivolume, se il disco Å stato espulso deve richiederlo !!
  705. o forse non lo faccio qui, ma nella gestione setjmp, questa qui Å chiamata anche 
  706. in caso di quit
  707. o forse dare un messaggio, in fondo capita raramente...
  708. -- in multivolume archives, the sector to be cleared may be on another disk,
  709. which was ejected. The correct behaviour should be to ask the user to insert
  710. back that disk, carefully check that it's the right disk and clear the sector,
  711. or, if the user refuses to insert it back, print which sector (and file) 
  712. must be cleared. By now, in that case I do nothing
  713. */
  714. /*printf("<%ld>",(long)last_sector);*/
  715.     /* I may avoid to flush things which are AFTER the last header: not only that
  716.     saves time, but if the operation was interrupted because that's the wrong
  717.     disk it could save good data */
  718. invalid_after(last_sector);
  719.  
  720. read_sectors(last_sector,disk_buffer,1);    /* don't use the value stored in the buffers! */
  721. if(err_code==0){
  722.     /* compare it with the stored content of the last sector: it would be
  723.     terrible to clear a sector in a disk which happens to be in that drive
  724.     but is not the tar/bar disk I was writing !
  725.     */
  726.     if(compare_mem(ultimo_header,disk_buffer,sizeof(ultimo_header))){
  727.         fillmem(disk_buffer, 0, 512);
  728.         scrivi_settore(last_sector,disk_buffer); /* senza verifica di errore */
  729.         flush_buffers();
  730.         }
  731.     else
  732.         invalid_buffers();
  733.     }
  734. else
  735.     invalid_buffers();
  736. more_space=512;
  737. }
  738.  
  739. Boolean compare_mem(p,q,s)
  740. register char*p,*q;
  741. register int s;
  742. {
  743. while(s){
  744.     if(*p++ != *q++) return false;
  745.     s--;
  746.     }
  747. return true;
  748. }
  749.  
  750. void print_ready()
  751. {
  752. long sz=sectors_on_floppy-last_header-1;
  753. printf("%ld",sz/2);
  754. if(sz&1)printf(in_Italia?",5":".5");
  755. printf(in_Italia?" Kbytes disponibili\n":" Kbytes available\n");
  756. }
  757.  
  758. /********************************/
  759.  
  760. void check_and_eject()
  761. /* eseguita in caso di QUIT ma anche in caso di errore
  762. -- executed in case of error or Quit
  763. */
  764. {
  765. if(write_in_corso){
  766.     tronca_archivio();
  767.     write_in_corso=false;
  768.     }
  769. else{
  770.     if(dirty_buffers()) invalid_buffers();
  771.     }
  772. diskEject();
  773. }
  774.  
  775. /************************/
  776. void check_wr_err()
  777. {
  778. if(err_code){
  779.     start_of_line();
  780.     if(err_code==-65)
  781.         printf(in_Italia?"Errore, disco assente\n":"Error, missing disk\n");
  782.     else
  783.         printf("Disk write error %d\n",err_code);
  784.     if(!ignore_errors && write_in_corso){
  785.         tronca_archivio();
  786.         raise_error();
  787.         }
  788.     }
  789. }
  790. /*********************************/
  791.  
  792. void my_tar(file_mode)    /* handles a command from the Write menu */
  793. {
  794. int charsRead;
  795.  
  796. int n_types;
  797. SFTypeList    myTypes;
  798. extern unsigned char*nomeFormato;
  799.  
  800. if(file_mode==wmASCII){
  801.     n_types=1;
  802.     myTypes[0]='TEXT';
  803.     binary=false;
  804.     dataonly=true;
  805.     nomeFormato="\p    (ASCII)";
  806.     }
  807. else if(file_mode==wmWriteTar){
  808.     if(bar_archive)
  809.         n_types=-1;
  810.     else
  811.         n_types=2;
  812.     myTypes[0]='TARF';
  813.     myTypes[1]='TEXT';    /* quelli estratti con MacCompress se provengono da UNIX
  814.                         (niente resource fork) sono TEXT KAHL
  815.                         -- .tar.Z files extracted with MacCompress are TEXT-KAHL,
  816.                         .tar files created by tar 3.0 are TARF TAR , those created
  817.                         by suntar may be TARF (copy to mac file) or TEXT (save sectors)
  818.                         */
  819.     }
  820. else{    /* wmDataFork o wmWriteMacBin */
  821.     n_types=-1;
  822.     binary=true;
  823.     dataonly= file_mode==wmDataFork;
  824.     nomeFormato=file_mode==wmWriteMacBin?"\p(MacBinary)":"\p(Data fork)";
  825.     }
  826.  
  827. more_space=512;
  828. if(file_mode!=wmWriteTar){
  829.     Str255 name;
  830.     int i=get_file_or_folder(name,n_types,&myTypes);
  831.     if(i<0) return;    /* cancel...*/
  832.     if(i==0){    /* folder: il nome Å il path completo, ma non voglio 
  833.                 salvarlo tutto nell'archivio
  834.                 -- folder: discover the size difference between the full
  835.                 pathname and the partial pathname
  836.                 No more useful since now I use a partial file name anyway,
  837.                 but to keep these instructions causes no problems */
  838.         path_len=name[0]-1;    /*il -1 Å necessario, in fondo c'Å un : 
  839.                 -- the -1 is needed since the last character is a ':'
  840.                 */
  841.         while(path_len>0 && name[path_len]!=':') path_len--;
  842.         if(--path_len<0)path_len=0;    /*non dovrebbe mai capitare 
  843.                     -- that should never happen, but behaving well in cases
  844.                     that should be impossible may save a programmer from
  845.                     some nasty bugs */
  846.         }
  847.     else /* file semplice, il nome Å relativo al volume
  848.         -- single file, I've filename + vRefNum as returned by SFGetFile
  849.         */
  850.         path_len=0;
  851.     name[name[0]+1]=0;
  852.     fase=writing_disk;
  853.     write_in_corso=1;
  854.     tar_file_or_folder(&name[1]);
  855.     azzera_settore();
  856.     flush_buffers();
  857.     write_in_corso=0;
  858.     }
  859. else{    /* file tar, non c'Å da creare header o altro...
  860.         -- write tar file: handle it directly here...
  861.         */
  862.     sector_t more_sectors=0;
  863.     long length;
  864.  
  865.     my_SF_Get(n_types,myTypes);
  866.     if(!reply.good)return;
  867.     path_len=0;
  868.  
  869.     if(apri_file("rb",&inputFile))
  870.         return;
  871.     inf_is_open=true;
  872.     fase=writing_disk;
  873.     write_in_corso=1;
  874.     if(bar_archive){
  875.         /* read (and skip) the volume header, with some checks */
  876.         charsRead = mac_fread(disk_buffer, 512, inputFile);
  877.         if(((barh_type*)disk_buffer)->bar_magic[0]!= 'V' || 
  878.                ((barh_type*)disk_buffer)->bar_magic[1] != 0)
  879.             error_message(in_Italia?"Questo non Å un file in formato bar\n":
  880.                 "Not a bar file !\n");
  881.         if(floppy_n==0 && last_sector==0) mcopy(bar_date,((barh_type*)disk_buffer)->cdate,12);
  882.         }
  883.     do{
  884.         charsRead = mac_fread(disk_buffer, 512, inputFile);
  885.         if(charsRead>=0 && charsRead<512)
  886.             fillmem(&disk_buffer[charsRead], 0, 512-charsRead); /* non indispensabile, 
  887.                                     ma Å brutto che lo spazio extra
  888.                                     nell'ultimo settore del file resti garbage.
  889.                                     -- see before, clear the buffer to avoid writing
  890.                                     garbage at the end of the last sector
  891.                                     */
  892.         /* meglio non controllare errore, i file di tar2 sono cattivi e invece va poi 
  893.         tutto bene...*/
  894.         if(more_sectors==0){
  895.             last_header=last_sector;
  896.             if(check_all_zero(disk_buffer))
  897.                 more_sectors=-1;    /* infinity... */
  898.             else{
  899.             /* it was an header: do the standard work for headers, extract the size 
  900.             field and continue */
  901.                 questo_e_un_header=true;
  902.                 copia_ultimo_header(disk_buffer,last_sector+1);
  903.                 last_offset=0;
  904.                 (void)get_linkflag(&length);
  905.                 if(length<0){
  906.                     check_and_eject();
  907.                     raise_error();
  908.                     }
  909.                 else{
  910.                     more_sectors=(length+511)/512;
  911.                     print_info(bar_archive?((barh_type*)disk_buffer)->name:disk_buffer,length);
  912.                     if(!bar_archive) controlla_che_ci_stia(more_sectors);
  913.                     }
  914.                 }
  915.             }
  916.         else
  917.             more_sectors--;
  918.         check_events();
  919.         write_next_sector();
  920.         last_sector++;
  921.         }
  922.     while(charsRead>0);
  923.     flush_buffers();
  924.     write_in_corso=0;
  925.  
  926.     FSClose(inputFile);
  927.     inf_is_open=false;
  928.     last_sector=last_header;
  929.     }
  930. }
  931.  
  932.  
  933. void close_input_files()
  934. {    /* da chiamare in caso che una longjmp esca dalla routine precedente */
  935. if(inf_is_open){
  936.     FSClose(inputFile);
  937.     inf_is_open=false;
  938.     file_aperto=false;    /* lo stesso inputFile viene usato per due scopi diversi,
  939.                         in ogni caso dopo di adesso il valore buono Å false...
  940.                         -- the inputFile variable is used in two different places 
  941.                         for different purposes, hence two variables to be cleared
  942.                         */
  943.     }
  944. if(devo_chiudere_in){
  945.     (void) PBCloseSync(&pb);
  946.     devo_chiudere_in=false;
  947.     }
  948. }
  949.  
  950. void FillMacBin2Fields()        /* transforms a MacBinary header into a MacBinary II header */
  951. {
  952. extern short current_crc;
  953. register int i;
  954.  
  955. /* can't declare a pointer to binh_type since it's misaligned by one byte */
  956. tarh.name[101]=tarh.name[74];        /* because I didn't clear that byte, as the
  957.                     MacBinary standard says, but left there the finder flags which 
  958.                     MacBinary II says must be stored elsewhere */
  959. tarh.name[74]=0;    /* but now it's better to follow the standard */
  960. tarh.name[122]=tarh.name[123]=129;
  961. current_crc=0;
  962. for(i=0;i<124;i++)
  963.     CalcCRC(tarh.name[i]);
  964. CalcCRC(0);
  965. CalcCRC(0);
  966. *(short*)&tarh.name[124]=current_crc;
  967. }
  968.  
  969. void assegna_tar_version()
  970. {
  971. extern char *titoli[];
  972.  
  973. if(dirty_buffers()) flush_buffers();
  974. tar_version=my_modal_dialog(140,NULL,0);
  975.  
  976. ParamText(in_Italia?
  977.     "\pDevo assegnare l\'opzione \"tar version\" permanentemente ?":
  978.     "\pSet the option \"tar version\" permanently ?",PNS,PNS,PNS);
  979. if(my_modal_dialog(130,titoli,2)==1)
  980.     save_options();
  981. }
  982.  
  983.  
  984. void controlla_che_ci_stia(n_sectors)
  985. sector_t n_sectors;
  986. /* check that there is enough space in the disk for next file: if not,
  987. a multivolume archive could be generated, but the standard tar does not
  988. accept multivolume archives
  989. */
  990. {
  991. if(previousFormat<=tar_singlevol &&tar_version<=tar_singlevol &&
  992.    last_header+n_sectors+1>=sectors_on_floppy){    /* l'header va nel 
  993.             settore last_header, seguono n_sectors settori di dati fino a last_header +
  994.             n_sectors e il settore last_header+n_sectors+1 deve contenere gli zeri di
  995.             indicazione fine archivio */
  996.     if(previousFormat==tar_unknown&&tar_version==tar_unknown){
  997.         if(dirty_buffers()) flush_buffers();
  998.         ParamText(in_Italia?
  999.             "\pSpazio insufficiente, creo un archivio multidisco ?":
  1000.             "\pNot enough space, OK to create a multivolume archive ?",PNS,PNS,PNS);
  1001.         assegna_tar_version();
  1002.         }
  1003.  
  1004.     if(tar_version==tar_singlevol){
  1005.         printf(in_Italia?"Errore, spazio insufficiente\n":"Error, not enough space\n");
  1006.         /*tronca_archivio();    /* bisogna riazzerare l'ultimo header per avere un disco consistente */
  1007.         raise_error();    /* che chiama check_and_eject che chiama tronca_archivio, per cui
  1008.                 quella chiamata sopra non serve */
  1009.         }
  1010.     }
  1011. }
  1012.  
  1013. /*********** end of routines by Speranza ****************/
  1014.  
  1015. /****** start of routines by Gail Zacharias *****************/
  1016.  
  1017.  
  1018. void tar_file_or_folder (file_name)
  1019.   char *file_name;
  1020. {
  1021.     
  1022. statf(file_name);
  1023. if (statb.ioFlAttrib & ioDirMask) {
  1024.     statb.ioVRefNum = getvrefnum(file_name);
  1025.     tardir(file_name);
  1026.     }
  1027. else{
  1028.     char *cp = file_name+strlen(file_name);
  1029.     while (cp != file_name && cp[-1] != ':') --cp;
  1030.     if ((macbinh.nlen = strlen(cp)) >= 64) nametoolong(file_name);
  1031.     strcpy(macbinh.name, cp);
  1032.     tarfile(file_name);
  1033.     }
  1034. }
  1035.  
  1036. void tardir (dname)
  1037.   char *dname;
  1038. {
  1039.     int isvolume;
  1040.     Str255 name;
  1041.     long dirid = statb.ioDirID;
  1042.     int index = 0;
  1043.     int dlen = strlen(dname);
  1044.  
  1045.     isvolume = bar_archive ? bar_header(dname, 0L, &tarh) : tarheader(dname, 0L);
  1046.     if(!isvolume){
  1047.         if(expert_mode) print_sector_n(last_sector-1); /* -1 perchÄ Å giê stato
  1048.             incrementato; potrei spostare la printf sopra, ma allora non saprei se Å
  1049.             un volume... */
  1050.         printf(in_Italia?"Cartella %s\n":"Folder %s\n",
  1051.             bar_archive?((barh_type*)&tarh)->name:tarh.name);
  1052.         }
  1053.   
  1054.     if(strchr(dname, ':'))
  1055.         strcpy(name, dname);
  1056.     else{
  1057.         name[0] = ':';
  1058.         strcpy(&name[1], dname);
  1059.         dlen++;
  1060.         }
  1061.     if (name[dlen-1] != ':') name[dlen++] = ':';
  1062.     while (1) {
  1063.         statb.ioFDirIndex = ++index;
  1064.         statb.ioDirID = dirid;
  1065.         statb.ioNamePtr = &macbinh.nlen;
  1066.         if (PBGetCatInfoSync(&statb) || statb.ioResult) {
  1067.             if (statb.ioResult != fnfErr ) pbsyserr(&statb);
  1068.             return;
  1069.             }
  1070.         strncpy(&name[dlen], macbinh.name, macbinh.nlen);
  1071.         name[dlen+macbinh.nlen] = '\0';
  1072.         if (macbinh.nlen >= 64 ) nametoolong(name);
  1073.         if (statb.ioFlAttrib & ioDirMask) 
  1074.             tardir(name);
  1075.         else
  1076.             tarfile(name);
  1077.         }
  1078. }
  1079.  
  1080. static void alias_error(err)
  1081. {
  1082. if(err!=noErr){
  1083.     beep_in_foreground();
  1084.     error_message_1("Error %d in resolving alias\n",err);
  1085.     }
  1086. }
  1087.  
  1088. void tarfile (fname)
  1089. /* heavily modified by Speranza, in order to handle aliases */
  1090.   char *fname;
  1091. {
  1092. char name[150];
  1093. short vrefnum=0;
  1094. int old_pl=path_len;
  1095. extern char s_spazi[];
  1096.  
  1097. strcpy(name,fname);
  1098. if (statb.ioFRefNum) {
  1099.     printf("Warning: file %s was already open\n", name);
  1100.     devo_chiudere_in=false;
  1101.     }
  1102.  
  1103. if( resolve_aliases && (statb.ioFlFndrInfo.fdFlags & ALIAS_BIT) ){
  1104.     if(! gHasResolveAlias){
  1105.         if(dirty_buffers()) flush_buffers();
  1106.         ParamText(in_Italia?"\pPer risolvere gli alias ci vuole il System 7":
  1107.         "\pAliases can\'t be resolved without System 7",PNS,PNS,PNS);
  1108.         my_alert();
  1109.         }
  1110.     else{
  1111.         FSSpec mySpec;
  1112.         WDPBRec param;
  1113.         char is_folder,is_aliased;
  1114.         int io;
  1115.  
  1116.         io=FSMakeFSSpec(0,0L,c2pstr(name),&mySpec);
  1117.         alias_error(io);
  1118.         p2cstr(name);
  1119.  
  1120.         io=ResolveAliasFile(&mySpec,true,&is_folder,&is_aliased);
  1121.         if(io!=noErr){
  1122.             printf(in_Italia?"Alias %p: non trovato l\'originale\n":
  1123.             "Alias %p: original not found\n",mySpec.name);
  1124.             return;
  1125.             }
  1126. /* ora, il metodo regolamentare sarebbe fare
  1127. io=FSpOpenDF(&mySpec,fsRdPerm,&pb.ioRefNum);    (data fork)
  1128. io=FSpOpenRF(&mySpec,fsRdPerm,&pb.ioRefNum);    (resource fork)
  1129. ma tutto il programma Å impostato sui vecchi formati: quale Å il nuovo
  1130. equivalente di PBGetCatInfo ? Ovvero, come la si deve chiamare se si hanno
  1131. solo le informazioni vecchio stile ? Per ora preferisco tradurre la specifica nuova 
  1132. in una vecchia, forse il modo che uso non Å il migliore ma per ora l'importante 
  1133. Å che funzioni 
  1134. -- at this point, I have a FSSpec, while all the routines by Zacharias expect
  1135. the old couple vRefNum-filename
  1136. A conversion to the new style would be more elegant, a conversion to the old
  1137. style is more compatible and easier to implement, hence that's what I did
  1138. */
  1139.         if(is_folder){
  1140. #ifdef V_122
  1141.             PathNameFromDirID(mySpec.parID, mySpec.vRefNum, name);
  1142.             path_len=name[0]-1;    /* ci sarebbe da discutere che path name 
  1143.                         mettere nell'archivio, quello dell'alias o quello dell'
  1144.                         originale ? Cosô non ci metto nessun pathname, gli alias di
  1145.                         folder appaiono al livello esterno
  1146.                         -- which path must be written in the archive ? to remove
  1147.                         the problem, aliases are written with the last name only:
  1148.                         that's not the best solution, but it's simple to implement
  1149.                         */
  1150.             pStrcat(name,mySpec.name);
  1151.             pStrcat(name,"\p:");
  1152.             p2cstr(name);
  1153.             tar_file_or_folder (name);
  1154. #else
  1155.             short oldref;
  1156.             path_len=0;
  1157.             pStrcpy(name,"\p:");
  1158.             pStrcat(name,mySpec.name);
  1159.             pStrcat(name,"\p:");
  1160.             p2cstr(name);
  1161.             oldref=curr_vrefnum;
  1162.  
  1163.             param.ioVRefNum=mySpec.vRefNum;
  1164.             /*printf("FSSpec=%d %ld %p\n",mySpec.vRefNum,mySpec.parID,mySpec.name);*/
  1165.             param.ioNamePtr=NULL;
  1166.             param.ioWDProcID=signature;
  1167.             param.ioWDDirID=mySpec.parID;
  1168.             io=PBOpenWDSync(¶m);
  1169.             alias_error(io);
  1170.             curr_vrefnum=param.ioVRefNum;
  1171.             SetVol(NULL,curr_vrefnum);
  1172.             register_WD(param.ioVRefNum);
  1173.  
  1174.             /*printf("intero=%s pezzo=%s\n",name,name+path_len);*/
  1175.             tar_file_or_folder (name);
  1176.             SetVol(NULL,curr_vrefnum=oldref);
  1177. #endif
  1178.             path_len=old_pl;
  1179.             return;
  1180.             }
  1181. /* ora mi creo una WD sul file origine: poi non la chiudo per lo stesso motivo
  1182. che in Untar (gestione duplicate file name)
  1183. -- PBGetCatInfo may be called without a working directory ID (by using PBHGetCatInfo),
  1184. but tardata and other routines expect a vrefnum, hence I create a working directory. */
  1185.         param.ioVRefNum=mySpec.vRefNum;
  1186.         param.ioNamePtr=NULL;
  1187.         param.ioWDProcID=signature;
  1188.         param.ioWDDirID=mySpec.parID;
  1189.         io=PBOpenWDSync(¶m);
  1190.         alias_error(io);
  1191.  
  1192.         vrefnum=param.ioVRefNum;    /* ad uso delle varie open...*/
  1193.         register_WD(param.ioVRefNum);
  1194.  
  1195.         /* fill the informations which statf should have returned */
  1196.         statb.ioNamePtr = mySpec.name;
  1197.         statb.ioFVersNum = 0;
  1198.         statb.ioVRefNum = param.ioVRefNum;
  1199.         statb.ioFDirIndex = 0;
  1200.         statb.ioDirID = 0;
  1201.         if (PBGetCatInfoSync(&statb) ) pbsyserr(&statb);
  1202.  
  1203.         statb.ioNamePtr = NULL;
  1204.         p2cstr(mySpec.name);
  1205.         strcpy(name,mySpec.name);
  1206.         path_len=0;
  1207.         }
  1208.     }
  1209.  
  1210.  
  1211. if (dataonly){
  1212.     if(binary || (statb.ioFlFndrInfo.fdType == 'TEXT'&&!(statb.ioFlFndrInfo.fdFlags&ALIAS_BIT)))
  1213.         tardata(name,vrefnum);
  1214.     else    /* Write ASCII on non-text files */
  1215.         switch(non_text_ASCII){
  1216.         case 0:    /* not saved */
  1217.             if(expert_mode) printf(s_spazi);
  1218.             printf("File %s (%s)\n",name+path_len,in_Italia?"non salvato":"not saved");
  1219.             break;
  1220.         case 1:    /* data */
  1221.             binary=1;
  1222.             tardata(name,vrefnum);
  1223.             binary=0;
  1224.             break;
  1225.         case 2:    /* ASCII */
  1226.             tardata(name,vrefnum);
  1227.             break;
  1228.         case 3:    /* macbinary */
  1229.             tarmacbin(name,vrefnum);
  1230.             break;
  1231.         }
  1232.     }
  1233. else
  1234.     tarmacbin(name,vrefnum);
  1235. path_len=old_pl;
  1236. svuota_buffer();        /* per approssimare per eccesso a multipli di 512 bytes... */
  1237. }
  1238.  
  1239.  
  1240. void tardata (fname,vrefnum)
  1241.   char *fname;
  1242. {
  1243.     if(bar_archive)
  1244.         bar_header(fname, statb.ioFlLgLen, &tarh);
  1245.     else
  1246.         tarheader(fname, statb.ioFlLgLen);
  1247.     if(expert_mode) print_sector_n(last_sector-1);
  1248.  
  1249.     printf("File %s (%ld bytes)",bar_archive?((barh_type*)&tarh)->name:tarh.name, 
  1250.         statb.ioFlLgLen);
  1251.     if(!binary) printf(" ASCII\n"); else printf("\n");
  1252.  
  1253.     pb.ioParam.ioVRefNum = vrefnum;
  1254.     pb.ioParam.ioVersNum = 0;
  1255.     pb.ioParam.ioPermssn = fsRdPerm;
  1256.     pb.ioParam.ioMisc = 0;
  1257.     pb.ioParam.ioNamePtr = c2pstr(fname);
  1258.     if (PBOpenSync(&pb)) pbsyserr(&pb);
  1259.  
  1260.     devo_chiudere_in=true;
  1261.     tar_writefork(statb.ioFlLgLen, 0);
  1262.     p2cstr(fname);
  1263. }
  1264.  
  1265. void tarmacbin(fname,vrefnum)
  1266.   char *fname;
  1267. {
  1268.     long fsize = macbinsz(statb.ioFlLgLen)+macbinsz(statb.ioFlRLgLen)+128L;
  1269.     if(bar_archive)
  1270.         bar_header(fname, fsize, &tarh);
  1271.     else
  1272.         tarheader(fname, fsize);
  1273.     if(expert_mode) print_sector_n(last_sector-1);
  1274.  
  1275.     printf("MacBinary %s (data %ld+res %ld bytes)\n",
  1276.                 bar_archive ? ((barh_type*)&tarh)->name : tarh.name,
  1277.                 statb.ioFlLgLen, statb.ioFlRLgLen);
  1278.     macbinheader();
  1279.     pb.ioParam.ioVRefNum = vrefnum;
  1280.     pb.ioParam.ioVersNum = 0;
  1281.     pb.ioParam.ioPermssn = fsRdPerm;
  1282.     pb.ioParam.ioMisc = 0;
  1283.     pb.ioParam.ioNamePtr = c2pstr(fname);
  1284.     if (PBOpenSync(&pb)) pbsyserr(&pb);
  1285.     devo_chiudere_in=true;
  1286.     tar_writefork(statb.ioFlLgLen, 1);
  1287.     pb.ioParam.ioVRefNum = vrefnum;
  1288.     pb.ioParam.ioVersNum = 0;
  1289.     pb.ioParam.ioPermssn = fsRdPerm;
  1290.     pb.ioParam.ioMisc = 0;
  1291.  
  1292. #define ioDirID ioFlNum
  1293.     if((pb.fileParam.ioDirID=openfile_dirID)!=0){
  1294.         pb.ioParam.ioVRefNum=openfile_vrefnum;
  1295.         pb.ioParam.ioNamePtr=mac_file_name;
  1296.         }
  1297. #undef ioDirID        /* must not conflict with statb.ioDirID */
  1298.  
  1299.     if (PBHOpenRFSync(&pb)) pbsyserr(&pb);
  1300.     devo_chiudere_in=true;
  1301.     tar_writefork(statb.ioFlRLgLen, 2);
  1302.     /* if (fsize & 511L) writeblock(&tarh, 512 - (fsize & 511L));
  1303.         NO, ci deve pensare svuota_buffer */
  1304.     p2cstr(fname);
  1305. }
  1306.  
  1307. void macbinheader()
  1308. {
  1309.  
  1310.   fillmem(&macbinh.name[macbinh.nlen], 0, 64+63-macbinh.nlen);    
  1311.       /* anche i campi che seguono vanno azzerati... */
  1312.   mcopy(&macbinh.finfo, &statb.ioFlFndrInfo, sizeof(FInfo));
  1313.   macbinh.protected = 0;
  1314.   macbinh.zero = 0;
  1315.   macbinh.dflen = statb.ioFlLgLen;
  1316.   macbinh.rflen = statb.ioFlRLgLen;
  1317.   macbinh.cdate = statb.ioFlCrDat;
  1318.   macbinh.mdate = statb.ioFlMdDat;
  1319.   tarh.name[0]=0;
  1320.   mcopy(&tarh.name[1], &macbinh, sizeof(macbinh));
  1321.   FillMacBin2Fields();
  1322.   writeblock(&tarh, 128);
  1323. }
  1324.  
  1325. void tar_writefork (fsize, macbinp)
  1326.   long fsize;
  1327. {
  1328.   unsigned int n_non_ASCII=0;
  1329.   int blocksz = (macbinp ? 128 : 512);
  1330.   pb.ioParam.ioPosMode = fsAtMark;
  1331.   pb.ioParam.ioBuffer = (Ptr) &tarh;
  1332.   pb.ioParam.ioReqCount = blocksz;
  1333.   while (fsize) {
  1334.     if (fsize < pb.ioParam.ioReqCount)
  1335.         pb.ioParam.ioReqCount = fsize;
  1336.     fsize -= pb.ioParam.ioReqCount;
  1337.     if (PBReadSync(&pb) || pb.ioParam.ioActCount != pb.ioParam.ioReqCount) {
  1338.       int err = pb.ioParam.ioResult;
  1339.       (void) PBCloseSync(&pb);
  1340.       devo_chiudere_in=false;
  1341.       pb.ioParam.ioResult = err;
  1342.       pbsyserr(&pb);
  1343.     }
  1344.     if (!macbinp && !binary) {
  1345.       register char *cp = pb.ioParam.ioBuffer;
  1346.       register int i = pb.ioParam.ioActCount;
  1347.       while (i) {
  1348.         if (*cp == CR) *cp = LF;
  1349.         else if( (unsigned char) *cp >= 128 )
  1350.             n_non_ASCII++;
  1351.         --i, ++cp;
  1352.       }
  1353.     }
  1354.     if(pb.ioParam.ioActCount<blocksz)
  1355.         fillmem(&pb.ioParam.ioBuffer[pb.ioParam.ioReqCount],0,blocksz-(int)pb.ioParam.ioActCount);  /* il tar
  1356.         per UNIX non lo fa, ma Å talmente sporco non farlo */
  1357.     writeblock(pb.ioParam.ioBuffer, blocksz);
  1358.   }
  1359.   if(macbinp==1)
  1360.     get_openfile_location(pb.ioParam.ioRefNum);
  1361.  
  1362.   if (PBCloseSync(&pb)) pbsyserr(&pb);
  1363.   devo_chiudere_in=false;
  1364.   if(n_non_ASCII != 0) printf(in_Italia?"Scritti %u caratteri non ASCII\n":
  1365.       "%u non-ASCII characters were written\n",n_non_ASCII);
  1366. }
  1367.  
  1368. short tarheader (fname, fsize)
  1369.   char *fname;
  1370.   long fsize;
  1371. {
  1372.     long n_sectors=(fsize+511)/512;
  1373.  
  1374.     fillmem(&tarh, 0, 512);
  1375.     mac_to_unix(tarh.name, fname+path_len);
  1376.     if(!strcmp("./",tarh.name) || !tarh.name[0] ) return -1;
  1377.     if (statb.ioFlAttrib & ioDirMask)
  1378.     if (tarh.name[strlen(tarh.name)-1] != '/')
  1379.         tarh.name[strlen(tarh.name)] = '/';
  1380.     numstr(&tarh.mode, (long)((statb.ioFlAttrib & ioDirMask) ? dirmode : filemode), 8);
  1381.     numstr(&tarh.uid, my_uid, 8);
  1382.     numstr(&tarh.gid, my_gid, 8);
  1383.     numstr(&tarh.size, fsize, 12);
  1384.     numstr(&tarh.mtime, (long) statb.ioFlMdDat - UNIXTIME, 12);
  1385.     tarh.linkflag = ((statb.ioFlAttrib & ioDirMask) ? '5' : '0');
  1386.     fill_checksum(&tarh);
  1387.     last_offset=0;
  1388.     questo_e_un_header=true;
  1389.     writeblock(&tarh, 512);
  1390.     last_header=last_sector-1;    /* mi serve il valore pre-incremento, ma eventuali
  1391.                 header di volume devono essere contati... */
  1392.  
  1393. /* remember what you are going to write: it's useful for the 'M' continuation
  1394. header, and also for checks before clearing this same sector later if
  1395. I can't successfully save on disk the whole file
  1396. */
  1397.     copia_ultimo_header(&tarh,last_sector);    /* valore post-incremento */
  1398.     controlla_che_ci_stia((int)n_sectors);
  1399.     return 0;
  1400. }
  1401.  
  1402. void fill_checksum(t)
  1403. register tarh_type *t;
  1404. {
  1405.     register long chksum = 0;
  1406.     register int i;
  1407.     fillmem(t->chksum, ' ', 8);
  1408.     if(uname[0]||gname[0]){
  1409.         strcpy(t->magic, "ustar  ");
  1410.         strcpy(t->uname, uname);
  1411.         strcpy(t->gname, gname);
  1412.         }
  1413.         for(i=0; i<512; ++i) chksum += (unsigned char)t->name[i];
  1414.     numstr(t->chksum, chksum, 8);
  1415. }
  1416.  
  1417. /* Don't allow absolute names.   "HD:foo:bar" becomes "./foo/bar" */
  1418. void mac_to_unix(uname, mname)
  1419. char *uname, *mname;
  1420. {
  1421.   register char *dp = uname, *cp;
  1422.   register unsigned char c;
  1423.   register int namelen;
  1424.   if (cp = strchr(mname, ':')) {
  1425.   #ifdef DOT_SLASH_NAME
  1426.       *dp++ = '.', *dp++ = '/';
  1427.   #endif
  1428.        ++cp;
  1429.        }
  1430.   else
  1431.       cp = mname;
  1432.  
  1433.   for(;;) {
  1434.     while (*cp == ':') *dp++ = '.', *dp++ = '.', *dp++ = '/', ++cp;
  1435.     namelen=0;
  1436.     while (*cp && *cp != ':'){
  1437.         /* modified by Speranza to handle in some way non-ASCII codes 128 and upper,
  1438.         and characters which the UNIX shell uses.
  1439.         Really we're not so expert of UNIX to know the better thing to do with
  1440.         every character under every shell and/or file utility: the rule which
  1441.         is often given is "use only letters, digits, underscore and dot" but
  1442.         a few other characters are usually good */
  1443.         c=*cp++;
  1444.  
  1445.         if(c>=127){
  1446.             static char s1[]="Çàèܺ«╛╬╧¬";
  1447.             static char s2[]="⌐»┐╦╠═╪";
  1448.             char *p;
  1449.             if((p=strchr(s1,c))){    /* special characters with a two-character transliteration */
  1450.                 if(!trunc_14 || namelen<14)
  1451.                     *dp++="AOaosAaOot"[p-s1];
  1452.                 namelen++;
  1453.                 c=    "eeeeseeeem"[p-s1];
  1454.                 }
  1455.             else if(c>=128 && c<160)    /* remove accents, tilde etc. */
  1456.                 c= "AACENOUaaaaaaceeeeiiiinooooouuuu"[c-128];
  1457.             else if((p=strchr(s2,c)))
  1458.                 c= "cOoAAOy"[p-s2];
  1459.             else if( (c==208 || c==209) && namelen!=0)
  1460.                 c='-';
  1461.             else if(c==202&&!suppress_shell_chars)    /* non-breakable space */
  1462.                 c=' ';
  1463.             else
  1464.                 c='\0';
  1465.             }
  1466.         else if(suppress_shell_chars){
  1467.                 /* many characters have a special meaning to the UNIX shell, but some
  1468.                 only when used as first character of an identifier */
  1469.             if(c==' ')
  1470.                 c='_';
  1471.             else if(strchr(";|^*?\'\\`\"!$@<>&()[],",c) )
  1472.                 c= '\0';
  1473.             else if(namelen==0 && strchr("~%-.#",c) )
  1474.                 c= '\0';
  1475.             }
  1476.         if (c<' '){
  1477.             #define REPLACER '+'
  1478.             if(namelen!=0 && (*(dp-1)==REPLACER||*(dp-1)=='_' ) )
  1479.                 ;        /* suppress it ! */
  1480.             else
  1481.                 if(!trunc_14 || namelen<14) *dp++ = REPLACER;
  1482.             }
  1483.         else{
  1484.             if(c=='/') c=':';
  1485.             if(!trunc_14 || namelen<14) *dp++ = c;
  1486.             }
  1487.         namelen++;
  1488.         }
  1489.     if (!*cp++) break;
  1490.     *dp++ = '/';
  1491.   }
  1492.   if (strlen(uname) >= 100) nametoolong(mname);
  1493. }
  1494.  
  1495. void numstr (p, num, count)
  1496. register char *p;
  1497. register long num;
  1498. register int count;
  1499. {
  1500. /* come fatto da Zacharias lasciava un sacco di '0' in testa, l'unico modo 
  1501. per non farlo Å scrivere in un buffer e poi copiare
  1502. -- I (G. Speranza) don't like how Zacharias did it, he wrote directly to
  1503. the destination filling extra space at the beginning with '0's !  It's
  1504. also a risk for compatibility, since the UNIX tar and bar don't write 
  1505. things in that way.
  1506. */
  1507. char buffer[14];
  1508.   buffer[--count] = '\0';
  1509.   if (count != 11) buffer[--count] = ' ';
  1510.   if(count!=0){
  1511.       do{
  1512.         buffer[--count] = '0' + ((int)num & 7);
  1513.         num >>= 3;
  1514.         }
  1515.       while (count && num);
  1516.     }
  1517. strcpy(p,&buffer[count]);
  1518. }
  1519.  
  1520. void statf (fname)
  1521.   char *fname;
  1522. {
  1523.   char name[256];
  1524.   statb.ioNamePtr = c2pstr(strcpy(name, fname));
  1525.   statb.ioFVersNum = 0;
  1526.   statb.ioVRefNum = curr_vrefnum;
  1527.   statb.ioFDirIndex = 0;
  1528.   statb.ioDirID = 0;
  1529.   if (PBGetCatInfoSync(&statb) || statb.ioResult) pbsyserr(&statb);
  1530.   statb.ioNamePtr = NULL;
  1531. }
  1532.  
  1533. short getvrefnum (fname)
  1534.   char *fname;
  1535. {
  1536. /* ho il sospetto che non serva pi¥, se serve solo a sapere il vrefnum attuale...
  1537. no, a volte curr_vrefnum Å 0, forse serve, e comunque sono poche istruzioni
  1538. */
  1539.   HVolumeParam hpb;
  1540.   char name[256];
  1541.   hpb.ioNamePtr = c2pstr(strcpy(name, fname));
  1542.   hpb.ioVRefNum = 0;
  1543.   hpb.ioVolIndex = 0;
  1544.   if (PBHGetVInfoSync(&hpb) || hpb.ioResult) pbsyserr(&hpb);
  1545.   return hpb.ioVRefNum;
  1546. }
  1547.  
  1548. void nametoolong (name)
  1549.   char *name;
  1550. {
  1551.   printf("\"%s\" - name too long\n", name);
  1552.   raise_error();
  1553. }
  1554.