home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / suntar1.cpt / Untar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-15  |  85.6 KB  |  2,906 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 muntar version 1.0.
  9.  *
  10.  */
  11.  
  12. /* the original muntar program was then altered to become part of suntar:
  13. */
  14.  
  15. /*******************************************************************************\
  16.  
  17. tar reading 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. comments in the text explain which routines were added for suntar by us and
  27. which ones are from muntar, but most of the latter were modified more or less 
  28. heavily by us
  29. */
  30.  
  31. #define USA_CURRVREFN
  32.  
  33.  
  34.  
  35. #include "PB_sync.h"
  36. #include "antiglue.h"
  37. #include "windows.h"
  38. #include "suntar.h"
  39.  
  40. /*#include <FileMgr.h>
  41. #include <OSUtil.h>
  42. #include <HFS.h>*/
  43. #include <string.h>
  44. /* #include <errors.h> */
  45.  
  46. #define ASM
  47.  
  48. #define tarsz(n)    (((n)+511L) & -512L)
  49. #define  macbinsz(n)    (((n)+127L) & -128L)
  50.  
  51. char *strrchr();
  52.  
  53.  
  54. struct binh_type macbinh;
  55. tarh_type tarh;
  56. unsigned char disk_buffer [512];
  57.  
  58. OSType filecreator,filetype;
  59. unsigned char listonly=0;
  60.  
  61. /* alcune routines sue un po' riscritte (ho il sospetto esistano in libreria o nella ROM,
  62. ma non so con che nomi e che parametri, tanto vale riscriversele
  63. */
  64.  
  65.  
  66. StringPtr c2pstr(p)
  67. register char p[];
  68. {
  69. register int i,len=strlen(p);
  70. for(i=len;i>0;i--)
  71.     p[i]=p[i-1];
  72. p[0]=len;
  73. return (StringPtr) p;
  74. }
  75.  
  76. char * p2cstr(p)
  77. register unsigned char p[];
  78. {
  79. register int i,len=p[0];
  80. for(i=0;i<len;i++)
  81.     p[i]=p[i+1];
  82. p[len]='\0';
  83. return p;
  84. }
  85.  
  86. /* main() l'ho tolto di torno...
  87. {
  88. printf(
  89. "This is freeware.  If you paid money for this program, you got ripped off.\n");
  90.   return;
  91. }
  92. */
  93.  
  94. int binary=true; /* se convertire LF-CR o no */
  95. #define UNIXTIME    2082844800L  /* Jan 1, 1970 00:00:00 */
  96.  
  97. #ifndef ASM
  98. /* simple implementation */
  99. void mcopy(dest, src, len)
  100. register char*dest,*src;
  101. register unsigned short len;
  102. {
  103.     while ((short)--len>=0) *dest++ = *src++;
  104. }
  105. #endif
  106.  
  107.  
  108. /******************** start of routines by Speranza ***********************/
  109.  
  110. #ifdef ASM
  111. void mcopy(char * dest,char * src,unsigned short len )
  112.  
  113. /* optimazed implementation, remembering that the 68000 is a 32 bit machine
  114. and may move 4 bytes at a time, at least if they are placed at an even address
  115. (since the compiler places at even addresses the start of all data structures, 
  116. that means almost always)
  117. By Gabriele Speranza, 17 Nov 1991
  118. */
  119.  
  120. {
  121. extern SysEnvRec    gMac;
  122. /* #define EXPLOIT_020 */
  123. asm {
  124.     move.l    dest,a0
  125.     move.l    src,a1
  126.     move.w    len,d1
  127.         /* 
  128.         #ifndef EXPLOIT_020 / * suntar uses mcopy only for small * /
  129.             / * copies, and those which are not aligned are rarely big, * /
  130.             / * probably it's not worth of it, that symbol is NOT defined * /
  131.         if(len>=10 && !((((long)dest)^((long)src))&1) ){
  132.             / *    if the transfer is long enough and the pointers have the same parity * /
  133.         #else
  134.         if(len>=10 && ( gMac.processor>=env68020 || !((((long)dest)^((long)src))&1) ) ){
  135.             / * the 68020 and later CPUs do not require same parity * /
  136.         #endif
  137.         */
  138.     cmp.w    #10,d1
  139.     blt.s    @inloop
  140.     move.l    a0,d0
  141. #ifdef EXPLOIT_020
  142.     cmp.w    #env68020,gMac.processor
  143.     bge        @ok_to_movelong
  144. #endif
  145.     move.l    a1,d2
  146.     eor.l    d0,d2
  147.     lsr.l    #1,d2
  148.     bcs.s    @inloop
  149. ok_to_movelong:
  150.  
  151.         /* if(((long)dest)&1){
  152.                 *dest++ = *src++;    / * both odd=>move one byte to get both even * /
  153.                 len--;
  154.                 }
  155.         */
  156.     lsr.l    #1,d0
  157.     bcc.s    @l1
  158.     move.b    (a1)+,(a0)+
  159.     subq.w    #1,d1
  160.     addq.l    #1,d0    /* se il LSB era 1, aggiungere 1 provoca carry sul bit 1 
  161.                     -- bit 0 was shifted out, and was 1: adding 1 to bit 0 will cause
  162.                     a carry to bit 1, but bit 1 was shifted to bit 0...*/
  163.         /* if(((long)dest)&2){
  164.             / * now I have two even addresses, and that's good. But a destination 
  165.             at an address multiple of 4 better exploits a 32 bit bus.
  166.             Obviously, the same is for the source, but in 50% of cases aligning one
  167.             aligns the other too, and the cache works better when reading, hence a 
  168.             misalignment on reading is less bad then on writing.
  169.             Really, I've an LC where the bus is 16 bit wide, and the cache is used
  170.             only for instructions, so this trick is not fully exploited on my machine! * /
  171.             *((short*)dest)++ = *((short*)src)++;
  172.             len -= 2;
  173.             }
  174.         */
  175. l1:    lsr.l    #1,d0
  176.     bcc.s    @l2
  177.     move.w    (a1)+,(a0)+
  178.     subq.w    #2,d1
  179.         /*
  180.             for(temp=len/4;temp;temp--)
  181.                 *((long*)dest)++ = *((long*)src)++;
  182.             len %=4;
  183.         */
  184. l2:    move.w    d1,d0
  185.     lsr.w    #2,d0
  186.     subq.w    #1,d0
  187. loop1:move.l (a1)+,(a0)+
  188.     dbra d0,@loop1
  189.     and.w    #3,d1    /* up to 3 further bytes may have to be moved ... */
  190.         /*
  191.             }    / * end if: now move byte-wise anything is remaining, 
  192.                 that is all the job if couldn't move long-wise * /
  193.             while (len-- >0) *dest++ = *src++;
  194.         */
  195.     bra.s    @inloop
  196. loop2:    move.b (a1)+,(a0)+
  197. inloop:    dbra d1,@loop2
  198.     }
  199. }
  200. #endif
  201.  
  202. #define dp printf
  203.  
  204.  
  205. Boolean chiedi_su_questo(int,sector_t,char*);
  206. OsErr verifica_nome(int,sector_t *);
  207. short isMacBin2(unsigned char*);
  208. void make_badname(char*,char*);
  209. Boolean too_long(char *);
  210. Boolean is_gif_file(long);
  211. short gestisci_nome_doppio(char *,char*,FileParam *);
  212. static void skip_macbinII(int);
  213. void cancella_file_aperto(short);
  214.  
  215. jmp_buf main_loop;
  216. long file_date;
  217. unsigned char mac_file_name[120];    /* deve poter contenere un path completo...*/
  218. int openfile_vrefnum;
  219. long openfile_dirID;
  220.  
  221. int more_in_bytes;    /* I don't remember the number of bytes currently in the 
  222.                     buffer, but more_in_bytes = 512-number of bytes = free space */
  223. sector_t sect_n;
  224. ParamBlockRec pb;    /* Å diventata una variabile globale per poter chiudere il file in
  225.                     caso di errore; proprio per questo perÿ ha senso che anche il nome
  226.                     del file, puntato da un campo del record, sia globale */
  227. #define ioDirID ioFlNum
  228. int floppy_n;
  229. Boolean bar_archive;
  230. static Boolean notTrueMacBinary,MacBinaryII;
  231. static unsigned short mbIIsec_head_len;
  232. Boolean all_listonly;
  233. Boolean devo_chiudere_out=false;
  234. /* gruppetto di variabili usate per la verifica di un header 'M' del GNU tar, ma
  235. anche per altri scopi, sia in lettura sia in scrittura */
  236. Boolean ultimo_header_valido;
  237. Boolean ultimo_disco_espulso;    /* il disco contenente quell'ultimo header Å stato
  238.                                 espulso ? */
  239. Boolean hasVheader;
  240. char ultimo_header[184];        /* usata anche per altri scopi, viene SEMPRE aggiornata
  241.                                 coi primi 184 bytes dell'ultimo header, tar o bar, che
  242.                                 si Å letto o scritto
  243.                                 -- I always copy here the first 184 bytes of any 
  244.                                 tar or bar file header which is being read (here) or
  245.                                 written (in tar.c)
  246.                                 */
  247. long last_offset;        /* solo per GNU tar */
  248. sector_t next_header_for_AIX;    /* only for tar archives, useful only for AIX:
  249.                             -1 if next header is on same disk, otherwise number
  250.                             of sector in next disk */
  251. sector_t avail_sectors_for_file;    /* = sectors_on_floppy - sect_n successivo di quando ho 
  252.                                     caricato ultimo_header
  253.                             -- = sectors_on_floppy - the sector following the header
  254.                             */
  255.  
  256.  
  257. /* titoli italiani dei bottoni dei dialoghi modali 
  258. -- italian titles of the buttons */
  259. char *titoli[]={"\pSô","\pNo","\pTermina"};
  260. static char *t1[]= {"\pContinua qui","\pContinua altrove","\pNon salvare"};
  261. char s_spazi[]="              ";
  262.  
  263. /****************************/
  264.  
  265. /* do some buffering towards the hard disk. If I write in relatively small
  266. pieces (e.g. 5Kbytes) the Mac freezes for a few seconds from time to time,
  267. (maybe flushing the disk buffers?) yielding big total times. With 10K
  268. everything works regularly and about two times faster (three times faster than
  269. suntar 1.2.2, thanks to some other improvements).
  270. */
  271.  
  272. static char*hd_buffer;
  273. static short bytes_in_hd_buffer;
  274.  
  275. unsigned int hd_buffer_size;
  276.  
  277. void init_hd_buffering()
  278. {
  279. ResrvMem ((Size)hd_buffer_size);
  280. hd_buffer=NewPtr((Size) hd_buffer_size);
  281. check_allocated(hd_buffer);
  282. }
  283.  
  284. #define reinit_hd_buffering() bytes_in_hd_buffer=0
  285.  
  286. OSErr flush_hd_buffer(void);
  287. static OSErr flush_hd_buffer()
  288. {
  289. OSErr err;
  290. if(!bytes_in_hd_buffer) return noErr;
  291.  
  292. pb.ioParam.ioPosMode = fsAtMark;
  293. pb.ioParam.ioPosOffset = 0;
  294. pb.ioParam.ioBuffer = hd_buffer;
  295. pb.ioParam.ioReqCount=bytes_in_hd_buffer;
  296. bytes_in_hd_buffer=0;
  297. if( (err=PBWriteSync(&pb)) || pb.ioParam.ioResult) return pb.ioParam.ioResult;
  298.  
  299. if(pb.ioParam.ioReqCount != pb.ioParam.ioActCount) return ioErr;
  300. return noErr;
  301. }
  302.  
  303. OSErr write_hd(char*,short);
  304. static OSErr write_hd(buffer,size)
  305. char*buffer;
  306. short size;
  307. {
  308. OSErr i;
  309. if(bytes_in_hd_buffer>hd_buffer_size-size)
  310.     if((i=flush_hd_buffer())) return i;
  311. mcopy(hd_buffer+bytes_in_hd_buffer,buffer,size);
  312. if((bytes_in_hd_buffer+=size)==hd_buffer_size)
  313.     return flush_hd_buffer();
  314. return noErr;
  315. }
  316.  
  317. /******************************/
  318.  
  319. short readblock(buf,nbytes)
  320. /* this routines translates from the sector-based view of the device driver
  321. to the "byte stream" view used by most of the program, by buffering reads
  322. and controlling disk swaps
  323. Never call it asking for more than 512 bytes, the "buffer fill" operation is
  324. performed at most once.
  325. */
  326. register char*buf;
  327. int nbytes;
  328. {
  329. int i;
  330.  
  331. /*printf("readblock(%d)\n",nbytes);*/
  332. if(more_in_bytes<nbytes){
  333.     if(more_in_bytes){
  334.         nbytes-=more_in_bytes;
  335.         mcopy(buf,&disk_buffer[512-more_in_bytes],more_in_bytes);
  336.         buf+=more_in_bytes;
  337.         }
  338.     if(bar_archive)
  339.         bar_check_floppy_swap(0);
  340.     else
  341.         tar_check_floppy_swap(0);
  342.     leggi_settore(sect_n,&disk_buffer);
  343.  /*printf("leggo settore %ld,err=%d\n",(long)sect_n,err_code);*/
  344.      if((i=check_error_and_events())<0) return err_code;
  345.      if(i>0){    /* "missing disk" was converted to a pause event, now the disk
  346.                  should be in, but I must repeat the operation */
  347.         leggi_settore(sect_n,&disk_buffer);
  348.          if(check_error()) return err_code;
  349.          }
  350.     more_in_bytes=512;
  351.     sect_n++;
  352.     settori_passati++;
  353.     }
  354. mcopy(buf,&disk_buffer[512-more_in_bytes],nbytes);
  355. more_in_bytes-=nbytes;
  356. return 0;
  357. }
  358.  
  359. void unget_block()
  360. {
  361. /* viene chiamata per l'unget dei primi bytes di un file, quindi
  362. -- used to unget the first bytes of a file: they are still in the buffer, hence:
  363. */
  364. more_in_bytes=512;
  365. }
  366.  
  367. void unget_char()
  368. {
  369. more_in_bytes++;
  370. }
  371.  
  372. /*
  373. attenzione che anche nei moduli dehqx e unpit uso i buffer e more_in_bytes !
  374. -- caution: modifying the above functions, take a look at hqx_end_of_file &
  375. get_hqx_byte & fast_get_hqx_byte in dehqx.c, and fast_get_pit_byte in unpit.c,
  376. which are partially copied from the above and use the same data structures
  377. */
  378.  
  379.  
  380. void end_of_file()
  381. {
  382. /* Å chiamata per saltare sopra gli ultimi bytes prima dell' header del file
  383. seguente, quindi non c'Å che passare al settore successivo
  384. -- it skips the last bytes of the current sector: next read will read
  385. an header which is aligned at the start of a sector
  386. */
  387. more_in_bytes=0;
  388. }
  389.  
  390. void skip_file(fsize)
  391. /* it increments the sector number: the disk swap routines are designed to 
  392. handled case when the requested sector is not the first sector in next disk */
  393. long fsize;
  394. {
  395. if(fsize<=512)return;    /* il primo settore Å giê stato letto */
  396. sect_n+= (fsize-1) >>9;
  397. }
  398.  
  399.  
  400. /*************************/
  401.  
  402. void stampa_buffer(sect_n,buffer)
  403. /* utilissima nel debugging
  404. -- it was written for debugging, then it became a permanent part of the program
  405. executing the View sector command
  406. */
  407. sector_t sect_n;
  408. unsigned char *buffer;
  409. {short i,j=0,x;
  410. disable_autoflush();
  411. for(i=0;i<512;i++){
  412.     if((x=buffer[i])<16)
  413.         printf("0%x",x);
  414.     else if(x>=' '&&x<127)
  415.         printf(" %c",x);
  416.     else
  417.         printf("%x",x);
  418.     if(j==24){
  419.         put_char('\n');
  420.         j=0;
  421.         }
  422.     else{
  423.         put_char(' ');
  424.         j++;
  425.         }
  426.     }
  427. printf("        end of sector %ld\n",(long)sect_n);
  428. enable_autoflush();
  429. }
  430.  
  431. /***************************/
  432.  
  433. short isASCII(fsize,nLF)
  434. /* decide if the file is ASCII examining the first sector of its data
  435. (which was already read by chkmacbin, or is read and ungetted here)
  436. returns:
  437. 1 it's ASCII
  438. 0 it's not ASCII
  439. -1 the percentage of ASCII bytes is high enough to deserve a 'TEXT' type,
  440.     maybe that file was created on a Mac which gives a meaning to many
  441.     not ASCII chars (e.g. ⌐), but it's too low to choose to modify the 
  442.     data by automatically converting any LF to CR...
  443. */
  444. long fsize;
  445. int*nLF;
  446. {
  447. register int i,n_non_ASCII;
  448. int nbytes;
  449. register char c;
  450.  
  451. nbytes= fsize>512? 512 : fsize;
  452. if(nbytes==0) return 0;  /* troppo corto per 
  453.     decidere, e se Å 0 non ha senso dargli l'icona di testo... */
  454. if(more_in_bytes==0){
  455.     if(readblock(nLF,1)) raise_error();    /* fill the disk_buffer...*/
  456.     unget_block();
  457.     }
  458. *nLF=0;
  459. n_non_ASCII=0;
  460. for(i=nbytes-1;i>=0;i--){
  461.     c=disk_buffer[i];
  462.     if(c>=' ' && c <= 126)
  463.         ;    /* ASCII */
  464.     else if(c==CR || c== '\t' || c=='\f')
  465.         ;
  466.     else if(c==LF)
  467.         (*nLF)++;
  468.     else{
  469.         if(++n_non_ASCII>(14+(512>>5))) break;
  470.         }
  471.     }
  472. if( !n_non_ASCII && (nbytes>=80  || smallFilesAreASCII) ) return 1;
  473. return n_non_ASCII > 14+(nbytes>>5) ? 0 : -1;
  474. }
  475.  
  476. Boolean print_if_string(format,buffer,size)
  477. char*format,*buffer;
  478. {
  479. /* for error reporting: something coming from a sector containing errors is printed
  480. only if it looks like a string (only ASCII characters, a terminating '\0', no '\n'... */
  481. int i=0;
  482. size--;
  483. while(i<size && buffer[i]>=' ' && buffer[i]<127 )
  484.     i++;
  485. if(i==0 || buffer[i]) return false;    /* empty string or end of string not reached */
  486. printf(format,buffer);
  487. return true;
  488. }
  489.  
  490. /***************************/
  491.  
  492. void my_untar()        /* intermediate-level handler of the Extract and List commands */
  493. {
  494. int fine,i;
  495. long lunghezza_file();
  496.  
  497. more_in_bytes=0;
  498. bar_archive=0;
  499. all_listonly=listonly;
  500.  
  501. tar_check_floppy_swap(1);    /* ci sono delle inizializzazioni
  502.     -- obviously I don't swap disks before beginning, but it 
  503.     initializes some variables and checks sector 0
  504.     */
  505. do{
  506.     
  507.     leggi_settore(sect_n,&disk_buffer);
  508.     if(err_code==eofErr)
  509.         fine=true;
  510.     else{
  511.          if((i=check_error_and_events())<0) raise_error();
  512.          if(i>0){
  513.             leggi_settore(sect_n,&disk_buffer);
  514.              if(check_error()) raise_error();
  515.              }
  516.         fine=check_all_zero(disk_buffer);
  517.         }
  518.     if(!fine){
  519. /*printf("n_settori=%ld\n",((untar_number(&disk_buffer[124],false)+511)/512) );*/
  520.  
  521.         untar();
  522.         tar_check_floppy_swap(-1);
  523.         }
  524.     }
  525. while(!fine);
  526. if(sect_n==0){
  527.     one_empty_line();
  528.     printf(in_Italia?"Archivio vuoto\n":"No files in the archive\n");
  529.     }
  530. else{
  531.     if(expert_mode)
  532.         print_sector_n(sect_n);
  533.     else
  534.         printf("\n");
  535.     printf(in_Italia?"Fine archivio\n":"End of archive\n");
  536.     }
  537. }
  538. /************** gestione del formato bar *************/
  539. /* bar format handling */
  540.  
  541. void my_unbar()
  542. {
  543. int fine,i;
  544.  
  545. bar_archive=1;
  546. all_listonly=listonly;
  547. more_in_bytes=0;
  548.  
  549. bar_check_floppy_swap(1);
  550.  
  551. do{
  552.     leggi_settore(sect_n,&disk_buffer);
  553.     if(err_code==eofErr)
  554.         fine=true;
  555.     else{
  556.          if((i=check_error_and_events())<0) raise_error();
  557.          if(i>0){
  558.             leggi_settore(sect_n,&disk_buffer);
  559.              if(check_error()) raise_error();
  560.              }
  561.         fine=check_all_zero(disk_buffer);
  562.         }
  563.  
  564.     if(!fine){
  565.         unbar();
  566.         bar_check_floppy_swap(-1);
  567.         }
  568.     }
  569. while(!fine);
  570. if(expert_mode)
  571.     print_sector_n(sect_n);
  572. else
  573.     printf("\n");
  574. printf(in_Italia?"Fine archivio\n":"End of archive\n");
  575. }
  576.  
  577.  
  578. short unbar_checksum(buffer,do_error,exp_check)
  579. register unsigned char *buffer;
  580. long *exp_check;
  581. {
  582. register int i;
  583. register long chksum;
  584. long hchksum;
  585.  
  586. hchksum = untar_number(((barh_type*)buffer)->chksum,do_error);
  587. if(hchksum==-1) return -2;        /* testata non bar */
  588. chksum= ' ' * 8;    /* nel calcolo del checksum, il campo checksum era sostituito
  589.                     da spazi */
  590. for (i=0; i < 48; ++i)
  591.     chksum += (unsigned char)buffer[i];
  592. for (i+=8; i < sizeof(tarh); ++i)
  593.     chksum += (unsigned char)buffer[i];
  594.  
  595. *exp_check=chksum;
  596.  
  597. if (chksum == hchksum) return 0;    /* tutto OK */
  598.  
  599. /* il fatto e' questo: quando bar calcola il checksum del settore zero, il campo
  600. size contiene '0','\0'. Perÿ, per un orribile bug, i 10 bytes successivi non vengono 
  601. affatto azzerati ma contengono ancora la parte finale del campo size del disco 
  602. precedente, e se il nuovo valore di size, che viene scritto DOPO aver calcolato il 
  603. checksum, Å abbastanza lungo succede che parte dei bytes usati per il calcolo del 
  604. checksum vengono irrimediabilmente sovrascritti, e non ho pi¥ modo di calcolarlo 
  605. correttamente.
  606.  Ma d'altra parte a me fa molto comodo poter controllare il checksum, quindi mi rassegno
  607. al fatto che un errore puÿ esserci, ma controllo che questo errore sia compatibile con
  608. questo comportamento errato, senza perÿ strafare, in fondo altre versioni di bar
  609. potrebbero aver corretto il bug: cioÅ, controllo che il checksum letto sia giustificabile
  610. con un numero di cifre ottali <= del numero di caratteri sovrascritti dal nuovo valore
  611. di size, e ipotizzo anche che la correzione del bug consista nel calcolare il checksum
  612. quando sarebbe logico, dopo aver riscritto size.
  613.  
  614. -- The checksum computation of the volume header is one of the most 
  615. horrible aspects of bar (file headers are OK, fortunately). For some 
  616. unknown reason, bar saves the volume header in a reserved place, so
  617. the next volume header is built without reinitializing all fields:
  618. 1) the volume_num is updated
  619. 2) the size field is replaced by "0" (a '0' followed by a '\0'):
  620.    since that field is 12 bytes long, 10 bytes of the old value are not
  621.    altered by that operation
  622. 3) the checksum is computed and stored
  623. 4) the new value of size is now stored in the size field (strangely, since
  624.    file header checksums are always computed after filling all other fields):
  625.    since it's in octal and is multiple of 512, either it's 0 or it's at least 
  626.    4 bytes long, so it overwrites part of the non-fixed data used to compute 
  627.    the checksum
  628. Hence, the size field is not protected by the checksum (not a tragedy, the
  629. whole file data is not protected by any checksum...) and the cheksum is computed
  630. using some data which is no more stored on the current disk. In fact, bar 
  631. simply ignores the volume checksum, but it could check it by obliging you to 
  632. always insert all disks of the archive in the correct order (on the first disk the
  633. "old size" is 0, on other disks it's the previous size field partially overwritten
  634. by "0").
  635. But suntar allows you to insert disks in any order, starting extraction from
  636. any disk. Furthermore, it automatically distinguishes between a tar and bar
  637. archive, and the checksum of sector 0 looks like the better way to 
  638. guide the choice.
  639. Hence, this function returns:
  640. 0     OK, the checksum is valid for a file header (the write commands of suntar
  641.     computes checksums of volume headers as if they were file headers, by
  642.     updating the size field before computing the checksum)
  643. 1   the checksum is bad as a file header, but the error could be due to some 
  644.     binary zeros and some unknown octal digits overwritten by what is currently
  645.     in the size field: that is, it could be a valid checksum for a volume header
  646. -1  the checksum is invalid anyway
  647. -2  the checksum field did not contain an octal string
  648.  
  649. */
  650.  
  651. {
  652. register int s;
  653. s=0;
  654. for(i=0;((barh_type*)buffer)->size[i]!=0; ++i){
  655.     s+= (unsigned char)((barh_type*)buffer)->size[i];
  656.     }
  657. chksum -= s;
  658. }
  659.  
  660. if( hchksum<chksum || hchksum > chksum + (i+1)*'7' )    /* i contiene ancora la
  661.                             dimensione della stringa size, il +1 per il \0 in fondo */
  662.     return -1;    /* bad checksum */
  663.     /* there are still some values which are forbidden: e.g. there is a hole between
  664.     "7\0"=55 and "00"=96, however "7777777\0" is > "00000000" hence the last hole
  665.     occurs when there are 7 bytes */
  666. if(i+1 > 7) return 1;
  667. i= ((int)(hchksum-chksum))/'0';        /* that's the number of octal digits, supposing
  668.                                     that all other chars are binary zeros */
  669. if(i>=8) i=7;    /* "77777777"/'0' yields 8, but without doubts it contains 7 digits */
  670. if( (int)(hchksum-chksum) <= i*'7')
  671.     return 1;    /* l'errore Å giustificabile con i caratteri sporcati dal bug di bar */
  672. return -1;
  673.  
  674. }
  675.  
  676.  
  677.  
  678. unsigned char guess_bar_linkflag()
  679. /* il campo prima del linkflag che in teoria dovrebbe essere vuoto in pratica Å pieno
  680. e a volte sborda sul linkflag: a prima vista sembra che il linkflag sia scritto dopo, 
  681. era comunque sempre '0' per i file, ma '6' per una directory, invece del '5' che
  682. mi aspetterei secondo la codifica tar (un'altra volta era '5', ma quando il campo
  683. precedente non sborda Å '\0'). Per di pi¥, gli hard link (ma non quelli simbolici) hanno
  684. il campo size != 0 ( e il linkflag corretto, '1'), anche se poi non segue nessun byte. 
  685. Meglio continuare a fare a meno del linkflag nel capire che razza di entry Å... 
  686.  
  687. -- second horrible feature of bar: the rdev field should always be binary zeros
  688. for conventional files and directories, hence it should not be of interest
  689. to a program running on the Macintosh. On the contrary, it contains data, and
  690. I don't know what that data means. The horrible thing is that when that number
  691. was negative, it's written anyway as a 32 bit unsigned octal number, and that
  692. occupies 12 bytes, overflowing the rdev field and overwriting the linkflag
  693. field: it happens often, about one time out of two (and files in the same 
  694. subdirectories tend to either have all the problem or not have it at all).
  695.  So, the linkflag field can't be relied upon, and it should have been the most
  696. important field of the header, the first thing to look at!
  697.  If the original bar succeed to survive to such a disaster, there must be a way:
  698. here is what we succeeded to guess by a lot of testing:
  699. 1) folders may be distinguished since their name ends in '/': that was easy
  700. 2) links can be distinguished since the linkname field is full: however,
  701.    unlike tar and unlike what the documentation of bar says, the linkname field
  702.    really starts at the first byte after the '\0' which terminates the string
  703.    in the name field. The simple solution of suntar 1.0, consider that as a
  704.    file entry, works for symbolic links (obviously creating an empty file during
  705.    extraction) but does not work for hard links, whose size field is not 0
  706.    even if the archive contains 0 bytes of their contents
  707. 3) anything else is considered to be a normal file
  708.  If there will be any problem in this approach, the fault is not ours: the
  709. fault is of that fellow who after doing such a blatant bug, did not correct
  710. it and allowed it to remain in a program which was used for years and is now
  711. at the version number 4.51, if I remember well. Obviously, if we could have a 
  712. look at the source of the original bar we would be surer of what we are doing,
  713. but that would not make the thing less horrible.
  714. */
  715. {
  716. short l;
  717. l=strlen(((barh_type*)disk_buffer)->name);
  718. if( ((barh_type*)disk_buffer)->name[l-1] == '/')
  719.     return '5';
  720. else if( ((barh_type*)disk_buffer)->name[l+1] ) /* perchÄ il link name non sta 
  721.             affatto nel campo omonimo...
  722.             -- remember that the linkname is not placed in the linkname field */
  723.     return '1';
  724. else
  725.     return '0';
  726. }
  727.  
  728.  
  729. void unbar()
  730. {
  731. unsigned char linkflag;
  732. long exp_check;
  733.  
  734. if(expert_mode) print_sector_n(sect_n);
  735. sect_n++;
  736. more_in_bytes=0;
  737. if( unbar_checksum(&disk_buffer,1,&exp_check) != 0 ){
  738.     tarh.name[99]='\0';    /* non si sa mai che cosa ci sia...*/
  739.     printf("Bad header checksum ");
  740.     if(expert_mode){
  741.         if( print_if_string("(got %s expected ",((barh_type*)disk_buffer)->chksum,8))
  742.             printf("%lo) ",exp_check);
  743.         }
  744.     if(!ignore_errors) raise_error();
  745.     put_char('\n'); printf(s_spazi);
  746.     }
  747. strcpy(tarh.name,((barh_type*)disk_buffer)->name);
  748. copia_ultimo_header(disk_buffer,sect_n);
  749.  
  750. file_date= untar_number( &disk_buffer[36],false);
  751.  
  752. linkflag=guess_bar_linkflag();
  753.  
  754. if (linkflag=='5')
  755.     untar_directory();
  756. else if(linkflag=='1')
  757.     printf("Link %s -> %s%s\n", tarh.name,
  758.         &((barh_type*)disk_buffer)->name[strlen(((barh_type*)disk_buffer)->name)+1],
  759.         listonly?"":in_Italia?" (ignorato)":" (ignored)");
  760. else
  761.     untar_file(untar_number(((barh_type*)disk_buffer)->size,1));
  762. }
  763.  
  764. void copia_ultimo_header(p,sector_n)
  765. /* copies the first 184 bytes of the header where it must be copied, and 
  766. sets some related variables */
  767.  
  768. char*p;        /* puntatore al buffer contenente un header di file o directory */
  769. sector_t sector_n;    /* numero del settore che segue quello in cui l'header Å stato scritto */
  770. {
  771. mcopy(ultimo_header,p,sizeof(ultimo_header));
  772. ultimo_header_valido=true;
  773. ultimo_disco_espulso=false;
  774. avail_sectors_for_file= sectors_on_floppy - sector_n;
  775. /* last_offset non Å gestito qui, tocca al chiamante occuparsene
  776. -- last_offset is not assigned here, but it must be assigned by the caller
  777. */
  778. }
  779.  
  780. /*************************/
  781.  
  782. void bar_check_floppy_swap(situation)
  783. short situation;
  784. /* handle floppy swap for bar archives */
  785. {
  786. int i,this_floppy,accept_any_disk;
  787. sector_t previous_sect;
  788.  
  789. if(situation>0){    /* 1 => il primo settore dell'archivio; 0=>un altro settore richiesto da readblock 
  790.                     (entro un file); -1 => un altro settore richiesto per leggere un header
  791.                     -- situation =1 => the first sector in the archive; 0 => another 
  792.                     sector read through readblock; -1 => a sector which should contain
  793.                     a file header */
  794.     floppy_n=1;
  795.     sect_n=1;
  796.     if(fase==hack_listing){
  797.         this_floppy=bar_check_settore0(§_n,true);
  798.         if(this_floppy<0) raise_error();
  799.         if(sect_n>0)printf("%ld sectors from a previous file",sect_n);
  800.         sect_n++;
  801.         if(sect_n>=sectors_on_floppy){
  802.             printf(" (Partly on next disk)\n");    /* a very long file may be splitted
  803.                         in three or more disks... */
  804.             longjmp(main_loop,-1);    /* during Expert list, the disk is not 
  805.                         ejected...*/
  806.             }
  807.         else
  808.             printf("\n");
  809.         return;
  810.         }
  811.     /* e prosegui, per il controllo del settore 0
  812.     -- continue, to check sector 0 */
  813.     }
  814. else if(sect_n<sectors_on_floppy || !drive_number)
  815. /* the most common case: the requested sector is in the disk which is already
  816. in the drive */
  817.     return;
  818. else{
  819.     floppy_n++;
  820.     sect_n -= sectors_on_floppy-1;    /* -1 per via dell'header...; in modalitê normale
  821.                                     si ottiene sempre 1, in listonly no !
  822.                                     -- minus 1 because of the header; during extraction, 
  823.                                     sect_n will be == sectors_on_floppy, during a List
  824.                                     it will not
  825.                                     */
  826.     if(fase==hack_listing){
  827.         if(sect_n>1) printf("(%ld sectors on next disk)\n",(long)sect_n-1);
  828.         printf("\nEnd of disk\n");
  829.         longjmp(main_loop,-1);
  830.         }
  831.     }
  832.  
  833. accept_any_disk= listonly || situation!=0;    /* cioÅ, non sono in mezzo ad un salvataggio...
  834.         if I'm in the middle of a file saving, to get next disk is more important */
  835.  
  836. for(;;){
  837.     if(situation<=0){    /* il primo disco Å giê dentro, gli altri bisogna sostituirli a
  838.                         ciÿ che Å dentro...
  839.                         -- the first disk is already in the drive, further disks must
  840.                         be inserted
  841.                         */
  842.         if(file_aperto) raise_error();    /* dovrÿ metterci un messaggio di errore, 
  843.                 ma non ne ho voglia di farlo ora; idem per GNU... */
  844.         diskEject();
  845.         do{ 
  846.             if(fase==hack_reading)    /* succede solo per untar e unbar at sector */
  847.                 i=inserzione_assicurata(in_Italia?"\pInserisci il prossimo disco":
  848.                     "\pInsert next disk",accept_any_disk);
  849.             else{
  850.                 char buffer[40];
  851.                 strcpy(buffer,in_Italia?"Inserisci il disco numero ":"Insert disk number ");
  852.                 my_itoa((long)floppy_n,&buffer[strlen(buffer)]);
  853.                 i=inserzione_assicurata(c2pstr(buffer),accept_any_disk);
  854.                 }
  855.             }
  856.         while(i!=0);
  857.         }
  858.     else
  859.         situation=-2;    /* non posso lasciare 1 se resto entro il ciclo
  860.             -- it can't remain 1 inside the loop
  861.             */
  862.  
  863.     /* ora guardo se il disco ricevuto Å quello che mi aspetto
  864.     -- check whether the inserted disk is the expected disk
  865.     */
  866.  
  867.     this_floppy= bar_check_settore0(&previous_sect,true);
  868.  
  869.     if(this_floppy==floppy_n ||
  870.        fase==hack_reading && previous_sect+avail_sectors_for_file==
  871.            ((untar_number(((barh_type*)ultimo_header)->size,-1)+511)/512) ){
  872.         /* Å stato inserito il disco voluto: nel caso di unbar at sector non posso
  873.         fare affidamento sul numero di floppy, ma almeno le dimensioni le controllo */
  874.  
  875.         printf(in_Italia?"Disco numero %d":"Disk number %d",this_floppy);
  876.         print_if_string(in_Italia?" dell\'archivio %s":" of the archive %s",
  877.             ((barh_type*)disk_buffer)->name,100);
  878.         printf("\n");
  879.  
  880.         if(sect_n<sectors_on_floppy) return;
  881.         /* puÿ capitare durante il list di un file che risulta suddiviso in pi¥
  882.         di 2 dischi, allora chiede anche quelli intermedi ma al solo scopo di
  883.         sapere quanti settori ci sono
  884.         -- I may be here only during List of a file which is so long to be splitted
  885.         among at least three disks: suntar asks all the disks, but the intermediate 
  886.         ones are ejected soon after reading how many sectors they contain (it's not
  887.         forbidden to use disks of different sizes for a single archive)
  888.         */
  889.         if(sect_n>=sectors_on_floppy)
  890.             printf(in_Italia?"Disco occupato completamente da parte di un file precedente\n":
  891.                 "The whole disk is occupied by part of a previous file\n",
  892.                 ((tarh_type*)ultimo_header)->name);
  893.         floppy_n++;
  894.         sect_n -= sectors_on_floppy-1;
  895.         avail_sectors_for_file += sectors_on_floppy-1;
  896.         situation = -1;
  897.  
  898.         }
  899.     else if(this_floppy<0){
  900.         if(situation==-2)
  901.             raise_error();        /* l'utente puÿ ridare il comando senza rimetterci nulla
  902.                 -- the user may repeat the command and return here in this same situation */
  903.         else
  904.             ;    /* non Å un disco bar, non c'Å che riprovare...
  905.                 not a bar disk: remain in the loop, so it will be ejected and a new one
  906.                 will be asked for
  907.                 */
  908.         }
  909.     else{
  910.         /* it's not the right disk, but it's a bar disk */
  911.         printf(in_Italia?"Questo Å il floppy numero %d\n":"Disk number %d\n",this_floppy);
  912.         if(!accept_any_disk){
  913.             beep_in_foreground();
  914.             if(fase!=hack_reading)
  915.                 printf(in_Italia?"Errore, io voglio il floppy %d, non il %d\n":
  916.                 "Error, requested disk is number %d, not %d\n",floppy_n,this_floppy);
  917.             else
  918.                 printf("Wrong disk !\n");
  919.             }
  920.         else{
  921.             char pt[6];
  922.             my_itoa((long)floppy_n,&pt[1]);
  923.             pt[0]=strlen(pt+1);
  924.             ParamText(in_Italia?"\pLeggo questo disco invece del ":
  925.                 "\pMust I use this disk rather than disk ",pt,"\p ?",PNS);
  926.             if( chiedi_su_questo(this_floppy,previous_sect,NULL) ){
  927.                 floppy_n=this_floppy;
  928.                 sect_n = previous_sect;
  929.                 ultimo_header_valido=false;
  930.                 sect_n++;    /* per tener conto anche del settore 0 */
  931.                 return;
  932.                 }
  933.             }
  934.         }
  935.     }
  936. }
  937.  
  938. short inserzione_assicurata(mesg,accept_any_disk)
  939. /* as aspetta_inserzione but it never returns without a new disk inserted, 
  940. it rather calls raise_error: if a file is being saved, it asks for confirmation,
  941. since an error closes all open files and hence truncates them */
  942. char*mesg;
  943. Boolean accept_any_disk;
  944. {
  945. /* come aspetta inserzione ma non ritorna al chiamante, usando longjmp, se il disco
  946. non viene affatto inserito ed Å accettabile che non lo sia */
  947.     int i;
  948.     do{
  949.         i=aspetta_inserzione(mesg);
  950.         if(i!=0){
  951.             if(!accept_any_disk){
  952.                 ParamText(in_Italia?"\pVa bene lasciare il file incompleto ?":
  953.                     "\pDo you want to let this file uncompleted ?",PNS,PNS,PNS);
  954.                 if(my_modal_dialog(130,titoli,2)==1)
  955.                     raise_error();
  956.                 else
  957.                     return i;
  958.                 }
  959.             else
  960.                 raise_error();
  961.             }
  962.         if(di.is_not_initialized) diskEject();
  963.         }
  964.     while(di.is_not_initialized);
  965.     return 0;
  966. }
  967.  
  968.  
  969. short bar_check_settore0(previous_sect,verbose)
  970. /* examine if sector 0 is a valid bar volume header */
  971. sector_t *previous_sect;
  972. Boolean verbose;
  973. {
  974. int disk_n;
  975. long offset,exp_check;
  976.  
  977. leggi_settore(0,disk_buffer);
  978. if(check_error()) return err_code;
  979.  
  980. offset=untar_number(((barh_type*)disk_buffer)->size,-1);
  981.  
  982. if(my_atoi(((barh_type*)disk_buffer)->volume_num,&disk_n) ) disk_n = -1;
  983.  
  984. if(((barh_type*)disk_buffer)->bar_magic[0]!= 'V' || 
  985.    ((barh_type*)disk_buffer)->bar_magic[1] != 0 || disk_n==-1 || offset==-1){
  986.     if(verbose){
  987.         beep_in_foreground();
  988.         printf(in_Italia?"Questo non Å un disco in formato bar\n":"Not a bar disk !\n");
  989.         }
  990.     return -1;
  991.     }
  992. *previous_sect=(offset+511)/512; /* Å un multiplo di 512, ma non fidarsi Å meglio */
  993. /* se fosse previous_sect = 0 (se l'ultimo settore di un disco Å un header...) allora
  994. permettere di estrarre anche questo file !!*/
  995.  
  996. if( unbar_checksum(disk_buffer,0,&exp_check) <0 ){
  997.     if(verbose){
  998.         printf("Bad disk header checksum");
  999.         if(expert_mode){
  1000.             if( print_if_string(" (got %s expected ",((barh_type*)disk_buffer)->chksum,8))
  1001.                 printf("%lo)",exp_check);
  1002.             }
  1003.         printf("\n");
  1004.         if( ! ignore_errors){
  1005.             raise_error();
  1006.             return -1;
  1007.             }
  1008.         }
  1009.     else
  1010.         return -1;
  1011.     }
  1012. return disk_n;
  1013. }
  1014.  
  1015. static Boolean chiedi_su_questo(this_floppy,previous_sect,name)
  1016. /* presents the modal dialog "must I continue on this disk ?" */
  1017. sector_t previous_sect;
  1018. char*name;
  1019. {
  1020. enum {dOK=1,dNo,dHalt};
  1021. switch(my_modal_dialog(129,titoli,3)){
  1022. case dOK:
  1023.     if(this_floppy>1&§_n>0){
  1024.         printf(in_Italia?"Presenti %ld settori di completamento di "
  1025.             :"%ld sectors from ",(long)previous_sect);
  1026.         if(name==NULL)
  1027.             printf(in_Italia?"un file precedente\n":"a previous file\n");
  1028.         else
  1029.             printf("%s\n",name);
  1030.         }
  1031.     return 1;
  1032. case dNo:
  1033.     return 0;
  1034. case dHalt:
  1035.     raise_error();
  1036. }
  1037. }
  1038.  
  1039. /*******************************/
  1040.  
  1041. void tar_check_floppy_swap(situation)
  1042. /* check disk swap for GNU tar or AIX tar archives.
  1043. Many comments are identical to those in bar_check_floppy_swap, hence they were not
  1044. translated */
  1045. {
  1046. /* in questa routine, floppy_n puo' valere solo 1 o 2, non vado a contare i floppy.
  1047. Perÿ, se capita che un disco che non sia il primo abbia di nuovo un header di file
  1048. al settore 0, devo rimetterlo ad 1 perchÄ non avrÿ l'header di continuazione
  1049. -- floppy_n may have only two values: 1 for disks without an 'M' continuation
  1050. header (such as the first disk) and 2 for a disk which has one (as most of the 
  1051. following disks)
  1052. */
  1053.  
  1054. int i,this_floppy,accept_any_disk;
  1055. sector_t previous_sect;
  1056. static char s1[]="Disco occupato completamente da parte di %s\n",
  1057.             s2[]="The whole disk is occupied by a part of %s\n";
  1058.  
  1059. if(situation>0){    /* 1 => il primo settore dell'archivio;
  1060.                     0 => un altro settore richiesto da readblock (entro un file);
  1061.                     -1 => un altro settore richiesto per leggere un header;
  1062.                     -2 => il parametro di ingresso era 1 ma ho dovuto espellere
  1063.                         il disco perchÄ non buono */
  1064.     floppy_n=1;
  1065.     previousFormat=tar_unknown;
  1066.     ultimo_header_valido=false;
  1067.     sect_n=0;
  1068.     if(fase==hack_listing){
  1069.         if(next_header_for_AIX!=-1){
  1070.             sect_n=next_header_for_AIX;    /* hacking() has already checked that's a good
  1071.                                 starting sector */
  1072.             return;
  1073.             }
  1074.         accept_any_disk= true;
  1075.         this_floppy=tar_check_settore0(true);
  1076.         if(this_floppy<0)
  1077.             raise_error();
  1078.         if(this_floppy==2){
  1079.             sect_n= (untar_number(((tarh_type*)disk_buffer)->size,false)+511)>>9;
  1080.             if(sect_n>0)printf("%ld sectors from %s",    /* se il file Å lunghissimo non
  1081.                     Å vero, non sono tutti qui ! Lo scrivo sotto */
  1082.                 (long)sect_n,((tarh_type*)disk_buffer)->name);
  1083.             sect_n++;
  1084.             }
  1085.         if(hasVheader) sect_n++;
  1086.         if(sect_n>=sectors_on_floppy){
  1087.             printf(" (Partly on next disk)\n");
  1088.             longjmp(main_loop,-1);
  1089.             }
  1090.         printf("\n");
  1091.         return;
  1092.         }
  1093.     accept_any_disk= true;
  1094.     }
  1095. else if(sect_n<sectors_on_floppy || !drive_number)
  1096.     return;
  1097. else{
  1098.     accept_any_disk= listonly || situation!=0;
  1099.     floppy_n=2;
  1100.     sect_n -= sectors_on_floppy;    /* in modalitê normale si ottiene sempre 0, in listonly no !*/
  1101.     if(situation==-1 && sect_n==0){        /* in questo caso l'header di continuazione non c'Å
  1102.                 -- if the last sectors of a file happens to be written in the last
  1103.                 sector of a disk, the following disk has not a continuation header, hence
  1104.                 it looks like the first disk of another archive */
  1105.         floppy_n=1;
  1106.         /*sect_n--; no, chiedo comunque il 0, sta poi alla gestione dell'inserzione
  1107.                     prossimo disco saltare eventuali header */
  1108.         }
  1109.     if(fase==hack_listing){
  1110.         if(sect_n>0) printf("(%ld sectors on next disk)\n",(long)sect_n);
  1111.         printf("\nEnd of disk\n");
  1112.         longjmp(main_loop,-1);
  1113.         }
  1114.     }
  1115.  
  1116. for(;;){
  1117.     if(situation<=0){    /* il primo disco Å giê dentro, gli altri bisogna sostituirli a
  1118.                         ciÿ che Å dentro... */
  1119.         if(file_aperto) raise_error();
  1120.         diskEject();
  1121.         if(tar_version==tar_unknown &&previousFormat==tar_unknown){
  1122.             ParamText(in_Italia?
  1123.                 "\pQuesto Å un archivio multidisco ?":
  1124.                 "\pIs this a multivolume archive ?",PNS,PNS,PNS);
  1125.             assegna_tar_version();
  1126.             }
  1127.         if(tar_version==tar_singlevol && previousFormat==tar_unknown)
  1128.             error_message(in_Italia?"Errore: raggiunta la fine del disco\n":
  1129.                 "Error: end of disk was reached\n");
  1130.  
  1131.         do{
  1132.             i=inserzione_assicurata(situation==-2 ? (
  1133.                 in_Italia?"\pInserisci il disco in formato tar":
  1134.                 "\pInsert the disk in tar format") :
  1135.                 (in_Italia?"\pInserisci il prossimo disco tar":
  1136.                 "\pInsert next tar disk"), accept_any_disk);
  1137.             }
  1138.         while(i!=0);
  1139.         }
  1140.     else
  1141.         situation=-2;    /* non posso lasciare 1 se resto entro il ciclo */
  1142.  
  1143.     if(situation!=-2 && (previousFormat==tar_AIX ||
  1144.        previousFormat==tar_unknown && tar_version==tar_AIX) ){
  1145.         /* an AIX disk has no header, hence I can't be sure that it's the right
  1146.         disk, I must rely on the current setting of the option */
  1147.         previousFormat=tar_AIX;
  1148.         this_floppy=2;
  1149.         previous_sect=0;
  1150.         if(sect_n >= sectors_on_floppy){        /* la solito, puÿ succedere per un List */
  1151.             sect_n -= sectors_on_floppy;
  1152.             printf(in_Italia? s1:s2,((tarh_type*)ultimo_header)->name);
  1153.             continue;        /* the disk must be ejected, continuing on next one */
  1154.             }
  1155.         /* if(qualche controllo che sia veramente AIX.....) */
  1156.         return;
  1157.         }
  1158.  
  1159.     this_floppy= tar_check_settore0(true);
  1160.     previous_sect=0;
  1161.  
  1162.     if(floppy_n==2 && this_floppy==2 && 
  1163.        verifica_nome(hasVheader,&previous_sect)!=noErr ) this_floppy=3; /* any value 
  1164.                    which can't be equal to floppy_n */
  1165.     if(this_floppy==floppy_n){        /* Å stato inserito il disco voluto */
  1166.  
  1167.         if(hasVheader) sect_n++;        /* devo incrementare sect_n per saltare l'header di 
  1168.                     volume, ed Å pi¥ flessibile non farlo in tar_check_settore0,
  1169.                     non posso farlo se il disco non viene accettato e l'ultima
  1170.                     decisione su questo la prendo qui
  1171.                     -- I could not do that in tar_check_settore0, since it can't
  1172.                     know whether the disk is the right one or not */
  1173.         if(floppy_n==2) sect_n++;    /* salto anche l'header extra... */
  1174.         avail_sectors_for_file = sectors_on_floppy;
  1175.         if(hasVheader) avail_sectors_for_file--;        /* perchÄ quei settori non sono */
  1176.         if(this_floppy>=2) avail_sectors_for_file--;    /*usati per il file */
  1177.         if(sect_n<sectors_on_floppy)
  1178.             return;
  1179.  
  1180.         /* puÿ capitare durante il list di un file che risulta suddiviso in pi¥
  1181.         di 2 dischi, allora chiede anche quelli intermedi ma al solo scopo di
  1182.         sapere quanti settori ci sono */
  1183.         printf(in_Italia? s1:s2,((tarh_type*)ultimo_header)->name);
  1184.         sect_n -= sectors_on_floppy;    /* gli incrementi a sect_n per gli header extra
  1185.                                     sono giê stati effettuati OK */
  1186.         floppy_n=2;
  1187.         if(situation==-1 && sect_n==1)
  1188.             floppy_n=1;
  1189.         /* e proseguo, esattamente come se ci fosse stato un errore e fosse stato 
  1190.         inserito il disco sbagliato, solo che i dati di controllo sono stati
  1191.         aggiornati a pretendere il disco successivo */
  1192.         }
  1193.     else if(this_floppy<0){
  1194.         /* printf(in_Italia ? "Il disco non Å in formato tar nÄ bar\n" : 
  1195.             "Disk format is neither tar nor bar\n"); no, qualcosa viene scritto da
  1196.             bar_check_settore_zero (magari tramite check_error o untar_number) */
  1197.         if(situation==-2){
  1198.             raise_error();        /* l'utente puÿ ridare il comando senza rimetterci nulla */
  1199.             }
  1200.         else
  1201.             printf(in_Italia?"Riprova !\n":"Try again !\n");    /* disco non tar, non c'Å che riprovare... */
  1202.         }
  1203.     else{
  1204.         if(!accept_any_disk){
  1205.             beep_in_foreground();
  1206.             printf(in_Italia?"Errore, non Å il floppy successivo!\n":
  1207.             "Error, it\'s not next disk!\n");
  1208.             }
  1209.         else{
  1210.             if(this_floppy==1)
  1211.                 previous_sect=0;
  1212.             else
  1213.                 previous_sect= (untar_number(((tarh_type*)disk_buffer)->size,false)+511)>>9;
  1214.             if(situation==-2)
  1215.                 ParamText(in_Italia?"\pInizio da questo disco ?":
  1216.                     "\pMust I start from this disk ?",PNS,PNS,PNS);
  1217.             else
  1218.                 ParamText(in_Italia?"\pContinuo su questo disco ?":
  1219.                     "\pMust I continue on this disk ?",PNS,PNS,PNS);
  1220.             if( chiedi_su_questo(this_floppy,previous_sect,((tarh_type*)disk_buffer)->name) ){
  1221.                 if(this_floppy==1){
  1222.                     ultimo_header_valido=false;    /* tanto gestisco subito il primo buono */
  1223.                     avail_sectors_for_file=sectors_on_floppy-sect_n;
  1224.                     }
  1225.                 else{
  1226.                     long last_size;
  1227.                     copia_ultimo_header(disk_buffer,hasVheader?2:1);
  1228.                     last_offset=untar_number(((tarh_type*)disk_buffer)->offset,-1);
  1229.                     last_size=untar_number(((tarh_type*)ultimo_header)->size,false);
  1230.                     ((tarh_type*)ultimo_header)->linkflag='\0';
  1231.                     numstr (((tarh_type*)ultimo_header)->size,last_size+last_offset,12);
  1232.                     }
  1233.                 if(this_floppy==3) this_floppy=2;
  1234.                 floppy_n=this_floppy;
  1235.                 sect_n = previous_sect;
  1236.                 if(hasVheader) sect_n++;
  1237.                 if(this_floppy>=2) sect_n++;
  1238.                 if(sect_n<sectors_on_floppy){
  1239.                     if(this_floppy!=1) printf(in_Italia ? "Parte finale del file %s\n":
  1240.                         "Last part of file %s\n",((tarh_type*)ultimo_header)->name);
  1241.                     return;
  1242.                     }
  1243.                 sect_n-=sectors_on_floppy;
  1244.                 if(this_floppy!=1) printf(in_Italia ? s1: s2, ((tarh_type*)ultimo_header)->name);
  1245.                 }
  1246.             }
  1247.         }
  1248.     }
  1249. }
  1250.  
  1251. short tar_check_settore0(verbose)
  1252. /* examine the first sector of a tar disk: either it's all zeros, or a normal
  1253. file header, or a continuation file header. If it's a 'V' volume header, then
  1254. check sector 1 too
  1255. */
  1256. Boolean verbose;
  1257. {
  1258. int i;
  1259.  
  1260. hasVheader=0;
  1261. leggi_settore(0,disk_buffer);
  1262. if(check_error()) return err_code;
  1263.  
  1264. if(check_all_zero(disk_buffer)) return 1;        /* un archivio tar vuoto... */
  1265. if( (i=untar_checksum(disk_buffer,-1,verbose)) < 0){
  1266.     if(i==-2||!verbose|| !ignore_errors) return -1;
  1267.     }
  1268.  
  1269. hasVheader = ((tarh_type*)disk_buffer)->linkflag=='V';
  1270. if(hasVheader){
  1271.     previousFormat=tar_GNU;
  1272.     disk_buffer[99]=0;
  1273.     if(verbose) printf(in_Italia?"Il nome del disco Å %s\n":
  1274.         "The disk name is %s\n",disk_buffer);    /* stampa l'informazione contenuta nell'header ! 
  1275.         -- that's the string the user specified in the V option, plus the volume number */
  1276.     leggi_settore(1,disk_buffer);
  1277.     if(check_error()) return err_code;
  1278.     if(check_all_zero(disk_buffer)) return 1;
  1279.     if( (i=untar_checksum(disk_buffer,-1,verbose&&!ignore_errors)) < 0){
  1280.         if( (i==-2 || !ignore_errors) && verbose ) return -1;
  1281.             /* verbose is false if and only if I were called by identify format,
  1282.             which only wants to know if this is a tar archive, not if its sector 1
  1283.             is corrupted */
  1284.         }
  1285.     }
  1286.  
  1287. if(((tarh_type*)disk_buffer)->linkflag=='M'){
  1288.     previousFormat=tar_GNU;
  1289.     return 2;
  1290.     }
  1291. else
  1292.     return 1;
  1293. }
  1294.  
  1295. static OsErr verifica_nome(volume_header,previous_sect)
  1296. /* verify a continuation header against the normal header which was in the previous disk */
  1297. sector_t *previous_sect;
  1298. {
  1299. long last_size,sizeleft,expected_offset;
  1300.  
  1301. if(!ultimo_header_valido){
  1302.     *previous_sect=0;
  1303.     return noErr;        /* non ho visto il disco precedente, perchÄ
  1304.         sono alla prima inserzione */
  1305.     }
  1306. sizeleft=untar_number(((tarh_type*)disk_buffer)->size,false);
  1307. last_size=untar_number(((tarh_type*)ultimo_header)->size,false);
  1308. *previous_sect=(sizeleft+511)>>9;
  1309. if( strcmp(ultimo_header,disk_buffer) ) return -1;    /* il nome non coincide */
  1310.  
  1311. expected_offset=last_offset+((long)avail_sectors_for_file<<9);
  1312. last_offset=untar_number(((tarh_type*)disk_buffer)->offset,false);
  1313. /*printf("<%ld %ld,%ld,%ld,%ld>",(long)avail_sectors_for_file,expected_offset,last_offset,last_size,sizeleft);*/
  1314.  
  1315. if(expected_offset!=last_offset || last_size-last_offset!=sizeleft) return -1;
  1316.  
  1317. if(volume_header)
  1318.     (*previous_sect)++;
  1319.  
  1320. return noErr;
  1321. }
  1322.  
  1323.  
  1324. void close_or_del_out_file()
  1325. {
  1326. if(devo_chiudere_out){
  1327.     if(del_incompl){
  1328.         reinit_hd_buffering();
  1329.         cancella_file_aperto(pb.ioParam.ioRefNum);
  1330.         }
  1331.     else{
  1332.         flush_hd_buffer();
  1333.         PBCloseSync(&pb);
  1334.         }
  1335.     devo_chiudere_out=false;
  1336.     }
  1337. }
  1338.  
  1339. /******************************************************************/
  1340.  
  1341. int filter_conf(EventRecord*);
  1342. static int filter_conf(theEvent)
  1343. EventRecord*theEvent;
  1344. {
  1345. /* the standard filter for semimodal makes CR equivalent to button 1,
  1346. this filter makes esc equivalent to button 2 */
  1347. #define ESC 27
  1348. if(theEvent->what==keyDown&&(char)theEvent->message==ESC)
  1349.     return 2;
  1350. return 0;
  1351. }
  1352.  
  1353.  
  1354. void check_confirmation()
  1355. /* handles the confirm saves dialog */
  1356. {
  1357. /* il nome del file DEVE stare in tarh.name, formato C
  1358. -- the file name MUST be a C string in tarh.name
  1359.  */
  1360. static Point wPos={-1,-1};
  1361. static char *t_ita[]= {"\pSalva","\pNon salvare","\pSalva tutto","\pSalta tutto"};
  1362. char buffer[120];
  1363.  
  1364. if(!confirm_saves||all_listonly||fase==hack_reading||
  1365.     fase==hack_listing||fase==selected_reading || file_aperto>ff_tarbar ) 
  1366.     return;
  1367. else{
  1368.     int item;
  1369.     enum {cdSave=1,cdSkip,cdSaveAll,cdSkipAll};
  1370.  
  1371.     strcpy(buffer,"File\312");    /* spazio non interrompibile
  1372.                                 -- non-breakable space: if the file name is long,
  1373.                                 breaking between lines here is not a wise thing */
  1374.     strcat(buffer,tarh.name);
  1375.  
  1376.     item=semimodalDialog(136,&wPos,filter_conf,t_ita,4,c2pstr(buffer),NULL,NULL,teJustLeft,true);
  1377.  
  1378.     listonly= item==cdSkip || item==cdSkipAll;
  1379.     if(item==cdSaveAll || item==cdSkipAll)
  1380.         set_skip_all(1);
  1381.     }
  1382. }
  1383.  
  1384. void check_conf_dir(dname)
  1385. char*dname;
  1386. {
  1387. /* in confirm saves directories are extracted only if they already existed.
  1388. OK, that seems the opposite of any logical thing, but when extracting, for example,
  1389. dir/file if dir does not exist it's created. Hence, if I wish to extract files
  1390. which go to that directory it will be created anyway, but I should warn the user
  1391. before placing them in a directory which already existed (that could cause a
  1392. chaotic mix of files). The simplest way to do that warning is calling create_directory...
  1393. */
  1394. if(!confirm_saves||all_listonly||fase==hack_reading||
  1395.     fase==hack_listing||fase==selected_reading) 
  1396.     return;
  1397. {
  1398. CInfoPBRec cinfo;
  1399. int i;
  1400. cinfo.dirInfo.ioNamePtr= c2pstr(dname);
  1401. #ifdef USA_CURRVREFN
  1402. cinfo.dirInfo.ioVRefNum=curr_vrefnum;
  1403. #else
  1404. cinfo.dirInfo.ioVRefNum=0;
  1405. #endif
  1406. cinfo.dirInfo.ioFDirIndex=0;
  1407. cinfo.dirInfo.ioDrDirID=0;
  1408. listonly= PBGetCatInfoSync(&cinfo)!=noErr;
  1409. p2cstr(dname);
  1410. }
  1411. }
  1412.  
  1413. /********************************/
  1414. void my_itoa(val,buffer)
  1415. register long val;
  1416. char *buffer;
  1417. {
  1418. char buf[14];
  1419. Boolean nega;
  1420. register char *p=&buf[13];
  1421. if(nega= (val<0) )
  1422.     val= -val;
  1423. *p='\0';
  1424. do{
  1425.     *--p ='0'+(int)(val%10);
  1426.     val /= 10;
  1427.     }
  1428. while(val>0);
  1429. if(nega) *--p='-';
  1430. strcpy(buffer,p);
  1431. }
  1432.  
  1433. static short isMacBin2(buf)
  1434. /* checks whether the MacBinary header is a MacBinary II header;
  1435. returns 0 for non-MacBinary II
  1436. 1 for Macbinary II
  1437. -1 for an unknown (future) release of MacBinary II that suntar can't decode,
  1438. -2 for CRC error
  1439.  */
  1440. register unsigned char *buf;
  1441. {
  1442. extern short current_crc;
  1443. register int i;
  1444. /* can't declare a pointer to binh_type since it's misaligned by one byte */
  1445. if(buf[122]<129 || buf[123]<129) return 0;
  1446. if(buf[123]>129) return -1;
  1447. current_crc=0;
  1448. for(i=0;i<124;i++)
  1449.     CalcCRC(buf[i]);
  1450. CalcCRC(0);
  1451. CalcCRC(0);
  1452. if( current_crc != *(short*)&buf[124]) return -2;
  1453. return 1;
  1454. }
  1455.  
  1456. void clear_unused_fields()
  1457. {
  1458. /* leggere documentazione su MacBinary II, ma non azzero busy perchÄ 
  1459.     nel System 7 ha cambiato significato
  1460. -- the file macbinary2-standard.txt, reporting the decisions of the people
  1461. who met to set the standard, explains:
  1462. >All Finder flags and information would be uploaded, however, a downloading
  1463. >program should clear the Finder flag bits of
  1464. >  0 - Set if file/folder is on the desktop (Finder 5.0 and later)
  1465. >  1 - bFOwnAppl (used internally)
  1466. >  8 - Inited (seen by Finder)
  1467. >  9 - Changed (used internally by Finder)
  1468. > 10 - Busy (copied from File System busy bit)
  1469.  
  1470. >Also, fdLocation and fdFldr should be zeroed
  1471.  
  1472. Bit    Meaning (from Technical Note 40)
  1473. 0    Set if file/folder is on the desktop (Finder 5.0 and later)
  1474. 1    bFOwnAppl (used internally)
  1475. 2    reserved, currently unused
  1476. 3    reserved, currently unused
  1477. 4    bFNever (never SwitchLaunch) (not implemented)
  1478. 5    bFAlways (always SwitchLaunch) 
  1479. 6    Set if application is shared and is opened read-only (128K ROM only)
  1480. 7    Set if file should be cached (not implemented)
  1481. 8   Inited (seen by Finder)
  1482. 9   Changed (used internally by Finder)
  1483. 10  Busy (copied from File System busy bit)
  1484. 11  NoCopy (not used in 5.0 and later, formerly called BOZO)
  1485. 12  System (set if file is a system file)
  1486. 13  HasBundle
  1487. 14  Invisible
  1488. 15  File Locked
  1489.  
  1490. However, in System 7 bit 10 means "hasCustomIcon" and it's better to preserve it.
  1491. It's unfortunate that the MacBinary standard did not include a field for "version
  1492. of Finder which created it", now that different versions of the Finder use the same bits
  1493. for different purposes: luckily, if that file does have a custom icon its resource
  1494. fork contains a 'ICN#' resource with ID -16455.
  1495. And bit 15 should not be cleared according to the standard, but in System 7 it means
  1496. "is an alias" and it's correct to clear it when transferring an old file to
  1497. system 7, if the file does not contain an 'alis' resource.
  1498. As a result, I MUST examine the resource fork of the file if either bit 10 or 15
  1499. are set.
  1500. Bit 11 is now "is stationery pad": it's better to preserve it anyway, since the old
  1501. meaning is obsolete since Finder 5.0, there is no particular contents to check for
  1502. and the user may change it by a Get Info
  1503. Bit 12 was "is System file" and is now "Name locked": since it would be useless
  1504. to download an old system file to a machine with System 7, under System 7 it's
  1505. better to preserve it, but under system 6 ?
  1506. */
  1507.  
  1508.     macbinh.finfo.fdFlags &= ~0x303;
  1509.     *(long*)&macbinh.finfo.fdLocation=0;
  1510.     macbinh.finfo.fdFldr=0;
  1511.  
  1512.     if(macbinh.finfo.fdFlags & 0x8400){
  1513.         if(macbinh.rflen==0 || 
  1514.            !(macbinh.finfo.fdFlags & 0x400)&&(macbinh.dflen>0||macbinh.rflen>4096) )
  1515.            /* an alias file has no data fork and is not very big */
  1516.             macbinh.finfo.fdFlags &= ~0x8400;
  1517.         else{
  1518.             unsigned char name[64];
  1519.             int refnum,oldvRefNum,oldres;
  1520.             SetResLoad(false);        /* it should save the old status to restore
  1521.                     it, but it should never be false... */
  1522.             if(GetVol (&name,&oldvRefNum)!=noErr) oldvRefNum=0;
  1523.  
  1524.               SetVol(NULL,pb.fileParam.ioVRefNum);
  1525.               oldres=CurResFile();
  1526.               refnum= OpenResFile(pb.fileParam.ioNamePtr);
  1527.               if(refnum==-1)
  1528.                   macbinh.finfo.fdFlags &= ~0x8400;    /* clear both flags */
  1529.               else{
  1530.                 if(macbinh.finfo.fdFlags & 0x8000){    /* alias bit */
  1531.                     if(! Count1Resources ('alis') )
  1532.                         macbinh.finfo.fdFlags &= ~0x8000;
  1533.                     else if(!gHasResolveAlias){
  1534.                         ParamText(in_Italia?
  1535.                         "\pQuesto file Å un alias, solo il System 7 puÿ utilizzarlo":
  1536.                         "\pThis file is an alias, only System 7 knows how to use it",PNS,PNS,PNS);
  1537.                         my_alert();
  1538.                         }
  1539.                     }
  1540.                 if(macbinh.finfo.fdFlags & 0x400){    /* "has custom icon" bit */
  1541.                     Handle h = Get1Resource('ICN#',-16455);
  1542.                     if(h!=NULL)
  1543.                         ReleaseResource(h);
  1544.                     else
  1545.                         macbinh.finfo.fdFlags &= ~0x400;
  1546.                     }
  1547.                 CloseResFile(refnum);
  1548.                 }
  1549.             if(oldvRefNum) SetVol (&name,oldvRefNum);
  1550.             UseResFile(oldres);
  1551.             SetResLoad(true);
  1552.             }
  1553.         }
  1554. }
  1555.  
  1556.  
  1557. static void make_badname(fname,name)
  1558. /* creates a new name for a file which caused a bad name error (some
  1559. versions of UNIX have a max name length which is greater than that of the HFS,
  1560. and it happens to see public domain Mac files with a very long name which 
  1561. would not be legal on a Macintosh)
  1562. */
  1563. char*fname,*name;
  1564. {
  1565. static int bad_names=0;
  1566. static char BadNameFolder[]=":bad names folder:";
  1567. register char *p1,*p;
  1568. register int i;
  1569.  
  1570. strcpy(fname,BadNameFolder);
  1571. my_itoa((long)++bad_names,&fname[sizeof(BadNameFolder)-1]);
  1572.  
  1573. p1= name;
  1574. p=&p1[(unsigned char)*p1];    /* last character of original name */
  1575. p1=p1+1;
  1576. while(*p==':' && p>p1) p--;        /* typically, at the end of a Mac name there may be */
  1577. i = *p!=':';    /* 0-1 */
  1578. while(p>p1 && p[-1]!=':' && i<=24){
  1579.     p--; i++;
  1580.     }
  1581. p1=fname + strlen(fname);
  1582. if(i){
  1583.     *p1++ =' ';
  1584.     *p1++ ='-';
  1585.     while(i-- >0){
  1586.         if(*p>=' ' && *p< 127) *p1++ = *p;
  1587.         p++;
  1588.         }
  1589.     }
  1590. *p1='\0';
  1591.  
  1592. printf(in_Italia?"%p: nome non valido, cambiato in %s\n":
  1593.     "%p: bad name, renamed to %s\n",name,fname);
  1594. }
  1595.  
  1596. static Boolean too_long(fname)
  1597. register char *fname;
  1598. {
  1599. register int i=0;
  1600. while(*fname!='\0'){
  1601.     if(*fname==':')
  1602.         i=0;
  1603.     else
  1604.         if(++i>31) return true;
  1605.     fname++;
  1606.     }
  1607.  return false;
  1608. }
  1609.  
  1610. static Boolean is_gif_file(fsize)
  1611. long fsize;
  1612. {
  1613. /* checks whether the file begins with 'GIF'
  1614. (really, the signature is GIF87a or GIF89a, but when there will be a GIF9xa
  1615. it will be better to recognize it too)
  1616. (This "privilege" is  because gif files are very popular, and since they are 
  1617. a non-Mac format usually they are downloaded as data only so they have no 
  1618. type and creator)
  1619. */
  1620. static char h[]={'G','I','F'};
  1621. if (fsize>100 && !strncmp(h,disk_buffer,(size_t)3) && 
  1622.     disk_buffer[3]>='0' && disk_buffer[3]<='9' && 
  1623.     disk_buffer[4]>='0' && disk_buffer[4]<='9' &&
  1624.     disk_buffer[5]>='a' && disk_buffer[5]<='z') return true;
  1625. return false;
  1626. /*    since a gif file has an internal signature, it's better to rely on it
  1627. than to look at the name...
  1628. int l;
  1629. l=strlen(tarh.name);
  1630. return (l >4 && !ci_strcmp(&tarh.name[l-4],".gif" );
  1631. */
  1632. }
  1633.  
  1634. void print_type_creator(t,c)
  1635. OSType t,c;
  1636. {
  1637. /* sorry, my printf doesn't accept %.4s */
  1638. printf(in_Italia?"tipo=\'":"type=\'");
  1639. print_chars(&t,4);
  1640. printf(in_Italia?"\' creatore=\'":"\' creator=\'");
  1641. print_chars(&c,4);
  1642. printf("\'");
  1643. }
  1644.  
  1645. void print_one_date(cdate,message)
  1646. long cdate;
  1647. char*message;
  1648. {
  1649.     char p[20];
  1650.     printf("%s",message);
  1651.     IUDateString(cdate,abbrevDate,p);
  1652.     printf("%p ",p);
  1653.     IUTimeString(cdate,true,p);
  1654.     printf("%p",p);
  1655. }
  1656.  
  1657.  
  1658.  
  1659. void cancella_file_aperto(ioRefNum)
  1660. short ioRefNum;
  1661. {
  1662. OSErr i;
  1663. get_openfile_location(ioRefNum);
  1664. PBCloseSync(&pb);
  1665. pb.fileParam.ioNamePtr=mac_file_name;
  1666. pb.fileParam.ioVRefNum=openfile_vrefnum;
  1667. pb.fileParam.ioDirID=openfile_dirID;
  1668. i=PBHDeleteSync(&pb);
  1669. /*printf("delete=%d\n",i);*/
  1670. }
  1671.  
  1672. short crea_e_controlla(tempattrib)
  1673. /* crea un file ma fa anche qualche controllo...;
  1674. ritorna come create_file
  1675. -- creates a file and does some checking; returns as create_file
  1676. */
  1677. Boolean tempattrib;
  1678. {
  1679. char copia[100];
  1680. short i;
  1681.  
  1682. mcopy(copia,tarh.name,100);
  1683. for(;;){
  1684.     if( create_file(tarh.name,fsWrPerm,tempattrib)) return 1;    /* Cancel... */
  1685.     
  1686.     i=controlla_spazio(macbinh.dflen,macbinh.rflen);
  1687.     if(i==1) return 1;
  1688.     if(i==2){
  1689.         /* restore the name, in case it was changed (e.g. if the file existed...) */
  1690.         mcopy(tarh.name,copia,100);
  1691.         /* and retry... */
  1692.         }
  1693.     else{
  1694.         if(macbinh.finfo.fdFlags&0x4000){    /* bit "invisible" */
  1695.             ParamText(in_Italia?"\pFile invisibile: lo rendo visibile ?":
  1696.                 "\pInvisible file: make it visible ?",PNS,PNS,PNS);
  1697.             if(my_modal_dialog(130,titoli,2)==1)
  1698.                 macbinh.finfo.fdFlags &= ~0x4000;
  1699.             }
  1700.         return 0;
  1701.         }
  1702.     }
  1703. }
  1704.  
  1705.  
  1706. short controlla_spazio(dlen,rlen)
  1707. long dlen,rlen;
  1708. /* checks that the destination volume has enough free space;
  1709. returns 0 if OK, 1 if not enough space and the user canceled
  1710. the operation, 2 if not enough space and the user selected another
  1711. volume for continuing
  1712. */
  1713. {
  1714. long l;
  1715. int vrefnum;
  1716. Boolean prima_volta=true;
  1717. short i;
  1718.  
  1719. for(;;){
  1720.     if(pb.fileParam.ioVRefNum)
  1721.         vrefnum=pb.fileParam.ioVRefNum;
  1722.     else{
  1723.         volumeParam param;
  1724.         char buffer[50];
  1725.         param.ioNamePtr=buffer;    /* or NULL, but what happens if some system bug
  1726.                             (or a bad INIT) does not check for NULLs ? */
  1727.         if(PBGetVolSync (¶m) !=noErr) return;
  1728.         vrefnum=param.ioVRefNum;
  1729.         }
  1730.     if(GetVInfo (0,NULL,&vrefnum,&l)!=noErr)
  1731.         return 0;        /* the error could be not fatal, it's better to hope that
  1732.                         anything is OK, this routine is only a check to prevent
  1733.                         some errors but suntar still works without checking for
  1734.                         space... */
  1735.     /*printf("l=%ld\n",l);*/
  1736.     if( ((dlen+511)&~511L) + ((rlen+511)&~511L) <= l )
  1737.         return 0;    /* space is enough */
  1738.     else{
  1739.         if(!prima_volta){
  1740.             ParamText(in_Italia?"\pSpazio ancora insufficiente,\rproseguo comunque ?":
  1741.                 "\pSpace is still insufficient,\rcontinue anyway ?",PNS,PNS,PNS);
  1742.             if(my_modal_dialog(130,titoli,2)==1)
  1743.                 return 0;
  1744. /*            else continue */
  1745.             }
  1746.         do{
  1747.             i=semimodalDialog(141,NULL,NULL,t1,3,
  1748.                in_Italia?"\pSpazio su disco insufficiente: puoi voler cancellare\r\
  1749. qualcosa prima di cliccare su un bottone\roppure puoi abortire il comando":
  1750. "\pInsufficient space on destination volume: you\r\
  1751. might wish to delete something before clicking a\r\
  1752. button or you may abort the current command",
  1753.                NULL,NULL,teJustCenter,true);
  1754.             if(i==2){
  1755.                    /* continue elsewhere */
  1756.                 select_directory();
  1757.                 cancella_file_aperto(pb.ioParam.ioRefNum);
  1758.                 if(reply.good) return 2;
  1759.                 }
  1760.             else if(i==3)
  1761.                 return 1;
  1762.             else{
  1763.                 /* continue here: maybe the user deleted some files */
  1764.                 prima_volta=false;
  1765.                 }
  1766.             }
  1767.         while(i==2);    /* if I'm here, it was cancelled */
  1768.         }
  1769.     }
  1770. }
  1771.  
  1772. #if V_122
  1773. /* old versions used till suntar 1.2.2 */
  1774.  
  1775. void conferma_invisibili()
  1776. {
  1777. if(macbinh.finfo.fdFlags&0x4000){    /* bit "invisible" */
  1778.     ParamText(in_Italia?"\pFile invisibile: lo rendo visibile ?":
  1779.         "\pInvisible file: make it visible ?",PNS,PNS,PNS);
  1780.         if(my_modal_dialog(130,titoli,2)==1)
  1781.             macbinh.finfo.fdFlags &= ~0x4000;
  1782.     }
  1783. }
  1784.  
  1785. void controlla_spazio(dlen,rlen)
  1786. long dlen,rlen;
  1787. /* checks that the destination volume has enough free space */
  1788. {
  1789. long l;
  1790. int vrefnum;
  1791. if(pb.fileParam.ioVRefNum)
  1792.     vrefnum=pb.fileParam.ioVRefNum;
  1793. else{
  1794.     volumeParam param;
  1795.     char buffer[50];
  1796.     param.ioNamePtr=buffer;    /* or NULL, but what happens if some system bug
  1797.                             (or a bad INIT) does not check for NULLs ? */
  1798.     if(PBGetVolSync (¶m) !=noErr) return;
  1799.     vrefnum=param.ioVRefNum;
  1800.     }
  1801. if(GetVInfo (0,NULL,&vrefnum,&l)==noErr){
  1802. /*printf("l=%ld\n",l);*/
  1803.     if( ((dlen+511)&~(long)0x1FF) + ((rlen+511)&~(long)0x1FF) > l){
  1804.         beep_in_foreground();
  1805.         error_message(in_Italia?"Spazio su disco insufficiente\n":
  1806.             "Insufficient space on destination volume\n");
  1807.         }
  1808.     }
  1809. }
  1810. #endif
  1811.  
  1812.  
  1813.  
  1814. static short gestisci_nome_doppio(fname,name,fpb)
  1815. /* handle a duplicate name error */
  1816. char *fname,*name;
  1817. register FileParam *fpb;
  1818. {
  1819. int err,i,l=strlen(fname);
  1820. WDPBRec param;
  1821.  
  1822. settori_passati=0;
  1823. beep_in_foreground();
  1824. /*if(fase==hack_reading){
  1825.     error_message("File already existing !\n");
  1826.     }
  1827. */
  1828. /* ci sono due modi di procurarsi le informazioni da mettere nelle due variabili 
  1829. che dicono dove lo standard file deve posizionarsi inizialmente:
  1830. 1) come nel programma Apple, creare una WD con PBOpenWD e poi fare PBGetWDInfo
  1831. 2) non creare alcuna WD, ma allora bisogna usare PBGetCatInfo per avere il DirID
  1832.    e PBGetWDInfo (sulla WD preesistente...) per avere il vRefNum del volume
  1833.    (cioÅ, della root)
  1834. per ora seguo il metodo 1, che funziona, ma quando avrÿ tempo preferirei passare al 2
  1835. -- I must oblige SFPutFile to show the folder where the file had to go, and that's
  1836. done by setting two low memory variables. But I must get the information in the
  1837. right format, and the simplest way to do that requires the creation of a working
  1838. directory (the other way looks even easier, but currently it does not work, at least
  1839. not always)
  1840. */
  1841.  
  1842. for(i=l-1;i>=0 && fname[i]!=':';i--)
  1843.     ;
  1844. #if 1
  1845. /* ora i Å -1 o punta ad un ':' */
  1846. if(i<=0){        /* un : in testa non conta... */
  1847.     err=GetVol (name,¶m.ioVRefNum);
  1848.     /* name[0]=0; */
  1849.     }
  1850. else{
  1851.     mcopy(&name[1],fname,i+1);    /* cosô tronco al : (che resta compreso)...*/
  1852.     name[0]=i+1;
  1853.  
  1854.  
  1855. #ifdef USA_CURRVREFN
  1856.     param.ioVRefNum=curr_vrefnum;
  1857. #else
  1858.     param.ioVRefNum=0;
  1859. #endif
  1860.     }
  1861.     param.ioNamePtr=(unsigned char*)name;
  1862.     param.ioWDProcID=signature;
  1863.     param.ioWDDirID=0;
  1864.     err=PBOpenWDSync(¶m);        /* ho bisogno di una WD perchÄ doForceDirectory
  1865.                                 Å fatta a quel modo... */
  1866.     doForceDirectory(¶m);
  1867.     register_WD(param.ioVRefNum);
  1868.  
  1869. #else
  1870. /* that's the second way: in this form it's worse, but, damn it, why should I be
  1871. obliged to do two calls to get both the dirID and the root vRefNum ? */
  1872.  
  1873. /* se mi decido per questo, togliere doForceDirectory da StdFile.c ! */
  1874. /*printf("giusti = %d %ld \n",-SFSaveDisk,CurDirStore);*/
  1875. {CInfoPBRec cinfo;
  1876.  
  1877. printf("fname=%s, name=%p\n",fname,name);
  1878.  
  1879. cinfo.dirInfo.ioNamePtr= (unsigned char*)name;
  1880. cinfo.dirInfo.ioVRefNum=curr_vrefnum;
  1881. cinfo.dirInfo.ioFDirIndex=0;
  1882. cinfo.dirInfo.ioDrDirID=0;
  1883. PBGetCatInfoSync(&cinfo);        /* get the dirID */
  1884.  
  1885. /*printf("result= %d attr=%x\n",cinfo.dirInfo.ioResult,cinfo.dirInfo.ioFlAttrib);
  1886. printf("cose che vedo =%d %ld %d\n",cinfo.dirInfo.ioVRefNum,cinfo.dirInfo.ioDrDirID,
  1887.     cinfo.dirInfo.ioFRefNum);*/
  1888. /*cinfo.dirInfo.ioDrDirID contiene il DirId giusto, ma il vRefNum giusto
  1889. non sta in nessun campo !*/
  1890.     param.ioNamePtr = NULL;
  1891.     param.ioVRefNum = 0;
  1892.     param.ioWDIndex = 0;
  1893.     param.ioWDProcID = 0;
  1894.  
  1895.     PBGetWDInfoSync(¶m);        /* get the vrefnum */
  1896. /* ioVRefNum Å quello che voglio, ma ovviamente non avendogli dato il path da lô
  1897. non posso avere alcun DirID, e anche a dare il path sembra che non si ottenga */
  1898. /*printf("stavolta ho %d %ld\n",param.ioVRefNum, param.ioWDDirID);*/
  1899.  
  1900.     CurDirStore = cinfo.dirInfo.ioDrParID  or cinfo.dirInfo.ioDrDirID ???????;
  1901.     SFSaveDisk = -param.ioVRefNum;
  1902. }
  1903. #endif
  1904. /*printf("settato %d %ld\n",SFSaveDisk,CurDirStore);*/
  1905.  
  1906. c2pstr(&fname[i+1]);
  1907.  
  1908. while( SFPut_con_pausa(&fname[i+1])){
  1909.     handle_pause();
  1910.     accept_abort_command();
  1911.     }
  1912. if(!reply.good) return 1;
  1913.  
  1914.     fpb->ioNamePtr = reply.fName;
  1915.     fpb->ioVRefNum = reply.vRefNum;
  1916.     fpb->ioFVersNum = 0;
  1917.     err=PBCreateSync(fpb) ;
  1918.     pStrcpy(fname,reply.fName);        /* devo salvarlo prima se no lo perdo */
  1919.     if(err==dupFNErr){
  1920.         if(open_overwrite(reply.fName,reply.vRefNum,&(fpb->ioFRefNum))==noErr)    /* ok il 
  1921.                 codice che dice che esiste, siamo dopo un SFPutFile, ma bisogna 
  1922.                 troncare il file... */
  1923.             FSClose(fpb->ioFRefNum);
  1924.         }
  1925.  
  1926.     else if(err!=noErr)
  1927.         pbsyserr(fpb);
  1928.  
  1929.     p2cstr(fname);
  1930.     fpb->ioVRefNum = reply.vRefNum;
  1931.     fpb->ioFVersNum = 0;
  1932.     fpb->ioFDirIndex = 0;
  1933.     return 0;
  1934. }
  1935.  
  1936. static void skip_macbinII(size)
  1937. int size;
  1938. {
  1939. while(size>0){
  1940.     if(readblock(&tarh,128)) raise_error();
  1941.     size-=128;
  1942.     }
  1943. }
  1944.  
  1945.  
  1946. void get_openfile_location(ioRefNum)
  1947. int ioRefNum;
  1948. {
  1949. /* get the current name and location of the file, so that it may be
  1950. reopened even if the user has moved or renamed it */
  1951.  
  1952. FCBPBRec param;
  1953.  
  1954. fillmem(¶m,0,sizeof(param));
  1955. param.ioVRefNum=0;
  1956. param.ioRefNum=ioRefNum;
  1957. param.ioFCBIndx=0;
  1958.  
  1959. param.ioNamePtr=mac_file_name;
  1960. if((err_code=PBGetFCBInfoSync(¶m))==noErr){
  1961.     openfile_vrefnum=param.ioFCBVRefNum;
  1962.     openfile_dirID=param.ioFCBParID;
  1963.     /*pStrcpy(mac_file_name,param.ioNamePtr);*/
  1964.     }
  1965. else
  1966.     openfile_dirID=0;
  1967. /*
  1968. printf("err=%d(%d) ioV=%d ioR=%d volRN=%d dirID=%ld name=%lx:%p\n",
  1969. err_code,param.ioResult,param.ioVRefNum,param.ioRefNum,param.ioFCBVRefNum,param.ioFCBParID,
  1970. param.ioNamePtr,param.ioNamePtr);
  1971. */
  1972.  
  1973. }
  1974.  
  1975. /************* end of routines by Speranza **************************/
  1976.  
  1977. /************* Routines obtained by modifying ones by Zacharias **********
  1978. (that is, modifying their interface and purpose and not only their code)
  1979.  **********************************************************************/
  1980.  
  1981.  
  1982. /********************* hqx *******************************/
  1983.  
  1984. void untar_hqx (fsize)
  1985.   long fsize;
  1986. {
  1987. register char *cp;
  1988. jmp_buf savebuf;
  1989. int i;
  1990.  
  1991. hqx_length=fsize;
  1992. mcopy(&savebuf,&main_loop,sizeof(jmp_buf));
  1993. if((i=setjmp(main_loop))<0 ){
  1994.     mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  1995.     if(i==-2)        /* raise_hqx_error... */
  1996.         return;
  1997.     raise_error();
  1998.     }
  1999.  
  2000. if( hqx_header() ){            /* con risultati in macbinh
  2001.                             -- results in macbinh */
  2002.     mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2003.     return;
  2004.     }
  2005.  
  2006. for(cp = tarh.name+strlen(tarh.name); cp != tarh.name && cp[-1] != ':'; --cp);
  2007. mcopy(cp, macbinh.name, macbinh.nlen);
  2008. cp[macbinh.nlen] = '\0';
  2009.  
  2010. disable_autoflush();
  2011. if(expert_mode&&file_aperto<=ff_tarbar) printf(s_spazi);    /*per allinearsi col [sector xxxx] stampato
  2012.                 presumibilmente alla riga prima
  2013.                 -- to align with the [sector xxxx] printed in the previous line */
  2014. printf(in_Italia ? "Contenente" : "Containing");
  2015. printf(" %p (", &macbinh.nlen);
  2016. printf("data %ld+res %ld bytes)", macbinh.dflen, macbinh.rflen);
  2017. if(fase==hack_listing){
  2018.     printf("  ");
  2019.     print_type_creator(macbinh.finfo.fdType,macbinh.finfo.fdCreator);
  2020.     }
  2021. printf("\n");
  2022. enable_autoflush();
  2023.  
  2024. filecreator=filetype='????';
  2025.  
  2026. #ifdef V_122
  2027. if (!listonly && ! create_file(tarh.name,fsWrPerm,true)) {
  2028.     controlla_spazio(macbinh.dflen,macbinh.rflen);
  2029.     conferma_invisibili();
  2030.     #if 0    /* Think C Marker.... */
  2031.         }
  2032.     #endif
  2033. #else
  2034.  
  2035. if(!listonly && ! crea_e_controlla(true) ){
  2036. #endif
  2037.     write_hqx_fork(512,macbinh.dflen);
  2038.  
  2039.     pb.ioParam.ioVersNum = 0;
  2040.     pb.ioParam.ioPermssn = fsWrPerm;
  2041.     pb.ioParam.ioMisc = 0;
  2042.     if((pb.fileParam.ioDirID=openfile_dirID)!=0){
  2043.         pb.ioParam.ioVRefNum=openfile_vrefnum;
  2044.         pb.ioParam.ioNamePtr=mac_file_name;
  2045.         }
  2046.     if( PBHOpenRFSync(&pb)) pbsyserr(&pb);
  2047.  
  2048.     devo_chiudere_out=true;
  2049.  
  2050.     write_hqx_fork(512,macbinh.rflen);
  2051.  
  2052.     set_binhex();
  2053.     if(hqx_length > 16)    /* tanto per dare un valore... 
  2054.                     -- well, due to multiple buffering of data that variable
  2055.                     does NOT hold the number of remaining chars, at least if
  2056.                     those chars are before the final ':' (the buffering does
  2057.                     not go past that ':'); on the other hand I don't check for 
  2058.                     the presence of that ':', and I've read that
  2059.                     "Some old programs produced an extra exclamation mark (!) 
  2060.                     immediately before the final colon", hence I don't want to
  2061.                     check that no extra chars are present.
  2062.                     */
  2063.         printf(in_Italia ? "%ld caratteri dopo i dati Binhex sono stati ignorati\n" :
  2064.                 "%ld characters follow BinHex data: ignored\n", hqx_length);
  2065.     }
  2066. hqx_end_of_file();
  2067. mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2068. }
  2069.  
  2070. void write_hqx_fork(chunk_size,size)
  2071.   short chunk_size;
  2072.   long size;
  2073. {
  2074. short bytes_to_read;
  2075.  
  2076. reinit_hd_buffering();
  2077. current_crc=0;
  2078. while (size) {
  2079.     bytes_to_read= chunk_size;
  2080.     if(bytes_to_read>size) bytes_to_read=size;
  2081.     read_hqx(&tarh,bytes_to_read);
  2082.     size -= bytes_to_read;
  2083.     if(write_hd((char*) &tarh, bytes_to_read) ) pbsyserr(&pb);
  2084.     }
  2085. if(flush_hd_buffer()) pbsyserr(&pb);
  2086. get_openfile_location(pb.ioParam.ioRefNum);
  2087. PBCloseSync(&pb);
  2088. devo_chiudere_out=false;
  2089. check_CRC();
  2090. }
  2091.  
  2092. void write_pit_fork(chunk_size,size)
  2093.   short chunk_size;
  2094.   long size;
  2095. {
  2096. int bytes_to_read;
  2097.  
  2098. reinit_hd_buffering();
  2099.  
  2100. while (size) {
  2101.     bytes_to_read= chunk_size;
  2102.     if(bytes_to_read>size) bytes_to_read=size;
  2103.     get_pit_bytes(&tarh,bytes_to_read);
  2104.  
  2105.     size -= bytes_to_read;
  2106.     if(write_hd((char*) &tarh, bytes_to_read)) pbsyserr(&pb);
  2107.     }
  2108. if(flush_hd_buffer()) pbsyserr(&pb);
  2109. get_openfile_location(pb.ioParam.ioRefNum);
  2110. PBCloseSync(&pb);
  2111. devo_chiudere_out=false;
  2112. }
  2113.  
  2114.  
  2115. void set_binhex ()
  2116. /* set the file informations from the BinHex header, almost identical to setmacbin */
  2117. {
  2118. FileParam fpb;
  2119. fpb.ioFVersNum = 0;
  2120. fpb.ioFDirIndex = 0;
  2121.  
  2122. if((fpb.ioDirID=openfile_dirID)!=0){
  2123.     fpb.ioVRefNum=openfile_vrefnum;
  2124.     fpb.ioNamePtr=mac_file_name;
  2125.     }
  2126. else{
  2127.     fpb.ioVRefNum=pb.fileParam.ioVRefNum;
  2128.     fpb.ioNamePtr=pb.fileParam.ioNamePtr;
  2129.     }
  2130.  
  2131. if (PBHGetFInfoSync(&fpb)) pbsyserr(&fpb);
  2132.  
  2133. clear_unused_fields();
  2134. mcopy(&fpb.ioFlFndrInfo, &macbinh.finfo, 10); /* type,creator e flags ma non il resto*/
  2135. if(file_aperto==ff_binhex){
  2136.     fpb.ioFlCrDat=macbinh.cdate;
  2137.     fpb.ioFlMdDat=macbinh.mdate;
  2138.     }
  2139. else if(file_date!=-1)
  2140.         fpb.ioFlCrDat = fpb.ioFlMdDat = file_date + UNIXTIME;
  2141. fpb.ioDirID=openfile_dirID;    /* PBHSetFInfo writes the FlNum return value in that field ! */
  2142. if (PBHSetFInfoSync(&fpb)) pbsyserr(&fpb);
  2143. }
  2144.  
  2145.  
  2146. short untar_checksum(buffer,do_error,verbose)
  2147. register unsigned char *buffer;
  2148. Boolean verbose;
  2149. {
  2150. register int i;
  2151. register long chksum;
  2152. long hchksum;
  2153. #define tar_chksum_offset 148 /* (tarh.checksum-(char*)&tarh) */
  2154. hchksum = untar_number(((tarh_type*)buffer)->chksum,do_error);
  2155. if(hchksum==-1){
  2156.     if(verbose) printf("Empty header checksum\n");
  2157.     return -2;        /* testata non tar */
  2158.     }
  2159. chksum= ' ' * 8;    /* nel calcolo del checksum, il campo checksum era sostituito
  2160.                     da spazi */
  2161. for (i=0; i < tar_chksum_offset; ++i)
  2162.     chksum += (unsigned char)*buffer++;
  2163. for (i+=8,buffer+=8; i < sizeof(tarh); ++i)
  2164.     chksum += (unsigned char)*buffer++;
  2165.  
  2166. if (chksum == hchksum) return 0;    /* tutto OK */
  2167. if(verbose){
  2168.     printf("Bad header checksum ");
  2169.     if(expert_mode){
  2170.         if(((tarh_type*)disk_buffer)->linkflag!='V')
  2171.             if(print_if_string("(got %s expected ",((tarh_type*)disk_buffer)->chksum,8))
  2172.                 printf("%lo)",chksum);
  2173.         }
  2174.     printf("\n");
  2175.     }
  2176. return -1;
  2177. }
  2178.  
  2179.  
  2180. short chkmacbin (fsize,relax_test)
  2181. /* tests whether the file is MacBinary */
  2182.   long fsize;
  2183.   int relax_test;
  2184. {
  2185.   char buf[128];
  2186.  
  2187.  
  2188.   if (fsize == 0) return 0;
  2189.   if (readblock(buf,128))     /* devo leggerlo comunque, per uniformitê */
  2190.       raise_error();
  2191.   if (fsize < 128){
  2192.     unget_block();
  2193.     return 0;
  2194.     }
  2195.   mcopy(&macbinh, &buf[1], sizeof(macbinh));
  2196.  
  2197. /* in the MacBinary format, the data and resource forks should occupy an
  2198. integer number of 128 bytes blocks (the size of XMODEM blocks): however, 
  2199. some programs save space by not extending the two forks, hence I must
  2200. accept both standard ad "compact" formats
  2201. */
  2202.  
  2203. if (buf[0] == 0 && macbinh.zero == 0 && macbinh.nlen < 64 && macbinh.nlen > 0 )
  2204.     if(macbinh.dflen >= 0 && macbinh.rflen >= 0 ){
  2205.         short i=isMacBin2(buf);
  2206.         long expected_length_compact=macbinh.dflen +macbinh.rflen + 128L;
  2207.         long expected_length_standard=macbinsz(macbinh.dflen) + macbinsz(macbinh.rflen) + 128L;
  2208.         if( (MacBinaryII=i>0)){
  2209. /* The MacBinary || standard defines fields for the sizes of extra header info
  2210. and of comment:
  2211. >  Offset 099-Word, length of Get Info comment to be sent after the resource
  2212. >             fork (if implemented).
  2213. > *Offset 120-Word, Length of a secondary header.  If this is non-zero,
  2214. >             Skip this many bytes (rounded up to the next multiple of 128)
  2215. >             This is for future expansion only, when sending files with
  2216. >             MacBinary, this word should be zero.
  2217.  we've never seen files using those fields, nor versions of MacbinaryII
  2218.  bigger than 129, but it would not be honest to declare that suntar is
  2219.  MacBinaryII compatible without supporting them
  2220. */
  2221.             mcopy(&mbIIsec_head_len,&macbinh.headlen,2);
  2222.             mbIIsec_head_len = macbinsz(mbIIsec_head_len);
  2223.             expected_length_standard += macbinh.gilen + mbIIsec_head_len;
  2224.             /* I believe that a MBII file can't be "compact", and surely it can't 
  2225.             be compact and have comment info or secondary header */
  2226.             }
  2227.         if(relax_test ||
  2228.             (fsize==expected_length_compact||fsize==expected_length_standard) &&
  2229.             i>=0 ){
  2230.             notTrueMacBinary = fsize<expected_length_standard;
  2231.             if(relax_test==ff_c_macbin&&fsize<expected_length_standard)
  2232.                 notTrueMacBinary=true;
  2233.  
  2234.             if( MacBinaryII )
  2235.                 macbinh.finfo.fdFlags = macbinh.finfo.fdFlags&0xFF00 |
  2236.                     (unsigned char) macbinh.extra_fflags;
  2237.             /* else
  2238.                 macbinh.finfo.fdFlags = macbinh.finfo.fdFlags&0xFF00; NO:
  2239. The first MacBinary standard did not store bits 7-0, stating that
  2240. the byte following bits 15-8 should be zeroed. But mtar did not zero it, and maybe
  2241. it's the same for other programs (but NOT for BinHex5.0), anyway suntar does not check
  2242. for them to be zero, and in a MacBinary (not MacBinary II) files which has a nonzero 
  2243. value in that byte it believes that it's containing the correct values of bits 0-7.
  2244. */
  2245.               return 1;
  2246.               }
  2247.         }
  2248.     unget_block();
  2249.     return 0;
  2250. }
  2251.  
  2252. void setdata ()
  2253. /* set modification date = creation date */
  2254. {
  2255. FileParam fpb;
  2256. fpb.ioFVersNum = 0;
  2257. fpb.ioFDirIndex = 0;
  2258.  
  2259. if((fpb.ioDirID=openfile_dirID)!=0){
  2260.     fpb.ioVRefNum=openfile_vrefnum;
  2261.     fpb.ioNamePtr=mac_file_name;
  2262.     }
  2263. else{
  2264.     fpb.ioVRefNum=pb.fileParam.ioVRefNum;
  2265.     fpb.ioNamePtr=pb.fileParam.ioNamePtr;
  2266.     }
  2267. if (PBHGetFInfoSync(&fpb)==noErr){    /* not to be able to set the date is NOT a big error */
  2268.     fpb.ioFlMdDat = fpb.ioFlCrDat;
  2269.     fpb.ioDirID=openfile_dirID;
  2270.     PBHSetFInfoSync(&fpb);
  2271.     }
  2272. }
  2273.  
  2274. /******* end of routines by Gail Zacharias, rewritten by Speranza ********/
  2275.  
  2276. /***************** start of routines by Gail Zacharias **********/
  2277.  
  2278.  
  2279. void untar ()
  2280. {
  2281.  
  2282. long exp_check;
  2283. short i;
  2284.     if(expert_mode) print_sector_n(sect_n);
  2285.     sect_n++;
  2286.     more_in_bytes=0;    /* forse non necessario, ma prudente */
  2287.  
  2288.     mcopy(&tarh,&disk_buffer,sizeof(tarh));
  2289.     if ( (i=untar_checksum(&disk_buffer[0],1,true)) != 0 ){
  2290.         if(i==-2 || !ignore_errors) raise_error();
  2291.         if(i==-1) printf(s_spazi);
  2292.         }
  2293.     copia_ultimo_header(disk_buffer,sect_n);    /* sect_n Å giê stato incrementato */
  2294.     last_offset=0;        /* l'offset Å 0 perchÄ non Å un header 'M' */
  2295.  
  2296.     file_date= untar_number(&tarh.mtime,false);
  2297.  
  2298.     switch (tarh.linkflag) {
  2299.     case '\0': case '0': case '7':
  2300. is_file:    
  2301.         if (tarh.name[strlen(tarh.name)-1] == '/')
  2302.             untar_directory();
  2303.         else
  2304.             untar_file(untar_number(tarh.size,1));
  2305.         break;
  2306.     case '1': case '2':
  2307.         untar_link();
  2308.         break;
  2309.     case '5':
  2310.         untar_directory();
  2311.         break;
  2312.     case 'M':
  2313.         if(untar_number(&tarh.offset,-1)==0) goto is_file;        /* the file header
  2314.             was in the last sector of previous disk, hence this continuation
  2315.             header is followed by the whole contents of the file, so it may
  2316.             be extracted starting from here: all informations are available... */
  2317.         /* else continue */
  2318.     case 'V':
  2319.         printf("Bad use of GNU extensions\n");
  2320.         raise_error();
  2321.         break;
  2322.     default:
  2323.         printf("Unknown header type (octal %o)\n", tarh.linkflag);
  2324.         raise_error();
  2325.     }
  2326. }
  2327.  
  2328.  
  2329. void untar_file (fsize)
  2330. long fsize;
  2331. {
  2332.   int nLF;
  2333.   short isText;
  2334.   short isBinHex;
  2335.   Boolean is_gif=false;
  2336.   long cdate=untar_number(bar_archive?((barh_type*)disk_buffer)->mtime:
  2337.         ((tarh_type*)disk_buffer)->mtime,-1);
  2338.  
  2339.     disable_autoflush();
  2340.     if(listonly!=2) printf("File %s", tarh.name);    /* 2 means Get File Info, which has
  2341.                 already printed the file name and size */
  2342.     if(!bar_archive){
  2343.         next_header_for_AIX = sect_n + ((fsize+511)>>9);
  2344.         if(next_header_for_AIX<sectors_on_floppy)
  2345.             next_header_for_AIX=-1;
  2346.         else
  2347.             next_header_for_AIX-=sectors_on_floppy;
  2348.         }
  2349.     if(sect_n==sectors_on_floppy){
  2350.         if(fase==hack_listing){
  2351.             printf(" (%ld bytes, on next disk)\n",fsize);
  2352.             /* for expert list of AIX archives, I must let sect_n point to next
  2353.             file header... */
  2354.             enable_autoflush();
  2355.             longjmp(main_loop,-1);
  2356.             }
  2357.         else
  2358.             start_of_line();    /* ci saranno i messaggi di cambio disco...
  2359.                                 --some messages are arriving... */
  2360.         enable_autoflush();
  2361.         }
  2362.     if ( file_aperto==ff_macbin || file_aperto<=ff_tarbar && chkmacbin(fsize,0)){
  2363.         /*printf(" ");
  2364.         if(fase==hack_listing)*/
  2365.         if(listonly!=2) printf(" (%ld bytes) ",fsize);
  2366.         if(notTrueMacBinary) printf("compact ");
  2367.         printf("MacBinary");
  2368.         if(MacBinaryII) printf(" II");
  2369.         printf("\n");
  2370.         if(expert_mode&&file_aperto<=ff_tarbar) printf(s_spazi);
  2371.         printf(in_Italia ? "Contenente":"Containing");
  2372.         printf(" %p (", &macbinh.nlen);
  2373.         printf("data %ld+res %ld bytes)", macbinh.dflen, macbinh.rflen);
  2374.         if(fase==hack_listing){
  2375.             printf("\n%s",s_spazi);
  2376.             print_type_creator(macbinh.finfo.fdType,macbinh.finfo.fdCreator);
  2377.             if(cdate!=-1) print_one_date(cdate+UNIXTIME,in_Italia?"  creato ":"  created ");    /* di solito in expert mode non
  2378.                     bado alla lingua, ma poi stampo una stringa del toolbox che lo fa...*/
  2379.             }
  2380.         printf("\n");
  2381.         enable_autoflush();
  2382.  
  2383.         check_confirmation();    /* se ora andassi in non_convertire, nessun problema... */
  2384.         unix_to_mac(tarh.name);
  2385.  
  2386.         untar_macbin(fsize);
  2387.         }
  2388.     else{
  2389.         if(listonly!=2) printf(" (%ld bytes)",fsize);    /* queste scritte devono stare prima della
  2390.                     check_confirmation, ma del resto i test sulle conversioni vanno dopo
  2391.                     e questo complica un po' le cose */
  2392.         if(file_aperto<=ff_tarbar)
  2393.             isBinHex= fsize>=20 && is_hqx_name();
  2394.         else
  2395.             isBinHex=file_aperto==ff_binhex;
  2396.         if(isBinHex){
  2397.             printf(in_Italia?" testo BinHex":" BinHex text");
  2398.             binary=0;    /* per il caso poi non vada convertito */
  2399.             }
  2400.         else{
  2401.             if(file_aperto<=ff_tarbar){
  2402.                   isText=isASCII(fsize,&nLF); /* grazie a chkmacbin, disk_buffer Å pieno... */
  2403.                     binary= ! (isText>0 && nLF>0);
  2404.                     }
  2405.             else{
  2406.                   isText= file_aperto==ff_ASCII;    /* I'm not here in that case, but
  2407.                           who knows what may happen in the future... */
  2408.                   binary=false;
  2409.                   }
  2410.  
  2411.             if (isText>0 && !binary)
  2412.                 printf(in_Italia?" testo ASCII con LF":" ASCII text using LF");
  2413.             else if(isText>0)
  2414.                 printf(in_Italia?" testo ASCII":" ASCII text");
  2415.             else if((is_gif=is_gif_file(fsize)))
  2416.                 printf(" CompuServe GIF");
  2417.             }
  2418.         if(fase==hack_listing)
  2419.             if(cdate!=-1) print_one_date(cdate+UNIXTIME,in_Italia?"  creato ":"  created ");
  2420.  
  2421.         printf("\n");
  2422.         enable_autoflush();
  2423.  
  2424.         check_confirmation();    /* durante il quale posso anche cambiare preferences */
  2425.         unix_to_mac(tarh.name);
  2426.  
  2427.         if( !(disable_binhex&1) && isBinHex==1 && 
  2428.             !(non_convertire&&file_aperto<=ff_tarbar && !listonly) ){
  2429.               untar_hqx(fsize);
  2430.               }
  2431.         else{
  2432.               if(is_gif ){
  2433.                   filecreator= gif_creator;
  2434.                   filetype='GIFf';
  2435.                   }
  2436.               else{
  2437.                   filecreator= (isText>0||isBinHex) ? text_creator : '????';
  2438.                   filetype= (isText||isBinHex) ? 'TEXT' : '????';
  2439.                   }
  2440.               untar_data(fsize);
  2441.           }
  2442.     }
  2443. }
  2444.  
  2445.  
  2446. void untar_data (fsize)
  2447.   long fsize;
  2448. {
  2449.  
  2450. #ifdef V_122
  2451.     if (!listonly && ! create_file(tarh.name,fsWrPerm,false)) {
  2452.         controlla_spazio(fsize,0L);
  2453.     #if 0    /* Think C Marker.... */
  2454.         }
  2455.     #endif
  2456. #else
  2457.     macbinh.dflen=fsize;        /* crea_e_controlla expects some data here... */
  2458.     macbinh.rflen=0;
  2459.     macbinh.finfo.fdFlags=0;
  2460.     if(!listonly && ! crea_e_controlla(false) ){
  2461. #endif
  2462.         pb.ioParam.ioReqCount = sizeof(tarh);
  2463.         notTrueMacBinary=true;    /* writefork tests it... in practice its value is
  2464.             irrelevant, since extra bytes in the last sector are skipped anyway */
  2465.         writefork(512, fsize, binary || non_convertire&&file_aperto<=ff_tarbar);
  2466.         if(save_modi_date) setdata();
  2467.         }
  2468.     else
  2469.         skip_file(fsize);
  2470. }
  2471.  
  2472. void untar_macbin (fsize)
  2473.   long fsize;
  2474. {
  2475. register char *cp;
  2476.  
  2477. for(cp = tarh.name+strlen(tarh.name); cp != tarh.name && cp[-1] != ':'; --cp);
  2478. mcopy(cp, macbinh.name, macbinh.nlen);
  2479. cp[macbinh.nlen] = '\0';
  2480. if(non_convertire&&file_aperto<=ff_tarbar){
  2481.     unget_block();    /* i 128 bytes di intestazione... */
  2482.     filetype='TEXT';
  2483.     filecreator='BnHq';        /* il creator di BinHex 5.0 */
  2484.       untar_data(fsize);
  2485.       return;
  2486.       }
  2487.  
  2488. filecreator=filetype='????';    /* temporaneamente, ma in caso di errore resta cosô */
  2489.  
  2490. #ifdef V_122
  2491. if (!listonly && ! create_file(tarh.name,fsWrPerm,true)) {
  2492.     controlla_spazio(macbinh.dflen,macbinh.rflen);
  2493.     conferma_invisibili();
  2494.     #if 0    /* Think C Marker.... */
  2495.         }
  2496.     #endif
  2497. #else
  2498.  
  2499. if(!listonly && ! crea_e_controlla(true) ){
  2500. #endif
  2501.     if(MacBinaryII) skip_macbinII(mbIIsec_head_len);    /* secondary header... */
  2502.     writefork(128,macbinh.dflen, 1);
  2503.     pb.ioParam.ioVersNum = 0;
  2504.     pb.ioParam.ioPermssn = fsWrPerm;
  2505.     pb.ioParam.ioMisc = 0;
  2506.     if((pb.fileParam.ioDirID=openfile_dirID)!=0){
  2507.         pb.ioParam.ioVRefNum=openfile_vrefnum;
  2508.         pb.ioParam.ioNamePtr=mac_file_name;
  2509.         }
  2510.     if( PBHOpenRFSync(&pb)) pbsyserr(&pb);
  2511.     devo_chiudere_out=true;
  2512.     pb.ioParam.ioReqCount = 128;
  2513.     writefork(128,macbinh.rflen, 1);
  2514.     if(MacBinaryII) skip_macbinII(macbinh.gilen);        /* comment */
  2515.     setmacbin();
  2516.  
  2517.     end_of_file();
  2518.     }
  2519. else
  2520.     skip_file(fsize);
  2521. }
  2522.  
  2523. void writefork(chunk_size, size, binp)
  2524. short chunk_size;
  2525. long size;
  2526. Boolean binp;
  2527. {
  2528.     short bytes_to_read;
  2529.  
  2530.     reinit_hd_buffering();
  2531.  
  2532.     while (size) {
  2533.         bytes_to_read= chunk_size;
  2534.         if(notTrueMacBinary && bytes_to_read>size) bytes_to_read=size;
  2535.         if (readblock(&tarh, bytes_to_read))
  2536.              raise_error();
  2537.         if(bytes_to_read>size) bytes_to_read=size;    /* in true MacBinary, I may read
  2538.             from the archive more bytes than I write to the file */
  2539.         size -= bytes_to_read;
  2540.         if (!binp){
  2541.             register int i;
  2542.             register char*p=tarh.name;
  2543.             for (i=bytes_to_read; --i >= 0 ; p++)
  2544.                 if (*p == LF) *p = CR;
  2545.         }
  2546.         
  2547.         if(write_hd((char*) &tarh, bytes_to_read)) pbsyserr(&pb);
  2548.     }
  2549.     if(flush_hd_buffer()) pbsyserr(&pb);
  2550.  
  2551.     get_openfile_location(pb.ioParam.ioRefNum);
  2552.  
  2553.     PBCloseSync(&pb);
  2554.     devo_chiudere_out=false;
  2555. }
  2556.  
  2557. void setmacbin ()
  2558. /* set the file informations from the MacBinary header */
  2559. {
  2560. FileParam fpb;
  2561. fpb.ioFVersNum = 0;
  2562. fpb.ioFDirIndex = 0;
  2563.  
  2564. if((fpb.ioDirID=openfile_dirID)!=0){
  2565.     fpb.ioVRefNum=openfile_vrefnum;
  2566.     fpb.ioNamePtr=mac_file_name;
  2567.     }
  2568. else{
  2569.     fpb.ioVRefNum=pb.fileParam.ioVRefNum;
  2570.     fpb.ioNamePtr=pb.fileParam.ioNamePtr;
  2571.     }
  2572.  
  2573. if (PBHGetFInfoSync(&fpb)) pbsyserr(&fpb);
  2574. clear_unused_fields();
  2575. mcopy(&fpb.ioFlFndrInfo, &macbinh.finfo, 10);
  2576. fpb.ioFlCrDat = macbinh.cdate;
  2577. fpb.ioFlMdDat = macbinh.mdate;
  2578.  
  2579. fpb.ioDirID=openfile_dirID;
  2580. if (PBHSetFInfoSync(&fpb)) pbsyserr(&fpb);
  2581. }
  2582.  
  2583. void untar_directory ()
  2584. {
  2585.   int len = strlen(tarh.name);
  2586.  
  2587.   if (len && tarh.name[len-1] != '/') {
  2588.     tarh.name[len] = '/';
  2589.     tarh.name[len+1] = '\0';
  2590.   }
  2591.   if(!bar_archive){
  2592.         if(sect_n<sectors_on_floppy)
  2593.             next_header_for_AIX=-1;
  2594.         else
  2595.             next_header_for_AIX=sect_n-sectors_on_floppy;
  2596.         }
  2597.   printf("Directory %s\n", tarh.name);
  2598.   unix_to_mac(tarh.name);
  2599.   if (!tarh.name[1] ) return;
  2600.   check_conf_dir(tarh.name);
  2601.   if(!listonly) create_directory(tarh.name);
  2602. }
  2603.  
  2604.  
  2605.  
  2606. /*  fname may contain a filename after the last ':', it will be ignored */
  2607. void create_directory (fname)
  2608.   char *fname;
  2609. {
  2610.   FileParam fpb;
  2611.   char name[128], *cp, *bp;
  2612.   OSErr i;
  2613.  
  2614.   cp = fname + strlen(fname);
  2615.   for (bp = fname; *bp == ':'; ++bp);
  2616.  
  2617.   fpb.ioNamePtr = (StringPtr) name;
  2618.   do {
  2619.     while (cp[-1] != ':') --cp;
  2620.     if (cp == bp){ printf("%s - Bad directory name\n", fname); raise_error(); }
  2621.     strncpy(name+1, fname, name[0] = --cp - fname);
  2622. retry:
  2623.  
  2624. #ifdef USA_CURRVREFN
  2625.     fpb.ioVRefNum = curr_vrefnum;
  2626. #else
  2627.     fpb.ioVRefNum = 0;
  2628. #endif
  2629.  
  2630.     fpb.ioDirID = 0;
  2631.   } while ((i=PBDirCreateSync(&fpb)) == dirNFErr || i==fnfErr);
  2632. if(fpb.ioResult == dupFNErr){
  2633.     beep_in_foreground();
  2634.     if(fase==hack_reading){
  2635.         printf("Folder already existing\n");
  2636.         fpb.ioResult=noErr;
  2637.         }
  2638.     else{
  2639.         char buffer[100];
  2640.         short item;
  2641.         do{
  2642.             strcpy(buffer,tarh.name);
  2643.             c2pstr(buffer);
  2644.             item = semimodalDialog(137,NULL,NULL,t1,2,
  2645.                 in_Italia?"\pLa cartella\312":"\pThe folder\312",buffer,in_Italia?
  2646. "\p\resiste giê: prima di cliccare su un bottone puoi\rvoler cambiar nome o spostare quella preesistente":
  2647. "\p\ralready exists: before clicking a button, you might\rwish to rename, move or delete the old one",
  2648.                 teJustLeft,true);
  2649.             if(item!=1){
  2650.                 select_directory();
  2651.                 if(reply.good) goto retry;
  2652.                 }
  2653.             }
  2654.         while(item!=1);
  2655.         fpb.ioResult=noErr;            /* e continua senza preoccuparti */
  2656.         }
  2657.     }
  2658.   if (fpb.ioResult)pbsyserr(&fpb);
  2659.   while (1) {
  2660.     while (*++cp != ':') if (!*cp) return;
  2661.     strncpy(name+1, fname, name[0] = cp - fname);
  2662.  
  2663. #ifdef USA_CURRVREFN
  2664.     fpb.ioVRefNum = curr_vrefnum;
  2665. #else
  2666.     fpb.ioVRefNum = 0;
  2667. #endif
  2668.  
  2669.     fpb.ioDirID = 0;
  2670.     if (PBDirCreateSync(&fpb)) pbsyserr(&fpb);
  2671.   }
  2672. }
  2673.  
  2674. short create_file (fname,perm,tempattrib)
  2675.   char *fname;
  2676.   int perm;
  2677.   Boolean tempattrib;
  2678. /* ritorna 1 se, causa nome doppio o bad name, il salvataggio Å stato annullato
  2679. -- returns 1 if, due to a duplicate name, the user clicked on Cancel
  2680. */
  2681. {
  2682. /*
  2683. this routine was heavily modified by us (Speranza).
  2684. OK, it's incoherent that for duplicate names a dialog appears
  2685. while bad names are renamed without asking to the user...
  2686. */
  2687.     FileParam fpb;
  2688.     char name[128];
  2689.     extern SysEnvRec    gMac;
  2690.     Boolean opened_OK=false;
  2691.  
  2692.     fillmem(&fpb,0,sizeof(fpb));
  2693.     fpb.ioNamePtr = c2pstr(strcpy(name, fname));
  2694.  
  2695.     while(!opened_OK){
  2696.  
  2697.     #ifdef USA_CURRVREFN
  2698.         fpb.ioVRefNum = curr_vrefnum;
  2699.     #else
  2700.         fpb.ioVRefNum = 0;
  2701.     #endif
  2702.  
  2703.         fpb.ioFVersNum = 0;
  2704.         if(!PBCreateSync(&fpb)) {
  2705.         #ifdef USA_CURRVREFN
  2706.             fpb.ioVRefNum = curr_vrefnum;
  2707.         #else
  2708.             fpb.ioVRefNum = 0;
  2709.         #endif
  2710.  
  2711.             fpb.ioFVersNum = 0;
  2712.             fpb.ioFDirIndex = 0;
  2713.             opened_OK=true;
  2714.             }
  2715.         else{
  2716. /*printf("creo %p con %d\n",name,fpb.ioResult);*/
  2717. /* The new network software from Apple has a bug: with System 7.0 and 7.01, 
  2718. when the "File Sharing Extension" is active (on our Mac LC which is not 
  2719. connected to a network), PBCreate returns paramErr (error in parameter block) 
  2720. when it should return bdNamErr (bad name) and fnfErr (file not found) when 
  2721. it should return dirNFErr (folder not found).
  2722.   Since fnfErr was not expected, we handle it as a dirNFErr. However, thinking
  2723. that any paramErr is a misnamed bdNamErr would be dangerous, hence we check that
  2724. the name contains a subname which is longer than 31 characters (since unix_to_mac
  2725. translates any non-ASCII char and checks the placing of ':', there should
  2726. be no other possible cause for a bad name) before translating the err code.
  2727. */
  2728.             if(fpb.ioResult==paramErr && too_long(fname) ) fpb.ioResult=bdNamErr;
  2729.             if(fpb.ioResult == dupFNErr){
  2730.                 if( gestisci_nome_doppio(fname,name,&fpb) ) return 1;    /* annullato...*/
  2731.                 opened_OK=true;
  2732.                 }
  2733.             else if(fpb.ioResult== bdNamErr){
  2734.                 /* check_foreground(); no, ma... non lo so */
  2735.                 SysBeep(5);
  2736.                 make_badname(fname,name);    /* o anche qui proporre di cambiare nome !*/
  2737.                 fpb.ioNamePtr = c2pstr(strcpy(name, fname));
  2738.                 }
  2739.             else if (fpb.ioResult == dirNFErr || fpb.ioResult==fnfErr){ /* System 7
  2740.                     sometimes returns fnfErr when the folder does not exist */
  2741.                 create_directory(fname);
  2742.                 fpb.ioNamePtr = c2pstr(strcpy(name, fname));
  2743.                 }
  2744.             else{
  2745.                 pbsyserr(&fpb);
  2746.                 }
  2747.             }
  2748.           }
  2749.  
  2750.     fpb.ioNamePtr = c2pstr(strcpy(name, fname));
  2751.     if (PBGetFInfoSync(&fpb)) pbsyserr(&fpb);
  2752.     fpb.ioNamePtr = c2pstr(strcpy(name, fname));
  2753.     fpb.ioFlFndrInfo.fdType = filetype;
  2754.     fpb.ioFlFndrInfo.fdCreator = filecreator;
  2755.     if(file_aperto==ff_binhex)
  2756.         fpb.ioFlCrDat =macbinh.cdate;    /* non posso assegnare ora anche la data
  2757.             di modifica, perchÄ sto per modificare il file: in macbinary e binhex
  2758.             lo faccio dopo, per il .info pazienza... Poi, Å bene avere un'indicazione 
  2759.             che il salvataggio di un file non Å stato completato (l'icona appare solo
  2760.             alla fine...)
  2761.             --there is no reason to set the modification date now, since I'm 
  2762.             going to modify the file ! That date is modified after closing the
  2763.             file, but not for the .info file. Also type and creator are set only
  2764.             when closing the file, so that the icon appears only when the file is 
  2765.             completed and may be opened by the application.
  2766.             */
  2767.     else if(file_date!=-1 )
  2768.         fpb.ioFlCrDat = file_date + UNIXTIME;
  2769.  
  2770.     if (PBSetFInfoSync(&fpb)) pbsyserr(&fpb);
  2771.  
  2772.     pStrcpy(mac_file_name,fpb.ioNamePtr);
  2773.     pb.ioParam.ioVRefNum = fpb.ioVRefNum;
  2774.     pb.ioParam.ioNamePtr = mac_file_name;
  2775.     pb.ioParam.ioVersNum = 0;
  2776.     pb.ioParam.ioPermssn = perm;
  2777.     pb.ioParam.ioMisc = 0;
  2778.     pb.ioParam.ioRefNum = 0;
  2779.     if (PBOpenSync(&pb)) pbsyserr(&pb);
  2780.     devo_chiudere_out=true;
  2781.     return 0;
  2782. }
  2783.  
  2784.  
  2785. void untar_link ()
  2786. {
  2787.   /*unix_to_mac(tarh.name);
  2788.   unix_to_mac(tarh.linkname);*/
  2789.   printf("Link %s -> %s%s\n",  tarh.name, tarh.linkname,
  2790.           listonly?"":in_Italia?" (ignorato)":" (ignored)");
  2791.   if(!bar_archive){
  2792.         if(sect_n<sectors_on_floppy)
  2793.             next_header_for_AIX=-1;
  2794.         else
  2795.             next_header_for_AIX=sect_n-sectors_on_floppy;
  2796.         }
  2797. }
  2798.  
  2799. /* Convert Unix pathname to a mac pathname.  Do not allow absolute
  2800.    names - "/foo/bar/baz" is treated as if it were "foo/bar/baz".
  2801. */
  2802. void unix_to_mac (name)
  2803.   char *name;
  2804. {
  2805.   char buf[102];
  2806.   register unsigned char *cp = name, *bp = buf, *op,c;
  2807.   *bp++ = ':';
  2808.   op = bp;
  2809.   while (1) {
  2810.     if (cp[0] == '/') ++cp;
  2811.     else if (cp[0] == '.' && cp[1] == '/') cp += 2;
  2812.     else if (cp[0] == '.' && cp[1] == '.' && cp[2] == '/') {
  2813.       if (op == bp) *bp++ = ':', op = bp;
  2814.       else for (--op; op != bp && op[-1] != ':'; --op);
  2815.       cp += 3;
  2816.     }
  2817.     else {
  2818.       while (c=*cp, c!=0 && c != '/'){
  2819.           if(c== ':')
  2820.               c= '/';
  2821.           else if(c=='_' && !pres_underscore)
  2822.               c=' ';
  2823.           else if(c<' '||c>126) c=0xC9;    /* '╔' */
  2824.           *op++ = c;
  2825.           cp++;
  2826.           }
  2827.       if (!*cp++) break;
  2828.       *op++ = ':';
  2829.     }
  2830.   }
  2831.   *op = '\0';
  2832.   strcpy(name, buf);
  2833. }
  2834.  
  2835. #if 0
  2836. /* Name is the user-specified name, file is the actual tarred file */
  2837. void match_file (name, file)
  2838.   char *name, *file;
  2839. {
  2840.   char *cp;
  2841.   if (!strdiff(name, file)) return 1;
  2842.   if ((cp = strrchr(file, ':')) && !strdiff(cp+1, name)) return 1;
  2843.   if (name[strlen(name)-1] == ':' && strdiff(name, file) >= 0) return 1;
  2844.   return 0;
  2845. }
  2846.  
  2847. /* return 0 if the same, 1 if s1 is a substring of s2, -1 otherwise */
  2848. strdiff (s1, s2)
  2849.   char *s1, *s2;
  2850. {
  2851.   while (*s1) {
  2852.     if (*s1 != *s2) {
  2853.       char c1 = *s1;
  2854.       if ('A' <= c1 && c1 <= 'Z') c1 |= 0x20;
  2855.       if ('a' > c1 || c1 > 'z' || c1 != (*s2 | 0x20)) return -1;
  2856.     }
  2857.     ++s1, ++s2;
  2858.   }
  2859.   return (*s2 ? 1 : 0);
  2860. }
  2861. #endif
  2862.  
  2863. long untar_number (cp,doerror)
  2864.   char *cp;
  2865. {
  2866.   int neg = 0;
  2867.   long num = 0;
  2868.   while (*cp == ' ') cp++;
  2869.   if (*cp == '-') neg++, cp++;
  2870.   if('0' <= *cp && *cp <= '7'){
  2871.       while ('0' <= *cp && *cp <= '7') num = (num<<3) + (*cp++ - '0');
  2872.       if (neg) num = -num;
  2873.       }
  2874.   else
  2875.       cp="A";        /* per fargli dare errore
  2876.                   -- in order to force the error */
  2877.   if(*cp!='\0'&&*cp!=' '){
  2878.       if(doerror>=0)
  2879.           printf(in_Italia?"Testata non in formato %car !\n":
  2880.               "Error: not a %car header !\n",bar_archive ? 'b' : 't');
  2881.       if(doerror>0)
  2882.           raise_error();
  2883.       else
  2884.           return -1L;
  2885.   }
  2886.   return num;
  2887. }
  2888.  
  2889. void pbsyserr (fpb)
  2890.   ioParam *fpb;
  2891. {
  2892.   int err = fpb->ioResult;
  2893.   char *name = (char*) fpb->ioNamePtr;
  2894.   p2cstr(name);
  2895.   start_of_line();
  2896.   if (err == fnfErr) printf("%s - File not found\n", name);
  2897.   else if (err == nsvErr) printf("%s - No such volume\n", name);
  2898.   else if (err == tmfoErr) printf("%s - Too many files open\n", name);
  2899.   else if (err == permErr) printf("%s - Permissions error\n", name);
  2900.   else if (err == dupFNErr) printf("%s - Duplicate filename\n", name);
  2901.   else if (err == eofErr) printf("%s - Premature end of file\n", name);
  2902.   else if (err == dskFulErr) printf("%s - Disk full\n", name);
  2903.   else printf("%s - Error #%d\n", name, err);
  2904.   raise_error();
  2905. }
  2906.