]> arthur.barton.de Git - netatalk.git/blobdiff - bin/megatron/nad.c
megatron, fix errors introduced in Sun Feb 6 10:16:00 2005 commit, 'replace a wrong...
[netatalk.git] / bin / megatron / nad.c
index 8571032cf2cec8ec8e3d0475523cd336c2063f70..92be35413fc8ed3c17a91ef2dc120e42ea5e55bc 100644 (file)
@@ -1,6 +1,10 @@
+/*
+ * $Id: nad.c,v 1.18 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/param.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
-#include <syslog.h>
 #include <dirent.h>
+#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
+#endif /* HAVE_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)) &&
@@ -79,32 +84,352 @@ char *utompath( upath )
        } 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;
@@ -114,11 +439,14 @@ nad_open( path, openflags, fh, options )
  * 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 ) {
@@ -133,7 +461,7 @@ nad_open( path, openflags, fh, options )
 #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 ] );
@@ -142,15 +470,16 @@ nad_open( path, openflags, fh, options )
        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 );
@@ -165,20 +494,29 @@ nad_open( path, openflags, fh, options )
     }
 }
 
-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" );
@@ -196,7 +534,7 @@ nad_header_read( fh )
     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 ));
@@ -216,7 +554,7 @@ nad_header_read( fh )
     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,
@@ -259,7 +597,7 @@ nad_header_read( fh )
        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;
 
@@ -267,8 +605,7 @@ nad_header_read( fh )
 
 }
 
-nad_header_write( fh )
-    struct FHeader     *fh;
+int nad_header_write(struct FHeader *fh)
 {
     u_int32_t          temptime;
 
@@ -293,7 +630,7 @@ nad_header_write( fh )
            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);
@@ -307,7 +644,7 @@ nad_header_write( fh )
     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, 
@@ -329,7 +666,7 @@ nad_header_write( fh )
 #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 );
@@ -339,31 +676,28 @@ nad_header_write( fh )
                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 )  {
@@ -374,27 +708,24 @@ nad_read( fork, forkbuf, bufc )
 
 #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;
@@ -414,12 +745,11 @@ nad_write( fork, forkbuf, bufc )
     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 );
        }
@@ -436,4 +766,5 @@ int                 status;
        }
        return( 0 );
     } else return( -1 );
+    return( 0 );
 }