17 #include <atalk/adouble.h>
18 #include <netatalk/endian.h>
21 /* String used to indicate standard input instead of a disk
22 file. Should be a string not normally used for a file
33 /* Size of a macbinary file header
35 #define HEADBUFSIZ 128
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.
43 struct bin_file_data {
44 u_int32_t forklen[ NUMFORKS ];
45 char path[ MAXPATHLEN + 1];
48 time_t gmtoff; /* to convert from/to localtime */
51 extern char *forkname[];
52 u_char head_buf[HEADBUFSIZ];
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.
60 bin_open( binfile, flags, fh, options )
71 fprintf( stderr, "entering bin_open\n" );
74 /* call localtime so that we get the timezone offset */
76 #ifndef NO_STRUCT_TM_GMTOFF
78 if (tp = localtime(&t))
79 bin.gmtoff = tp->tm_gmtoff;
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 ) {
90 fprintf( stderr, "opened %s for read\n", binfile );
92 if ((( rc = test_header() ) > 0 ) &&
93 ( bin_header_read( fh, rc ) == 0 )) {
96 fprintf( stderr, "%s is not a macbinary file.\n", binfile );
99 if (options & OPTION_STDOUT)
100 bin.filed = fileno(stdout);
102 maxlen = sizeof( bin.path ) - 1;
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 );
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 ) {
115 fprintf( stderr, "opened %s for write\n",
116 (options & OPTION_STDOUT) ? "(stdout)" : bin.path );
120 if ( bin_header_write( fh ) != 0 ) {
122 fprintf( stderr, "%s\n", bin.path );
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.
135 bin_close( keepflag )
139 fprintf( stderr, "entering bin_close\n" );
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 )) {
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.
160 bin_read( fork, buffer, length )
171 fprintf( stderr, "bin_read: fork is %s\n", forkname[ fork ] );
172 fprintf( stderr, "bin_read: remaining length is %d\n", bin.forklen[fork] );
175 if ( bin.forklen[ fork ] < 0 ) {
176 fprintf( stderr, "This should never happen, dude!\n" );
177 return( bin.forklen[ fork ] );
180 if ( bin.forklen[ fork ] == 0 ) {
181 if ( fork == DATA ) {
182 pos = lseek( bin.filed, 0, SEEK_CUR );
184 fprintf( stderr, "current position is %ld\n", pos );
186 if (pos = pos % HEADBUFSIZ) {
187 pos = lseek( bin.filed, HEADBUFSIZ - pos, SEEK_CUR );
190 fprintf( stderr, "current position is %ld\n", pos );
196 if ( bin.forklen[ fork ] < length ) {
197 readlen = bin.forklen[ fork ];
202 fprintf( stderr, "bin_read: readlen is %d\n", readlen );
203 fprintf( stderr, "bin_read: cc is %d\n", cc );
207 while (( readlen > 0 ) && ( cc > 0 )) {
208 if (( cc = read( bin.filed, buf_ptr, readlen )) > 0 ) {
210 fprintf( stderr, "bin_read: cc is %d\n", cc );
217 cc = buf_ptr - buffer;
218 bin.forklen[ fork ] -= cc;
222 fprintf( stderr, "bin_read: chars read is %d\n", cc );
231 bin_write( fork, buffer, length )
243 fprintf( stderr, "bin_write: fork is %s\n", forkname[ fork ] );
244 fprintf( stderr, "bin_write: remaining length is %d\n", bin.forklen[fork] );
247 if (( fork == RESOURCE ) && ( bin.forklen[ DATA ] != 0 )) {
248 fprintf( stderr, "Forklength error.\n" );
252 buf_ptr = (char *)buffer;
253 if ( bin.forklen[ fork ] >= length ) {
256 fprintf( stderr, "Forklength error.\n" );
261 fprintf( stderr, "bin_write: write length is %d\n", writelen );
264 while (( writelen > 0 ) && ( cc >= 0 )) {
265 cc = write( bin.filed, buf_ptr, writelen );
270 perror( "Couldn't write to macbinary file:" );
273 bin.forklen[ fork ] -= length;
275 if ( bin.forklen[ fork ] < 0 ) {
276 fprintf( stderr, "This should never happen, dude!\n" );
277 return( bin.forklen[ fork ] );
281 * add the padding at end of data and resource forks
284 if ( bin.forklen[ fork ] == 0 ) {
285 pos = lseek( bin.filed, 0, SEEK_CUR );
287 fprintf( stderr, "current position is %ld\n", pos );
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:" );
297 fprintf( stderr, "current position is %ld\n", pos );
302 fprintf( stderr, "\n" );
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.
314 bin_header_read( fh, revision )
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
327 switch ( revision ) {
330 mask = htons( 0xfcee );
331 memcpy(&fh->finder_info.fdFlags + 1, head_buf + 101,1 );
334 mask = htons( 0xfc00 );
342 * Go through and copy all the stuff you can get from the
343 * MacBinary header into the fh struct. What fun!
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';
366 fh->finder_xinfo.fdScript = *(head_buf + 106);
367 fh->finder_xinfo.fdXFlags = *(head_buf + 107);
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" );
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.
402 bin_header_write( fh )
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);
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;
433 head_buf[ 123 ] = 129;
435 bin.headercrc = htons( updcrc( (u_short) 0, head_buf, 124 ));
436 memcpy(head_buf + 124, &bin.headercrc, sizeof( bin.headercrc ));
438 bin.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
439 bin.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
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" );
454 write_ptr = (char *)head_buf;
455 wc = sizeof( head_buf );
457 while (( wc > 0 ) && ( wr >= 0 )) {
458 wr = write( bin.filed, write_ptr, wc );
463 perror( "Couldn't write macbinary header:" );
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.
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.
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.
490 const char zeros[25] = "";
496 fprintf( stderr, "entering test_header\n" );
499 cc = read( bin.filed, (char *)head_buf, sizeof( head_buf ));
500 if ( cc < sizeof( head_buf )) {
501 perror( "Premature end of file :" );
506 fprintf( stderr, "was able to read HEADBUFSIZ bytes\n" );
509 /* check for macbinary III header */
510 if (memcmp(head_buf + 102, "mBIN", 4) == 0)
513 /* check for macbinary II even if only one of the bytes is zero */
514 if (( head_buf[ 0 ] == 0 ) || ( head_buf[ 74 ] == 0 )) {
516 fprintf( stderr, "byte 0 and 74 are both zero\n" );
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 ) {
526 fprintf( stderr, "header crc didn't pan out\n" );
530 /* now see if we have a macbinary file. */
531 if ( head_buf[ 82 ] != 0 ) {
534 memcpy( &namelen, head_buf + 1, sizeof( namelen ));
536 fprintf( stderr, "name length is %d\n", namelen );
538 if (( namelen < 1 ) || ( namelen > 63 )) {
542 /* bytes 101 - 125 should be zero */
543 if (memcmp(head_buf + 101, zeros, sizeof(zeros)) != 0)
546 /* macbinary forks aren't larger than 0x7FFFFF */
547 memcpy(&cc, head_buf + 83, sizeof(cc));
551 memcpy(&cc, head_buf + 87, sizeof(cc));
558 fprintf( stderr, "byte 82 is zero and name length is cool\n" );