+/*
+ * $Id: nad.c,v 1.18 2010-01-27 21:27:53 didg Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
-#include <syslog.h>
#include <dirent.h>
#include <fcntl.h>
#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/volinfo.h>
#include <netatalk/endian.h>
#include "megatron.h"
+#include "nad.h"
-#define DEBUG 0
-
+static struct volinfo vol;
static char hexdig[] = "0123456789abcdef";
-char *mtoupath( mpath )
- char *mpath;
+static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
+static char *mtoupathcap(char *mpath)
{
- static char upath[ MAXNAMLEN + 1];
- char *m, *u;
+ char *m, *u, *umax;
int i = 0;
m = mpath;
- u = upath;
- while ( *m != '\0' ) {
+ u = mtou_buf;
+ umax = u + sizeof(mtou_buf) - 4;
+ while ( *m != '\0' && u < umax) {
#if AD_VERSION == AD_VERSION1
if ( !isascii( *m ) || *m == '/' || ( i == 0 && *m == '.' )) {
-#else
+#else /* AD_VERSION == AD_VERSION1 */
if (!isprint(*m) || *m == '/' || ( i == 0 && (*m == '.' ))) {
-#endif
+#endif /* AD_VERSION == AD_VERSION1 */
*u++ = ':';
*u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
*u++ = hexdig[ *m & 0x0f ];
} else {
#ifdef DOWNCASE
*u++ = ( isupper( *m )) ? tolower( *m ) : *m;
-#else DOWNCASE
+#else /* DOWNCASE */
*u++ = *m;
-#endif DOWNCASE
+#endif /* DOWNCASE */
}
i++;
m++;
}
*u = '\0';
- return( upath );
+ return( mtou_buf );
}
#define hextoint( c ) ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
#define islxdigit(x) (!isupper(x)&&isxdigit(x))
-char *utompath( upath )
- char *upath;
+static char *utompathcap( char *upath)
{
- static char mpath[ MAXNAMLEN + 1];
char *m, *u;
int h;
- m = mpath;
+ m = utom_buf;
u = upath;
while ( *u != '\0' ) {
if (*u == ':' && *(u + 1) != '\0' && islxdigit(*(u+1)) &&
} else {
#ifdef DOWNCASE
*m = diatolower(*u);
-#else DOWNCASE
+#else /* DOWNCASE */
*m = *u;
-#endif DOWNCASE
+#endif /* DOWNCASE */
}
u++;
m++;
}
*m = '\0';
- return( mpath );
+ return( utom_buf );
+}
+
+static void euc2sjis( int *p1, int *p2) /* agrees w/ Samba on valid codes */
+{
+ int row_offset, cell_offset;
+ unsigned char c1, c2;
+
+ /* first convert EUC to ISO-2022 */
+ c1 = *p1 & 0x7F;
+ c2 = *p2 & 0x7F;
+
+ /* now convert ISO-2022 to Shift-JIS */
+ row_offset = c1 < 95 ? 112 : 176;
+ cell_offset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;
+
+ *p1 = ((c1 + 1) >> 1) + row_offset;
+ *p2 = c2 + cell_offset;
+}
+
+static void sjis2euc( int *p1, int *p2) /* agrees w/ Samba on valid codes */
+{
+ int row_offset, cell_offset, adjust;
+ unsigned char c1, c2;
+
+ c1 = *p1;
+ c2 = *p2;
+
+ /* first convert Shift-JIS to ISO-2022 */
+ adjust = c2 < 159;
+ row_offset = c1 < 160 ? 112 : 176;
+ cell_offset = adjust ? (c2 > 127 ? 32 : 31) : 126;
+
+ c1 = ((c1 - row_offset) << 1) - adjust;
+ c2 -= cell_offset;
+
+ /* now convert ISO-2022 to EUC */
+ *p1 = c1 | 0x80;
+ *p2 = c2 | 0x80;
+}
+
+static char *mtoupatheuc( char *from)
+{
+ unsigned char *in, *out, *maxout;
+ int p, p2, i = 0;
+
+ in = (unsigned char *) from;
+ out = (unsigned char *) mtou_buf;
+
+ if( *in ) {
+ maxout = out + sizeof( mtou_buf) - 3;
+
+ while( out < maxout ) {
+ p = *in++;
+
+ if( ((0x81 <= p) && (p <= 0x9F))
+ || ((0xE0 <= p) && (p <= 0xEF)) ) {
+ /* JIS X 0208 */
+ p2 = *in++;
+ if( ((0x40 <= p2) && (p2 <= 0x7E))
+ || ((0x80 <= p2) && (p2 <= 0xFC)) )
+ sjis2euc( &p, &p2);
+ *out++ = p;
+ p = p2;
+
+ } else if( (0xA1 <= p) && (p <= 0xDF) ) {
+ *out++ = 0x8E; /* halfwidth katakana */
+ } else if( p < 0x80 ) {
+#ifdef DOWNCASE
+ p = ( isupper( p )) ? tolower( p ) : p;
+#endif /* DOWNCASE */
+ }
+ if( ( p == '/') || ( i == 0 && p == '.' ) ) {
+ *out++ = ':';
+ *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
+ p = hexdig[ p & 0x0f ];
+ }
+ i++;
+ *out++ = p;
+ if( p )
+ continue;
+ break;
+ }
+ } else {
+ *out++ = '.';
+ *out = 0;
+ }
+
+ return mtou_buf;
+}
+
+static char *utompatheuc( char *from)
+{
+ unsigned char *in, *out, *maxout;
+ int p, p2;
+
+ in = (unsigned char *) from;
+ out = (unsigned char *) utom_buf;
+ maxout = out + sizeof( utom_buf) - 3;
+
+ while( out < maxout ) {
+ p = *in++;
+
+ if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
+ p2 = *in++;
+ if( (0xA1 <= p2) && (p2 <= 0xFE) )
+ euc2sjis( &p, &p2);
+ *out++ = p;
+ p = p2;
+ } else if( p == 0x8E ) { /* halfwidth katakana */
+ p = *in++;
+ } else if( p < 0x80 ) {
+#ifdef DOWNCASE
+ p = ( isupper( p )) ? tolower( p ) : p;
+#endif /* DOWNCASE */
+ }
+ if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
+ *(in+1) != '\0' && islxdigit( *(in+1))) {
+ p = hextoint( *in ) << 4;
+ in++;
+ p |= hextoint( *in );
+ in++;
+ }
+ *out++ = p;
+ if( p )
+ continue;
+ break;
+ }
+
+ return utom_buf;
+}
+
+static char *mtoupathsjis( char *from)
+{
+ unsigned char *in, *out, *maxout;
+ int p, p2, i = 0;
+
+ in = (unsigned char *) from;
+ out = (unsigned char *) mtou_buf;
+
+ if( *in ) {
+ maxout = out + sizeof( mtou_buf) - 3;
+
+ while( out < maxout ) {
+ p = *in++;
+
+ if( ((0x81 <= p) && (p <= 0x9F))
+ || ((0xE0 <= p) && (p <= 0xEF)) ) {
+ /* JIS X 0208 */
+ p2 = *in++;
+ *out++ = p;
+ p = p2;
+
+ } else if( (0xA1 <= p) && (p <= 0xDF) ) {
+ ; /* halfwidth katakana */
+ } else if(p < 0x80 ) {
+#ifdef DOWNCASE
+ p = ( isupper( p )) ? tolower( p ) : p;
+#endif /* DOWNCASE */
+ }
+ if( ( p == '/') || ( i == 0 && p == '.' ) ) {
+ *out++ = ':';
+ *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
+ p = hexdig[ p & 0x0f ];
+ }
+ i++;
+ *out++ = p;
+ if( p )
+ continue;
+ break;
+ }
+ } else {
+ *out++ = '.';
+ *out = 0;
+ }
+
+ return mtou_buf;
+}
+
+static char *utompathsjis( char *from)
+{
+ unsigned char *in, *out, *maxout;
+ int p, p2;
+
+ in = (unsigned char *) from;
+ out = (unsigned char *) utom_buf;
+ maxout = out + sizeof( utom_buf) - 3;
+
+ while( out < maxout ) {
+ p = *in++;
+
+ if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
+ p2 = *in++;
+ *out++ = p;
+ p = p2;
+ } else if( p == 0x8E ) { /* do nothing */
+ ;
+ } else if( p < 0x80 ) {
+#ifdef DOWNCASE
+ p = ( isupper( p )) ? tolower( p ) : p;
+#endif /* DOWNCASE */
+ }
+ if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
+ *(in+1) != '\0' && islxdigit( *(in+1))) {
+ p = hextoint( *in ) << 4;
+ in++;
+ p |= hextoint( *in );
+ in++;
+ }
+ *out++ = p;
+ if( p )
+ continue;
+ break;
+ }
+
+ return utom_buf;
+ }
+
+static char *utompathiconv(char *upath)
+{
+ char *m, *u;
+ u_int16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+ size_t outlen;
+ static char mpath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
+
+ m = mpath;
+ outlen = strlen(upath);
+
+#if 0
+ if (vol->v_casefold & AFPVOL_UTOMUPPER)
+ flags |= CONV_TOUPPER;
+ else if (vol->v_casefold & AFPVOL_UTOMLOWER)
+ flags |= CONV_TOLOWER;
+#endif
+
+ u = upath;
+
+ /* convert charsets */
+ if ((size_t)-1 == ( outlen = convert_charset ( vol.v_volcharset, vol.v_maccharset, vol.v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) {
+ fprintf( stderr, "Conversion from %s to %s for %s failed.", vol.v_volcodepage, vol.v_maccodepage, u);
+ goto utompath_error;
+ }
+
+ if (flags & CONV_REQMANGLE)
+ goto utompath_error;
+
+ return(m);
+
+utompath_error:
+ return(utompathcap( upath ));
+}
+
+static char *mtoupathiconv(char *mpath)
+{
+ char *m, *u;
+ size_t inplen;
+ size_t outlen;
+ u_int16_t flags = 0;
+ static char upath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
+
+ if ( *mpath == '\0' ) {
+ return( "." );
+ }
+
+ /* set conversion flags */
+ if (!(vol.v_flags & AFPVOL_NOHEX))
+ flags |= CONV_ESCAPEHEX;
+ if (!(vol.v_flags & AFPVOL_USEDOTS))
+ flags |= CONV_ESCAPEDOTS;
+
+#if 0
+ if ((vol->v_casefold & AFPVOL_MTOUUPPER))
+ flags |= CONV_TOUPPER;
+ else if ((vol->v_casefold & AFPVOL_MTOULOWER))
+ flags |= CONV_TOLOWER;
+#endif
+
+ m = mpath;
+ u = upath;
+
+ inplen = strlen(m);
+ outlen = MAXPATHLEN;
+
+ if ((size_t)-1 == (outlen = convert_charset ( vol.v_maccharset, vol.v_volcharset, vol.v_maccharset, m, inplen, u, outlen, &flags)) ) {
+ fprintf (stderr, "conversion from %s to %s for %s failed.", vol.v_maccodepage, vol.v_volcodepage, mpath);
+ return(mtoupathcap( upath ));
+ }
+
+ return( upath );
}
+
+
+char * (*_mtoupath) ( char *mpath) = mtoupathcap;
+char * (*_utompath) ( char *upath) = utompathcap;
+
+/* choose translators for optional character set */
+void select_charset( int options)
+{
+
+ if( options & OPTION_EUCJP ) {
+ _mtoupath = mtoupatheuc;
+ _utompath = utompatheuc;
+ } else if( options & OPTION_SJIS ) {
+ _mtoupath = mtoupathsjis;
+ _utompath = utompathsjis;
+ } else {
+ _mtoupath = mtoupathcap;
+ _utompath = utompathcap;
+ }
+}
+
+
#if HEXOUTPUT
int hexfork[ NUMFORKS ];
-#endif
+#endif /* HEXOUTPUT */
-struct nad_file_data {
+static struct nad_file_data {
char macname[ MAXPATHLEN + 1 ];
char adpath[ 2 ][ MAXPATHLEN + 1];
int offset[ NUMFORKS ];
struct adouble ad;
} nad;
-nad_open( path, openflags, fh, options )
- char *path;
- int openflags, options;
- struct FHeader *fh;
+static void initvol(char *path)
+{
+ if (!loadvolinfo(path, &vol)) {
+ vol_load_charsets(&vol);
+ ad_init(&nad.ad, vol.v_adouble, 0);
+ _mtoupath = mtoupathiconv;
+ _utompath = utompathiconv;
+ }
+ else
+ ad_init(&nad.ad, 0, 0);
+}
+
+
+int nad_open( char *path, int openflags, struct FHeader *fh, int options)
{
struct stat st;
int fork;
* is for write, then stat the current directory to get its mode.
* Open the file. Either fill or grab the adouble information.
*/
+ select_charset( options);
memset(&nad.ad, 0, sizeof(nad.ad));
+
if ( openflags == O_RDONLY ) {
+ initvol(path);
strcpy( nad.adpath[0], path );
strcpy( nad.adpath[1],
- ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
+ nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF ));
for ( fork = 0 ; fork < NUMFORKS ; fork++ ) {
if ( stat( nad.adpath[ fork ], &st ) < 0 ) {
if ( errno == ENOENT ) {
#if DEBUG
fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
-#endif
+#endif /* DEBUG */
if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
perror( nad.adpath[ 0 ] );
return( nad_header_read( fh ));
} else {
+ initvol (".");
strcpy( nad.macname, fh->name );
strcpy( nad.adpath[0], mtoupath( nad.macname ));
strcpy( nad.adpath[1],
- ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
+ nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF ));
#if DEBUG
fprintf(stderr, "%s\n", nad.macname);
fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
-#endif
+#endif /* DEBUG */
if ( stat( ".", &st ) < 0 ) {
perror( "stat of . failed" );
return( -1 );
}
}
-nad_header_read( fh )
- struct FHeader *fh;
+int nad_header_read(struct FHeader *fh)
{
u_int32_t temptime;
struct stat st;
+ char *p;
+#if 0
memcpy( nad.macname, ad_entry( &nad.ad, ADEID_NAME ),
ad_getentrylen( &nad.ad, ADEID_NAME ));
nad.macname[ ad_getentrylen( &nad.ad, ADEID_NAME ) ] = '\0';
strcpy( fh->name, nad.macname );
+#endif
/* just in case there's nothing in macname */
- if (*fh->name == '\0')
+ if (*fh->name == '\0') {
+ if ( NULL == (p = strrchr(nad.adpath[DATA], '/')) )
+ p = nad.adpath[DATA];
+ else p++;
+#if 0
strcpy(fh->name, utompath(nad.adpath[DATA]));
+#endif
+ strcpy(fh->name, utompath(p));
+ }
if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
perror( "stat of datafork failed" );
fprintf( stderr, "size of resource fork\t\t%d\n",
ntohl( fh->forklen[ RESOURCE ] ));
fprintf( stderr, "get info comment\t\t\"%s\"\n", fh->comment );
-#endif
+#endif /* DEBUG */
ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
memcpy( &fh->create_date, &temptime, sizeof( temptime ));
temptime = AD_DATE_TO_UNIX(temptime);
fprintf( stderr, "backup_date seconds\t\t%lu\n", temptime );
fprintf( stderr, "size of finder_info\t\t%d\n", sizeof( fh->finder_info ));
-#endif
+#endif /* DEBUG */
memcpy(&fh->finder_info.fdType,
ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
fprintf(stderr, "fh script\t\t\t%x\n", fh->finder_xinfo.fdScript);
fprintf(stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags);
}
-#endif
+#endif /* DEBUG */
nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
}
-nad_header_write( fh )
- struct FHeader *fh;
+int nad_header_write(struct FHeader *fh)
{
u_int32_t temptime;
ad_entry( &nad.ad, ADEID_NAME ));
fprintf( stderr, "ADEID_COMMENT\t\t\t%d\n",
ad_getentrylen( &nad.ad, ADEID_COMMENT ));
-#endif
+#endif /* DEBUG */
memcpy( &temptime, &fh->create_date, sizeof( temptime ));
ad_setdate(&nad.ad, AD_DATE_CREATE, temptime);
ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
temptime = AD_DATE_TO_UNIX(temptime);
fprintf(stderr, "FILEIOFF_MODIFY seconds\t\t%ld\n", temptime );
-#endif
+#endif /* DEBUG */
memset( ad_entry( &nad.ad, ADEID_FINDERI ), 0, ADEDLEN_FINDERI );
memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
#if DEBUG
{
short flags;
- memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
+ memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS),
sizeof( flags ));
fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
sizeof( fh->finder_info.fdCreator ),
ad_entry( &nad.ad, ADEID_FINDERI ));
}
-#endif
+#endif /* DEBUG */
#if HEXOUTPUT
hexfork[ DATA ] = open( "datafork", O_WRONLY|O_CREAT, 0622 );
hexfork[ RESOURCE ] = open( "resfork", O_WRONLY|O_CREAT, 0622 );
-#endif
+#endif /* HEXOUTPUT */
nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
- ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF );
+ ad_flush( &nad.ad );
return( 0 );
}
-int forkeid[] = { ADEID_DFORK, ADEID_RFORK };
+static int forkeid[] = { ADEID_DFORK, ADEID_RFORK };
-nad_read( fork, forkbuf, bufc )
- int fork;
- char *forkbuf;
- int bufc;
+ssize_t nad_read(int fork, char *forkbuf, size_t bufc)
{
- int cc = 0;
+ ssize_t cc = 0;
#if DEBUG
fprintf( stderr, "Entering nad_read\n" );
-#endif
+#endif /* DEBUG */
if (( cc = ad_read( &nad.ad, forkeid[ fork ], nad.offset[ fork ],
forkbuf, bufc)) < 0 ) {
#if DEBUG
fprintf( stderr, "Exiting nad_read\n" );
-#endif
+#endif /* DEBUG */
return( cc );
}
-nad_write( fork, forkbuf, bufc )
- int fork;
- char *forkbuf;
- int bufc;
+ssize_t nad_write(int fork, char *forkbuf, size_t bufc)
{
char *buf_ptr;
- int writelen;
- int cc = 0;
+ size_t writelen;
+ ssize_t cc = 0;
#if DEBUG
fprintf( stderr, "Entering nad_write\n" );
-#endif
+#endif /* DEBUG */
#if HEXOUTPUT
write( hexfork[ fork ], forkbuf, bufc );
-#endif
+#endif /* HEXOUTPUT */
writelen = bufc;
buf_ptr = forkbuf;
return( bufc );
}
-nad_close( status )
-int status;
+int nad_close(int status)
{
int rv;
if ( status == KEEP ) {
- if (( rv = ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
+ if (( rv = ad_flush( &nad.ad )) < 0 ) {
fprintf( stderr, "nad_close rv for flush %d\n", rv );
return( rv );
}
}
return( 0 );
} else return( -1 );
+ return( 0 );
}