]> arthur.barton.de Git - netatalk.git/blob - bin/megatron/macbin.c
Missing paren in DEBUG section
[netatalk.git] / bin / megatron / macbin.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <sys/types.h>
6 #include <sys/uio.h>
7 #include <sys/time.h>
8 #include <sys/param.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <strings.h>
12 #include <syslog.h>
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <time.h>
16
17 #include <atalk/adouble.h>
18 #include <netatalk/endian.h>
19 #include "megatron.h"
20
21 /*      String used to indicate standard input instead of a disk
22         file.  Should be a string not normally used for a file
23  */
24 #ifndef STDIN
25 #       define  STDIN   "-"
26 #endif
27
28 /*      Yes and no
29  */
30 #define NOWAY           0
31 #define SURETHANG       1
32
33 /*      Size of a macbinary file header
34  */
35 #define HEADBUFSIZ      128
36
37 u_short         updcrc();
38
39 /*      Both input and output routines use this struct and the
40         following globals; therefore this module can only be used
41         for one of the two functions at a time.
42  */
43 struct bin_file_data {
44     u_int32_t           forklen[ NUMFORKS ];
45     char                path[ MAXPATHLEN + 1];
46     int                 filed;
47     u_short             headercrc;
48     time_t              gmtoff; /* to convert from/to localtime */
49 }               bin;
50
51 extern char     *forkname[];
52 u_char          head_buf[HEADBUFSIZ];
53
54 /* 
55  * bin_open must be called first.  pass it a filename that is supposed
56  * to contain a macbinary file.  an bin struct will be allocated and
57  * somewhat initialized; bin_filed is set.
58  */
59
60 bin_open( binfile, flags, fh, options )
61     char                *binfile;
62     int                 flags, options;
63     struct FHeader      *fh;
64 {
65     int                 maxlen;
66     int                 rc;
67     time_t              t;
68     struct tm           *tp;
69
70 #if DEBUG
71     fprintf( stderr, "entering bin_open\n" );
72 #endif
73
74     /* call localtime so that we get the timezone offset */
75     bin.gmtoff = 0;
76 #ifndef NO_STRUCT_TM_GMTOFF
77     time(&t);
78     if (tp = localtime(&t))
79         bin.gmtoff = tp->tm_gmtoff;
80 #endif
81
82     if ( flags == O_RDONLY ) { /* input */
83         if ( strcmp( binfile, STDIN ) == 0 ) {
84             bin.filed = fileno( stdin );
85         } else if (( bin.filed = open( binfile, flags )) < 0 ) {
86             perror( binfile );
87             return( -1 );
88         }
89 #if DEBUG
90         fprintf( stderr, "opened %s for read\n", binfile );
91 #endif
92         if ((( rc = test_header() ) > 0 ) && 
93                 ( bin_header_read( fh, rc ) == 0 )) {
94             return( 0 );
95         }
96         fprintf( stderr, "%s is not a macbinary file.\n", binfile );
97         return( -1 );
98     } else { /* output */
99         if (options & OPTION_STDOUT) 
100           bin.filed = fileno(stdout);
101         else {
102           maxlen = sizeof( bin.path ) - 1;
103 #if DEBUG
104           fprintf( stderr, "sizeof bin.path\t\t\t%d\n", sizeof( bin.path ));
105           fprintf( stderr, "maxlen \t\t\t\t%d\n", maxlen );
106 #endif
107           strncpy( bin.path, fh->name, maxlen );
108           strncpy( bin.path, mtoupath( bin.path ), maxlen );
109           strncat( bin.path, ".bin", maxlen - strlen( bin.path ));
110           if (( bin.filed = open( bin.path, flags, 0666 )) < 0 ) {
111             perror( bin.path );
112             return( -1 );
113           }
114 #if DEBUG
115           fprintf( stderr, "opened %s for write\n", 
116                    (options & OPTION_STDOUT) ? "(stdout)" : bin.path );
117 #endif
118         }
119
120         if ( bin_header_write( fh ) != 0 ) {
121             bin_close( TRASH );
122             fprintf( stderr, "%s\n", bin.path );
123             return( -1 );
124         }
125         return( 0 );
126     }
127 }
128
129 /* 
130  * bin_close must be called before a second file can be opened using
131  * bin_open.  Upon successful completion, a value of 0 is returned.  
132  * Otherwise, a value of -1 is returned.
133  */
134
135 bin_close( keepflag )
136     int                 keepflag;
137 {
138 #if DEBUG
139     fprintf( stderr, "entering bin_close\n" );
140 #endif
141     if ( keepflag == KEEP ) {
142         return( close( bin.filed ));
143     } else if ( keepflag == TRASH ) {
144         if (( strcmp( bin.path, STDIN ) != 0 ) && 
145                 ( unlink( bin.path ) < 0 )) {
146             perror ( bin.path );
147         }
148         return( 0 );
149     } else return( -1 );
150 }
151
152 /*
153  * bin_read is called until it returns zero for each fork.  when it is
154  * and finds that there is zero left to give, it seeks to the position
155  * of the next fork (if there is one ).
156  * bin_read must be called enough times to
157  * return zero and no more than that.
158  */
159
160 bin_read( fork, buffer, length )
161     int                 fork;
162     char                *buffer;
163     int                 length;
164 {
165     char                *buf_ptr;
166     int                 readlen;
167     int                 cc = 1;
168     off_t               pos;
169
170 #if DEBUG >= 3
171     fprintf( stderr, "bin_read: fork is %s\n", forkname[ fork ] );
172     fprintf( stderr, "bin_read: remaining length is %d\n", bin.forklen[fork] );
173 #endif
174
175     if ( bin.forklen[ fork ] < 0 ) {
176         fprintf( stderr, "This should never happen, dude!\n" );
177         return( bin.forklen[ fork ] );
178     }
179
180     if ( bin.forklen[ fork ] == 0 ) {
181         if ( fork == DATA ) {
182             pos = lseek( bin.filed, 0, SEEK_CUR );
183 #if DEBUG
184             fprintf( stderr, "current position is %ld\n", pos );
185 #endif
186             if (pos = pos % HEADBUFSIZ) {
187               pos = lseek( bin.filed, HEADBUFSIZ - pos, SEEK_CUR );
188             }
189 #if DEBUG
190             fprintf( stderr, "current position is %ld\n", pos );
191 #endif
192         }
193         return( 0 );
194     }
195
196     if ( bin.forklen[ fork ] < length ) {
197         readlen = bin.forklen[ fork ];
198     } else {
199         readlen = length;
200     }
201 #if DEBUG >= 3
202     fprintf( stderr, "bin_read: readlen is %d\n", readlen );
203     fprintf( stderr, "bin_read: cc is %d\n", cc );
204 #endif
205
206     buf_ptr = buffer;
207     while (( readlen > 0 ) && ( cc > 0 )) {
208         if (( cc = read( bin.filed, buf_ptr, readlen )) > 0 ) {
209 #if DEBUG >= 3
210             fprintf( stderr, "bin_read: cc is %d\n", cc );
211 #endif
212             readlen -= cc;
213             buf_ptr += cc;
214         }
215     }
216     if ( cc >= 0 ) {
217         cc = buf_ptr - buffer;
218         bin.forklen[ fork ] -= cc;
219     }
220
221 #if DEBUG >= 3
222     fprintf( stderr, "bin_read: chars read is %d\n", cc );
223 #endif
224     return( cc );
225 }
226
227 /*
228  * bin_write 
229  */
230
231 bin_write( fork, buffer, length )
232     int                 fork;
233     char                *buffer;
234     int                 length;
235 {
236     char                *buf_ptr;
237     int                 writelen;
238     int                 cc = 0;
239     off_t               pos;
240     u_char              padchar = 0;
241
242 #if DEBUG >= 3
243     fprintf( stderr, "bin_write: fork is %s\n", forkname[ fork ] );
244     fprintf( stderr, "bin_write: remaining length is %d\n", bin.forklen[fork] );
245 #endif
246
247     if (( fork == RESOURCE ) && ( bin.forklen[ DATA ] != 0 )) {
248         fprintf( stderr, "Forklength error.\n" );
249         return( -1 );
250     }
251
252     buf_ptr = (char *)buffer;
253     if ( bin.forklen[ fork ] >= length ) {
254         writelen = length;
255     } else {
256         fprintf( stderr, "Forklength error.\n" );
257         return( -1 );
258     }
259
260 #if DEBUG >= 3
261     fprintf( stderr, "bin_write: write length is %d\n", writelen );
262 #endif
263
264     while (( writelen > 0 ) && ( cc >= 0 )) {
265         cc = write( bin.filed, buf_ptr, writelen );
266         buf_ptr += cc;
267         writelen -= cc;
268     }
269     if ( cc < 0 ) {
270         perror( "Couldn't write to macbinary file:" );
271         return( cc );
272     }
273     bin.forklen[ fork ] -= length;
274
275     if ( bin.forklen[ fork ] < 0 ) {
276         fprintf( stderr, "This should never happen, dude!\n" );
277         return( bin.forklen[ fork ] );
278     }
279
280 /*
281  * add the padding at end of data and resource forks
282  */
283
284     if ( bin.forklen[ fork ] == 0 ) {
285         pos = lseek( bin.filed, 0, SEEK_CUR );
286 #if DEBUG
287         fprintf( stderr, "current position is %ld\n", pos );
288 #endif
289         if (pos = pos % HEADBUFSIZ) { /* pad only if we need to */
290           pos = lseek( bin.filed, HEADBUFSIZ - pos - 1, SEEK_CUR );
291           if ( write( bin.filed, &padchar, 1 ) != 1 ) {
292             perror( "Couldn't write to macbinary file:" );
293             return( -1 );
294           }
295         }
296 #if DEBUG
297           fprintf( stderr, "current position is %ld\n", pos );
298 #endif
299     }
300
301 #if DEBUG
302         fprintf( stderr, "\n" );
303 #endif
304
305     return( length );
306 }
307
308 /* 
309  * bin_header_read is called by bin_open, and before any information can
310  * read from the fh substruct.  it must be called before any
311  * of the bytes of the other two forks can be read, as well.
312  */
313
314 bin_header_read( fh, revision )
315     struct FHeader      *fh;
316     int                 revision;
317 {
318     u_short             mask;
319
320 /*
321  * Set the appropriate finder flags mask for the type of macbinary
322  * file it is, and copy the extra macbinary II stuff from the header.
323  * If it is not a macbinary file revision of I or II, then return
324  * negative.
325  */
326
327     switch ( revision ) {
328         case 3:
329         case 2 :
330             mask = htons( 0xfcee );
331             memcpy(&fh->finder_info.fdFlags + 1, head_buf + 101,1 );
332             break;
333         case 1 :
334             mask = htons( 0xfc00 );
335             break;
336         default :
337             return( -1 );
338             break;
339     }
340
341 /*
342  * Go through and copy all the stuff you can get from the 
343  * MacBinary header into the fh struct.  What fun!
344  */
345
346     memcpy(fh->name, head_buf +  2, head_buf[ 1 ] );
347     memcpy(&fh->create_date, head_buf +  91, 4 );
348     fh->create_date = MAC_DATE_TO_UNIX(fh->create_date) - bin.gmtoff;
349     fh->create_date = AD_DATE_FROM_UNIX(fh->create_date);
350     memcpy( &fh->mod_date, head_buf +  95, 4 );
351     fh->mod_date = MAC_DATE_TO_UNIX(fh->mod_date) - bin.gmtoff;
352     fh->mod_date = AD_DATE_FROM_UNIX(fh->mod_date);
353     fh->backup_date = AD_DATE_START;
354     memcpy( &fh->finder_info, head_buf +  65, 8 );
355     memcpy( &fh->finder_info.fdFlags, head_buf + 73, 1 );
356     fh->finder_info.fdFlags &= mask;
357     memcpy(&fh->finder_info.fdLocation, head_buf + 75, 4 );
358     memcpy(&fh->finder_info.fdFldr, head_buf +  79, 2 );
359     memcpy(&fh->forklen[ DATA ],  head_buf + 83, 4 );
360     bin.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
361     memcpy(&fh->forklen[ RESOURCE ],  head_buf +  87, 4 );
362     bin.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
363     fh->comment[0] = '\0';
364
365     if (revision == 3) {
366       fh->finder_xinfo.fdScript = *(head_buf + 106);
367       fh->finder_xinfo.fdXFlags = *(head_buf + 107);
368     }
369
370 #if DEBUG >= 5
371     {
372         short           flags;
373
374         fprintf( stderr, "Values read by bin_header_read\n" );
375         fprintf( stderr, "name length\t\t%d\n", head_buf[ 1 ] );
376         fprintf( stderr, "file name\t\t%s\n", fh->name );
377         fprintf( stderr, "get info comment\t%s\n", fh->comment );
378         fprintf( stderr, "type\t\t\t%.*s\n", sizeof( fh->finder_info.fdType ),
379                 &fh->finder_info.fdType );
380         fprintf( stderr, "creator\t\t\t%.*s\n", 
381                 sizeof( fh->finder_info.fdCreator ), 
382                 &fh->finder_info.fdCreator );
383         memcpy( &flags, &fh->finder_info.fdFlags, sizeof( flags ));
384         flags = ntohs( flags );
385         fprintf( stderr, "flags\t\t\t%x\n", flags );
386         fprintf( stderr, "data fork length\t%ld\n", bin.forklen[DATA] );
387         fprintf( stderr, "resource fork length\t%ld\n", bin.forklen[RESOURCE] );
388         fprintf( stderr, "\n" );
389     }
390 #endif
391
392     return( 0 );
393 }
394
395 /* 
396  * bin_header_write is called by bin_open, and relies on information
397  * from the fh substruct.  it must be called before any
398  * of the bytes of the other two forks can be written, as well.
399  * bin_header_write and bin_header_read are opposites.
400  */
401
402 bin_header_write( fh )
403     struct FHeader      *fh;
404 {
405     char                *write_ptr;
406     u_int32_t           t;
407     int                 wc;
408     int                 wr;
409
410     memset(head_buf, 0, sizeof( head_buf ));
411     head_buf[ 1 ] = (u_char)strlen( fh->name );
412     memcpy( head_buf + 2, fh->name, head_buf[ 1 ] );
413     memcpy( head_buf + 65, &fh->finder_info, 8 );
414     memcpy( head_buf + 73, &fh->finder_info.fdFlags, 1);
415     memcpy( head_buf + 75, &fh->finder_info.fdLocation, 4 );
416     memcpy( head_buf + 79, &fh->finder_info.fdFldr, 2 );
417     memcpy( head_buf + 83, &fh->forklen[ DATA ], 4 );
418     memcpy( head_buf + 87, &fh->forklen[ RESOURCE ], 4 );
419     t = AD_DATE_TO_UNIX(fh->create_date) + bin.gmtoff;
420     t = MAC_DATE_FROM_UNIX(t);
421     memcpy( head_buf + 91, &t, sizeof(t) );
422     t = AD_DATE_TO_UNIX(fh->mod_date) + bin.gmtoff;
423     t = MAC_DATE_FROM_UNIX(t);
424     memcpy( head_buf + 95, &t, sizeof(t) );
425     memcpy( head_buf + 101, &fh->finder_info.fdFlags + 1, 1);
426
427     /* macbinary III */
428     memcpy( head_buf + 102, "mBIN", 4);
429     *(head_buf + 106) = fh->finder_xinfo.fdScript;
430     *(head_buf + 107) = fh->finder_xinfo.fdXFlags;
431     head_buf[ 122 ] = 130;
432
433     head_buf[ 123 ] = 129;
434
435     bin.headercrc = htons( updcrc( (u_short) 0, head_buf, 124 ));
436     memcpy(head_buf + 124, &bin.headercrc, sizeof( bin.headercrc ));
437
438     bin.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
439     bin.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
440
441 #if DEBUG >= 5
442     {
443         fprintf( stderr, "Values written by bin_header_write\n" );
444         fprintf( stderr, "name length\t\t%d\n", head_buf[ 1 ] );
445         fprintf( stderr, "file name\t\t%s\n", (char *)&head_buf[ 2 ] );
446         fprintf( stderr, "type\t\t\t%.4s\n", (char *)&head_buf[ 65 ] );
447         fprintf( stderr, "creator\t\t\t%.4s\n", (char *)&head_buf[ 69 ] );
448         fprintf( stderr, "data fork length\t%ld\n", bin.forklen[DATA] );
449         fprintf( stderr, "resource fork length\t%ld\n", bin.forklen[RESOURCE] );
450         fprintf( stderr, "\n" );
451     }
452 #endif
453
454     write_ptr = (char *)head_buf;
455     wc = sizeof( head_buf );
456     wr = 0;
457     while (( wc > 0 ) && ( wr >= 0 )) {
458         wr = write( bin.filed, write_ptr, wc );
459         write_ptr += wr;
460         wc -= wr;
461     }
462     if ( wr < 0 ) {
463         perror( "Couldn't write macbinary header:" );
464         return( wr );
465     }
466
467     return( 0 );
468 }
469
470 /*
471  * test_header is called from bin_open.  it checks certain values of
472  * the first 128 bytes, determines if the file is a MacBinary,
473  * MacBinary II, MacBinary III, or non-MacBinary file, and returns a
474  * one, two, three or negative one to indicate the file type.
475  *
476  * If the signature at 102 is equal to "mBIN," then it's a MacBinary
477  * III file. Bytes 0 and 74 must be zero for the file to be any type
478  * of MacBinary.  If the crc of bytes 0 through 123 equals the value
479  * at offset 124 then it is a MacBinary II.  If not, then if byte 82
480  * is zero, byte 2 is a valid value for a mac filename length (between
481  * one and sixty-three), and bytes 101 through 125 are all zero, then
482  * the file is a MacBinary. 
483  *
484  * NOTE: apple's MacBinary II files have a non-zero value at byte 74.
485  * so, the check for byte 74 isn't very useful.
486  */
487
488 test_header()
489 {
490     const char          zeros[25] = "";
491     u_int32_t           cc;
492     u_short             header_crc;
493     u_char              namelen;
494
495 #if DEBUG
496     fprintf( stderr, "entering test_header\n" );
497 #endif
498
499     cc = read( bin.filed, (char *)head_buf, sizeof( head_buf ));
500     if ( cc < sizeof( head_buf )) {
501         perror( "Premature end of file :" );
502         return( -1 );
503     }
504
505 #if DEBUG
506     fprintf( stderr, "was able to read HEADBUFSIZ bytes\n" );
507 #endif
508
509     /* check for macbinary III header */
510     if (memcmp(head_buf + 102, "mBIN", 4) == 0)
511         return 3;
512
513     /* check for macbinary II even if only one of the bytes is zero */
514     if (( head_buf[ 0 ] == 0 ) || ( head_buf[ 74 ] == 0 )) {
515 #if DEBUG
516       fprintf( stderr, "byte 0 and 74 are both zero\n" );
517 #endif
518       bin.headercrc = updcrc( (u_short) 0, head_buf, 124 );
519       memcpy(&header_crc, head_buf + 124, sizeof( header_crc ));
520       header_crc = ntohs( header_crc );
521       if ( header_crc == bin.headercrc ) {
522         return( 2 );
523       }
524
525 #if DEBUG
526       fprintf( stderr, "header crc didn't pan out\n" );
527 #endif
528     }
529
530     /* now see if we have a macbinary file. */
531     if ( head_buf[ 82 ] != 0 ) {
532         return( -1 );
533     }
534     memcpy( &namelen, head_buf + 1, sizeof( namelen ));
535 #if DEBUG
536     fprintf( stderr, "name length is %d\n", namelen );
537 #endif
538     if (( namelen < 1 ) || ( namelen > 63 )) {
539         return( -1 );
540     }
541
542     /* bytes 101 - 125 should be zero */
543     if (memcmp(head_buf + 101, zeros, sizeof(zeros)) != 0)
544         return -1;
545
546     /* macbinary forks aren't larger than 0x7FFFFF */
547     memcpy(&cc, head_buf + 83, sizeof(cc));
548     cc = ntohl(cc);
549     if (cc > 0x7FFFFF)
550         return -1;
551     memcpy(&cc, head_buf + 87, sizeof(cc));
552     cc = ntohl(cc);
553     if (cc > 0x7FFFFF)
554         return -1;
555
556
557 #if DEBUG
558     fprintf( stderr, "byte 82 is zero and name length is cool\n" );
559 #endif
560
561     return( 1 );
562 }