+/*
+ * $Id: macbin.c,v 1.15 2010-01-27 21:27:53 didg Exp $
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/param.h>
+#ifdef HAVE_FCNTL_H
#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <string.h>
#include <strings.h>
-#include <syslog.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <atalk/adouble.h>
#include <netatalk/endian.h>
#include "megatron.h"
+#include "macbin.h"
+#include "updcrc.h"
+
+/* This allows megatron to generate .bin files that won't choke other
+ well-known converter apps. It also makes sure that checksums
+ always match. (RLB) */
+#define MACBINARY_PLAY_NICE_WITH_OTHERS
/* String used to indicate standard input instead of a disk
file. Should be a string not normally used for a file
*/
#ifndef STDIN
# define STDIN "-"
-#endif
+#endif /* STDIN */
/* Yes and no
*/
*/
#define HEADBUFSIZ 128
-u_short updcrc();
-
/* Both input and output routines use this struct and the
following globals; therefore this module can only be used
for one of the two functions at a time.
*/
-struct bin_file_data {
+static struct bin_file_data {
u_int32_t forklen[ NUMFORKS ];
char path[ MAXPATHLEN + 1];
int filed;
} bin;
extern char *forkname[];
-u_char head_buf[HEADBUFSIZ];
+static u_char head_buf[HEADBUFSIZ];
/*
* bin_open must be called first. pass it a filename that is supposed
* somewhat initialized; bin_filed is set.
*/
-bin_open( binfile, flags, fh, options )
- char *binfile;
- int flags, options;
- struct FHeader *fh;
+int bin_open(char *binfile, int flags, struct FHeader *fh, int options)
{
int maxlen;
int rc;
#if DEBUG
fprintf( stderr, "entering bin_open\n" );
-#endif
+#endif /* DEBUG */
/* call localtime so that we get the timezone offset */
bin.gmtoff = 0;
#ifndef NO_STRUCT_TM_GMTOFF
time(&t);
- if (tp = localtime(&t))
+ tp = localtime(&t);
+ if (tp)
bin.gmtoff = tp->tm_gmtoff;
-#endif
+#endif /* ! NO_STRUCT_TM_GMTOFF */
if ( flags == O_RDONLY ) { /* input */
if ( strcmp( binfile, STDIN ) == 0 ) {
}
#if DEBUG
fprintf( stderr, "opened %s for read\n", binfile );
-#endif
+#endif /* DEBUG */
if ((( rc = test_header() ) > 0 ) &&
( bin_header_read( fh, rc ) == 0 )) {
return( 0 );
#if DEBUG
fprintf( stderr, "sizeof bin.path\t\t\t%d\n", sizeof( bin.path ));
fprintf( stderr, "maxlen \t\t\t\t%d\n", maxlen );
-#endif
+#endif /* DEBUG */
strncpy( bin.path, fh->name, maxlen );
strncpy( bin.path, mtoupath( bin.path ), maxlen );
strncat( bin.path, ".bin", maxlen - strlen( bin.path ));
#if DEBUG
fprintf( stderr, "opened %s for write\n",
(options & OPTION_STDOUT) ? "(stdout)" : bin.path );
-#endif
+#endif /* DEBUG */
}
if ( bin_header_write( fh ) != 0 ) {
* Otherwise, a value of -1 is returned.
*/
-bin_close( keepflag )
- int keepflag;
+int bin_close(int keepflag)
{
#if DEBUG
fprintf( stderr, "entering bin_close\n" );
-#endif
+#endif /* DEBUG */
if ( keepflag == KEEP ) {
return( close( bin.filed ));
} else if ( keepflag == TRASH ) {
* return zero and no more than that.
*/
-bin_read( fork, buffer, length )
- int fork;
- char *buffer;
- int length;
+ssize_t bin_read( int fork, char *buffer, size_t length)
{
char *buf_ptr;
- int readlen;
- int cc = 1;
+ size_t readlen;
+ ssize_t cc = 1;
off_t pos;
#if DEBUG >= 3
fprintf( stderr, "bin_read: fork is %s\n", forkname[ fork ] );
fprintf( stderr, "bin_read: remaining length is %d\n", bin.forklen[fork] );
-#endif
+#endif /* DEBUG >= 3 */
- if ( bin.forklen[ fork ] < 0 ) {
- fprintf( stderr, "This should never happen, dude!\n" );
- return( bin.forklen[ fork ] );
+ if (bin.forklen[fork] > 0x7FFFFFFF) {
+ fprintf(stderr, "This should never happen, dude! fork length == %u\n", bin.forklen[fork]);
+ return -1;
}
if ( bin.forklen[ fork ] == 0 ) {
pos = lseek( bin.filed, 0, SEEK_CUR );
#if DEBUG
fprintf( stderr, "current position is %ld\n", pos );
-#endif
- if (pos = pos % HEADBUFSIZ) {
+#endif /* DEBUG */
+ pos %= HEADBUFSIZ;
+ if (pos != 0) {
pos = lseek( bin.filed, HEADBUFSIZ - pos, SEEK_CUR );
}
#if DEBUG
fprintf( stderr, "current position is %ld\n", pos );
-#endif
+#endif /* DEBUG */
}
return( 0 );
}
#if DEBUG >= 3
fprintf( stderr, "bin_read: readlen is %d\n", readlen );
fprintf( stderr, "bin_read: cc is %d\n", cc );
-#endif
+#endif /* DEBUG >= 3 */
buf_ptr = buffer;
while (( readlen > 0 ) && ( cc > 0 )) {
if (( cc = read( bin.filed, buf_ptr, readlen )) > 0 ) {
#if DEBUG >= 3
fprintf( stderr, "bin_read: cc is %d\n", cc );
-#endif
+#endif /* DEBUG >= 3 */
readlen -= cc;
buf_ptr += cc;
}
#if DEBUG >= 3
fprintf( stderr, "bin_read: chars read is %d\n", cc );
-#endif
+#endif /* DEBUG >= 3 */
return( cc );
}
* bin_write
*/
-bin_write( fork, buffer, length )
- int fork;
- char *buffer;
- int length;
+ssize_t bin_write(int fork, char *buffer, size_t length)
{
char *buf_ptr;
- int writelen;
- int cc = 0;
+ ssize_t writelen;
+ ssize_t cc = 0;
off_t pos;
- u_char padchar = 0;
+ u_char padchar = 0x7f;
+ /* Not sure why, but it seems this must be 0x7f to match
+ other converters, not 0. (RLB) */
#if DEBUG >= 3
fprintf( stderr, "bin_write: fork is %s\n", forkname[ fork ] );
fprintf( stderr, "bin_write: remaining length is %d\n", bin.forklen[fork] );
-#endif
+#endif /* DEBUG >= 3 */
if (( fork == RESOURCE ) && ( bin.forklen[ DATA ] != 0 )) {
fprintf( stderr, "Forklength error.\n" );
#if DEBUG >= 3
fprintf( stderr, "bin_write: write length is %d\n", writelen );
-#endif
+#endif /* DEBUG >= 3 */
while (( writelen > 0 ) && ( cc >= 0 )) {
cc = write( bin.filed, buf_ptr, writelen );
perror( "Couldn't write to macbinary file:" );
return( cc );
}
- bin.forklen[ fork ] -= length;
- if ( bin.forklen[ fork ] < 0 ) {
- fprintf( stderr, "This should never happen, dude!\n" );
- return( bin.forklen[ fork ] );
- }
+ bin.forklen[fork] -= length;
/*
* add the padding at end of data and resource forks
pos = lseek( bin.filed, 0, SEEK_CUR );
#if DEBUG
fprintf( stderr, "current position is %ld\n", pos );
-#endif
- if (pos = pos % HEADBUFSIZ) { /* pad only if we need to */
+#endif /* DEBUG */
+ pos %= HEADBUFSIZ;
+ if (pos != 0) { /* pad only if we need to */
pos = lseek( bin.filed, HEADBUFSIZ - pos - 1, SEEK_CUR );
if ( write( bin.filed, &padchar, 1 ) != 1 ) {
perror( "Couldn't write to macbinary file:" );
}
#if DEBUG
fprintf( stderr, "current position is %ld\n", pos );
-#endif
+#endif /* DEBUG */
}
#if DEBUG
fprintf( stderr, "\n" );
-#endif
+#endif /* DEBUG */
return( length );
}
* of the bytes of the other two forks can be read, as well.
*/
-bin_header_read( fh, revision )
- struct FHeader *fh;
- int revision;
+int bin_header_read(struct FHeader *fh, int revision)
{
u_short mask;
fh->mod_date = AD_DATE_FROM_UNIX(fh->mod_date);
fh->backup_date = AD_DATE_START;
memcpy( &fh->finder_info, head_buf + 65, 8 );
+
+#ifndef MACBINARY_PLAY_NICE_WITH_OTHERS /* (RLB) */
memcpy( &fh->finder_info.fdFlags, head_buf + 73, 1 );
fh->finder_info.fdFlags &= mask;
+#else /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
+ memcpy( &fh->finder_info.fdFlags, head_buf + 73, 2 );
+#endif /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
+
memcpy(&fh->finder_info.fdLocation, head_buf + 75, 4 );
memcpy(&fh->finder_info.fdFldr, head_buf + 79, 2 );
memcpy(&fh->forklen[ DATA ], head_buf + 83, 4 );
#if DEBUG >= 5
{
short flags;
+ long flags_long;
fprintf( stderr, "Values read by bin_header_read\n" );
fprintf( stderr, "name length\t\t%d\n", head_buf[ 1 ] );
memcpy( &flags, &fh->finder_info.fdFlags, sizeof( flags ));
flags = ntohs( flags );
fprintf( stderr, "flags\t\t\t%x\n", flags );
+
+ /* Show fdLocation too (RLB) */
+ memcpy( &flags_long, &fh->finder_info.fdLocation,
+ sizeof( flags_long ));
+ flags_long = ntohl( flags_long );
+ fprintf( stderr, "location flags\t\t%lx\n", flags_long );
+
fprintf( stderr, "data fork length\t%ld\n", bin.forklen[DATA] );
fprintf( stderr, "resource fork length\t%ld\n", bin.forklen[RESOURCE] );
fprintf( stderr, "\n" );
}
-#endif
+#endif /* DEBUG >= 5 */
return( 0 );
}
* bin_header_write and bin_header_read are opposites.
*/
-bin_header_write( fh )
- struct FHeader *fh;
+int bin_header_write(struct FHeader *fh)
{
char *write_ptr;
u_int32_t t;
head_buf[ 1 ] = (u_char)strlen( fh->name );
memcpy( head_buf + 2, fh->name, head_buf[ 1 ] );
memcpy( head_buf + 65, &fh->finder_info, 8 );
- memcpy( head_buf + 73, &fh->finder_info.fdFlags, 1);
+
+#ifndef MACBINARY_PLAY_NICE_WITH_OTHERS /* (RLB) */
+ memcpy( head_buf + 73, &fh->finder_info.fdFlags, 1 );
+#else /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
+ memcpy( head_buf + 73, &fh->finder_info.fdFlags, 2 );
+#endif /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
+
memcpy( head_buf + 75, &fh->finder_info.fdLocation, 4 );
memcpy( head_buf + 79, &fh->finder_info.fdFldr, 2 );
memcpy( head_buf + 83, &fh->forklen[ DATA ], 4 );
#if DEBUG >= 5
{
+ short flags;
+ long flags_long;
+
fprintf( stderr, "Values written by bin_header_write\n" );
fprintf( stderr, "name length\t\t%d\n", head_buf[ 1 ] );
fprintf( stderr, "file name\t\t%s\n", (char *)&head_buf[ 2 ] );
fprintf( stderr, "type\t\t\t%.4s\n", (char *)&head_buf[ 65 ] );
fprintf( stderr, "creator\t\t\t%.4s\n", (char *)&head_buf[ 69 ] );
+
+ memcpy( &flags, &fh->finder_info.fdFlags, sizeof( flags ));
+ flags = ntohs( flags );
+ fprintf( stderr, "flags\t\t\t%x\n", flags );
+
+ /* Show fdLocation too (RLB) */
+ memcpy( &flags_long, &fh->finder_info.fdLocation,
+ sizeof( flags_long ));
+ flags_long = ntohl( flags_long );
+ fprintf( stderr, "location flags\t\t%ldx\n", flags_long );
+
fprintf( stderr, "data fork length\t%ld\n", bin.forklen[DATA] );
fprintf( stderr, "resource fork length\t%ld\n", bin.forklen[RESOURCE] );
fprintf( stderr, "\n" );
}
-#endif
+#endif /* DEBUG >= 5 */
write_ptr = (char *)head_buf;
wc = sizeof( head_buf );
* so, the check for byte 74 isn't very useful.
*/
-test_header()
+int test_header(void)
{
const char zeros[25] = "";
- u_int32_t cc;
+ ssize_t cc;
u_short header_crc;
u_char namelen;
#if DEBUG
fprintf( stderr, "entering test_header\n" );
-#endif
+#endif /* DEBUG */
cc = read( bin.filed, (char *)head_buf, sizeof( head_buf ));
if ( cc < sizeof( head_buf )) {
#if DEBUG
fprintf( stderr, "was able to read HEADBUFSIZ bytes\n" );
-#endif
+#endif /* DEBUG */
/* check for macbinary III header */
if (memcmp(head_buf + 102, "mBIN", 4) == 0)
if (( head_buf[ 0 ] == 0 ) || ( head_buf[ 74 ] == 0 )) {
#if DEBUG
fprintf( stderr, "byte 0 and 74 are both zero\n" );
-#endif
+#endif /* DEBUG */
bin.headercrc = updcrc( (u_short) 0, head_buf, 124 );
memcpy(&header_crc, head_buf + 124, sizeof( header_crc ));
header_crc = ntohs( header_crc );
#if DEBUG
fprintf( stderr, "header crc didn't pan out\n" );
-#endif
+#endif /* DEBUG */
}
/* now see if we have a macbinary file. */
memcpy( &namelen, head_buf + 1, sizeof( namelen ));
#if DEBUG
fprintf( stderr, "name length is %d\n", namelen );
-#endif
+#endif /* DEBUG */
if (( namelen < 1 ) || ( namelen > 63 )) {
return( -1 );
}
return -1;
/* macbinary forks aren't larger than 0x7FFFFF */
+ /* we allow forks to be larger, breaking the specs */
memcpy(&cc, head_buf + 83, sizeof(cc));
cc = ntohl(cc);
- if (cc > 0x7FFFFF)
+ if (cc > 0x7FFFFFFF)
return -1;
memcpy(&cc, head_buf + 87, sizeof(cc));
cc = ntohl(cc);
- if (cc > 0x7FFFFF)
+ if (cc > 0x7FFFFFFF)
return -1;
#if DEBUG
fprintf( stderr, "byte 82 is zero and name length is cool\n" );
-#endif
+#endif /* DEBUG */
return( 1 );
}