2 * $Id: nad.c,v 1.12 2005-04-28 20:49:20 bfernhomberg Exp $
7 #endif /* HAVE_CONFIG_H */
10 #include <sys/param.h>
21 #endif /* HAVE_FCNTL_H */
23 #include <atalk/adouble.h>
24 #include <atalk/util.h>
25 #include <atalk/volinfo.h>
26 #include <netatalk/endian.h>
31 static char hexdig[] = "0123456789abcdef";
33 static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
34 static char *mtoupathcap( mpath )
42 umax = u + sizeof(mtou_buf) - 4;
43 while ( *m != '\0' && u < umax) {
44 #if AD_VERSION == AD_VERSION1
45 if ( !isascii( *m ) || *m == '/' || ( i == 0 && *m == '.' )) {
46 #else /* AD_VERSION == AD_VERSION1 */
47 if (!isprint(*m) || *m == '/' || ( i == 0 && (*m == '.' ))) {
48 #endif /* AD_VERSION == AD_VERSION1 */
50 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
51 *u++ = hexdig[ *m & 0x0f ];
54 *u++ = ( isupper( *m )) ? tolower( *m ) : *m;
67 #define hextoint( c ) ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
68 #define islxdigit(x) (!isupper(x)&&isxdigit(x))
70 static char *utompathcap( upath )
78 while ( *u != '\0' ) {
79 if (*u == ':' && *(u + 1) != '\0' && islxdigit(*(u+1)) &&
80 *(u+2) != '\0' && islxdigit(*(u+2))) {
82 h = hextoint(*u) << 4;
100 static void euc2sjis( int *p1, int *p2) /* agrees w/ Samba on valid codes */
102 int row_offset, cell_offset;
103 unsigned char c1, c2;
105 /* first convert EUC to ISO-2022 */
109 /* now convert ISO-2022 to Shift-JIS */
110 row_offset = c1 < 95 ? 112 : 176;
111 cell_offset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;
113 *p1 = ((c1 + 1) >> 1) + row_offset;
114 *p2 = c2 + cell_offset;
117 static void sjis2euc( int *p1, int *p2) /* agrees w/ Samba on valid codes */
119 int row_offset, cell_offset, adjust;
120 unsigned char c1, c2;
125 /* first convert Shift-JIS to ISO-2022 */
127 row_offset = c1 < 160 ? 112 : 176;
128 cell_offset = adjust ? (c2 > 127 ? 32 : 31) : 126;
130 c1 = ((c1 - row_offset) << 1) - adjust;
133 /* now convert ISO-2022 to EUC */
138 static char *mtoupatheuc( char *from)
140 unsigned char *in, *out, *maxout;
143 in = (unsigned char *) from;
144 out = (unsigned char *) mtou_buf;
147 maxout = out + sizeof( mtou_buf) - 3;
149 while( out < maxout ) {
152 if( ((0x81 <= p) && (p <= 0x9F))
153 || ((0xE0 <= p) && (p <= 0xEF)) ) {
156 if( ((0x40 <= p2) && (p2 <= 0x7E))
157 || ((0x80 <= p2) && (p2 <= 0xFC)) )
162 } else if( (0xA1 <= p) && (p <= 0xDF) ) {
163 *out++ = 0x8E; /* halfwidth katakana */
164 } else if( p < 0x80 ) {
166 p = ( isupper( p )) ? tolower( p ) : p;
167 #endif /* DOWNCASE */
169 if( ( p == '/') || ( i == 0 && p == '.' ) ) {
171 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
172 p = hexdig[ p & 0x0f ];
188 static char *utompatheuc( char *from)
190 unsigned char *in, *out, *maxout;
193 in = (unsigned char *) from;
194 out = (unsigned char *) utom_buf;
195 maxout = out + sizeof( utom_buf) - 3;
197 while( out < maxout ) {
200 if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
202 if( (0xA1 <= p2) && (p2 <= 0xFE) )
206 } else if( p == 0x8E ) { /* halfwidth katakana */
208 } else if( p < 0x80 ) {
210 p = ( isupper( p )) ? tolower( p ) : p;
211 #endif /* DOWNCASE */
213 if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
214 *(in+1) != '\0' && islxdigit( *(in+1))) {
215 p = hextoint( *in ) << 4;
217 p |= hextoint( *in );
229 static char *mtoupathsjis( char *from)
231 unsigned char *in, *out, *maxout;
234 in = (unsigned char *) from;
235 out = (unsigned char *) mtou_buf;
238 maxout = out + sizeof( mtou_buf) - 3;
240 while( out < maxout ) {
243 if( ((0x81 <= p) && (p <= 0x9F))
244 || ((0xE0 <= p) && (p <= 0xEF)) ) {
250 } else if( (0xA1 <= p) && (p <= 0xDF) ) {
251 ; /* halfwidth katakana */
252 } else if(p < 0x80 ) {
254 p = ( isupper( p )) ? tolower( p ) : p;
255 #endif /* DOWNCASE */
257 if( ( p == '/') || ( i == 0 && p == '.' ) ) {
259 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
260 p = hexdig[ p & 0x0f ];
276 static char *utompathsjis( char *from)
278 unsigned char *in, *out, *maxout;
281 in = (unsigned char *) from;
282 out = (unsigned char *) utom_buf;
283 maxout = out + sizeof( utom_buf) - 3;
285 while( out < maxout ) {
288 if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
292 } else if( p == 0x8E ) { /* do nothing */
294 } else if( p < 0x80 ) {
296 p = ( isupper( p )) ? tolower( p ) : p;
297 #endif /* DOWNCASE */
299 if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
300 *(in+1) != '\0' && islxdigit( *(in+1))) {
301 p = hextoint( *in ) << 4;
303 p |= hextoint( *in );
315 static char *utompathiconv(char *upath)
318 u_int16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
320 static char mpath[MAXPATHLEN];
323 outlen = strlen(upath);
326 if (vol->v_casefold & AFPVOL_UTOMUPPER)
327 flags |= CONV_TOUPPER;
328 else if (vol->v_casefold & AFPVOL_UTOMLOWER)
329 flags |= CONV_TOLOWER;
334 /* convert charsets */
335 if ((size_t)-1 == ( outlen = convert_charset ( vol.v_volcharset, vol.v_maccharset, vol.v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) {
336 fprintf( stderr, "Conversion from %s to %s for %s failed.", vol.v_volcodepage, vol.v_maccodepage, u);
341 if (flags & CONV_REQMANGLE)
347 return(utompathcap( upath ));
350 char *mtoupathiconv(char *mpath)
356 static char upath[MAXPATHLEN];
358 if ( *mpath == '\0' ) {
362 /* set conversion flags */
363 if (!(vol.v_flags & AFPVOL_NOHEX))
364 flags |= CONV_ESCAPEHEX;
365 if (!(vol.v_flags & AFPVOL_USEDOTS))
366 flags |= CONV_ESCAPEDOTS;
369 if ((vol->v_casefold & AFPVOL_MTOUUPPER))
370 flags |= CONV_TOUPPER;
371 else if ((vol->v_casefold & AFPVOL_MTOULOWER))
372 flags |= CONV_TOLOWER;
381 if ((size_t)-1 == (outlen = convert_charset ( vol.v_maccharset, vol.v_volcharset, vol.v_maccharset, m, inplen, u, outlen, &flags)) ) {
382 fprintf (stderr, "conversion from %s to %s for %s failed.", vol.v_maccodepage, vol.v_volcodepage, mpath);
383 return(mtoupathcap( upath ));
392 char * (*_mtoupath) ( char *mpath) = mtoupathcap;
393 char * (*_utompath) ( char *upath) = utompathcap;
395 /* choose translators for optional character set */
396 void select_charset( int options)
399 if( options & OPTION_EUCJP ) {
400 _mtoupath = mtoupatheuc;
401 _utompath = utompatheuc;
402 } else if( options & OPTION_SJIS ) {
403 _mtoupath = mtoupathsjis;
404 _utompath = utompathsjis;
406 _mtoupath = mtoupathcap;
407 _utompath = utompathcap;
413 int hexfork[ NUMFORKS ];
414 #endif /* HEXOUTPUT */
416 struct nad_file_data {
417 char macname[ MAXPATHLEN + 1 ];
418 char adpath[ 2 ][ MAXPATHLEN + 1];
419 int offset[ NUMFORKS ];
423 static void initvol(char *path)
425 if (!loadvolinfo(path, &vol)) {
426 vol_load_charsets(&vol);
427 ad_init(&nad.ad, vol.v_adouble, 0);
428 _mtoupath = mtoupathiconv;
429 _utompath = utompathiconv;
432 ad_init(&nad.ad, 0, 0);
436 int nad_open( path, openflags, fh, options )
438 int openflags, options;
445 * Depending upon openflags, set up nad.adpath for the open. If it
446 * is for write, then stat the current directory to get its mode.
447 * Open the file. Either fill or grab the adouble information.
449 select_charset( options);
450 memset(&nad.ad, 0, sizeof(nad.ad));
452 if ( openflags == O_RDONLY ) {
454 strcpy( nad.adpath[0], path );
455 strcpy( nad.adpath[1],
456 nad.ad.ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
457 for ( fork = 0 ; fork < NUMFORKS ; fork++ ) {
458 if ( stat( nad.adpath[ fork ], &st ) < 0 ) {
459 if ( errno == ENOENT ) {
460 fprintf( stderr, "%s is not an adouble file.\n", path );
462 perror( "stat of adouble file failed" );
469 fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
470 fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
472 if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
473 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
474 perror( nad.adpath[ 0 ] );
477 return( nad_header_read( fh ));
481 strcpy( nad.macname, fh->name );
482 strcpy( nad.adpath[0], mtoupath( nad.macname ));
483 strcpy( nad.adpath[1],
484 nad.ad.ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
486 fprintf(stderr, "%s\n", nad.macname);
487 fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
488 fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
490 if ( stat( ".", &st ) < 0 ) {
491 perror( "stat of . failed" );
495 if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
496 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
497 perror( nad.adpath[ 0 ] );
500 return( nad_header_write( fh ));
504 int nad_header_read( fh )
512 memcpy( nad.macname, ad_entry( &nad.ad, ADEID_NAME ),
513 ad_getentrylen( &nad.ad, ADEID_NAME ));
514 nad.macname[ ad_getentrylen( &nad.ad, ADEID_NAME ) ] = '\0';
515 strcpy( fh->name, nad.macname );
518 /* just in case there's nothing in macname */
519 if (*fh->name == '\0') {
520 if ( NULL == (p = strrchr(nad.adpath[DATA], '/')) )
521 p = nad.adpath[DATA];
524 strcpy(fh->name, utompath(nad.adpath[DATA]));
526 strcpy(fh->name, utompath(p));
529 if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
530 perror( "stat of datafork failed" );
533 fh->forklen[ DATA ] = htonl( st.st_size );
534 fh->forklen[ RESOURCE ] = htonl( ad_getentrylen( &nad.ad, ADEID_RFORK ));
535 fh->comment[0] = '\0';
538 fprintf( stderr, "macname of file\t\t\t%.*s\n", strlen( fh->name ),
540 fprintf( stderr, "size of data fork\t\t%d\n",
541 ntohl( fh->forklen[ DATA ] ));
542 fprintf( stderr, "size of resource fork\t\t%d\n",
543 ntohl( fh->forklen[ RESOURCE ] ));
544 fprintf( stderr, "get info comment\t\t\"%s\"\n", fh->comment );
547 ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
548 memcpy( &fh->create_date, &temptime, sizeof( temptime ));
549 ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
550 memcpy( &fh->mod_date, &temptime, sizeof( temptime ));
551 ad_getdate(&nad.ad, AD_DATE_BACKUP, &temptime);
552 memcpy( &fh->backup_date, &temptime, sizeof( temptime ));
555 memcpy( &temptime, &fh->create_date, sizeof( temptime ));
556 temptime = AD_DATE_TO_UNIX(temptime);
557 fprintf( stderr, "create_date seconds\t\t%lu\n", temptime );
558 memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
559 temptime = AD_DATE_TO_UNIX(temptime);
560 fprintf( stderr, "mod_date seconds\t\t%lu\n", temptime );
561 memcpy( &temptime, &fh->backup_date, sizeof( temptime ));
562 temptime = AD_DATE_TO_UNIX(temptime);
563 fprintf( stderr, "backup_date seconds\t\t%lu\n", temptime );
564 fprintf( stderr, "size of finder_info\t\t%d\n", sizeof( fh->finder_info ));
567 memcpy(&fh->finder_info.fdType,
568 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
569 sizeof( fh->finder_info.fdType ));
570 memcpy(&fh->finder_info.fdCreator,
571 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
572 sizeof( fh->finder_info.fdCreator ));
573 memcpy(&fh->finder_info.fdFlags,
574 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
575 sizeof( fh->finder_info.fdFlags ));
576 memcpy(&fh->finder_info.fdLocation,
577 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
578 sizeof( fh->finder_info.fdLocation ));
579 memcpy(&fh->finder_info.fdFldr,
580 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
581 sizeof( fh->finder_info.fdFldr ));
582 memcpy(&fh->finder_xinfo.fdScript,
583 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
584 sizeof(fh->finder_xinfo.fdScript));
585 memcpy(&fh->finder_xinfo.fdXFlags,
586 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
587 sizeof(fh->finder_xinfo.fdXFlags));
592 fprintf( stderr, "finder_info.fdType\t\t%.*s\n",
593 sizeof( fh->finder_info.fdType ), &fh->finder_info.fdType );
594 fprintf( stderr, "finder_info.fdCreator\t\t%.*s\n",
595 sizeof( fh->finder_info.fdCreator ),
596 &fh->finder_info.fdCreator );
597 fprintf( stderr, "nad type and creator\t\t%.*s\n\n",
598 sizeof( fh->finder_info.fdType ) +
599 sizeof( fh->finder_info.fdCreator ),
600 ad_entry( &nad.ad, ADEID_FINDERI ));
601 memcpy(&flags, ad_entry( &nad.ad, ADEID_FINDERI ) +
602 FINDERIOFF_FLAGS, sizeof( flags ));
603 fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
604 fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
605 fprintf(stderr, "fh script\t\t\t%x\n", fh->finder_xinfo.fdScript);
606 fprintf(stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags);
610 nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
616 int nad_header_write( fh )
621 ad_setentrylen( &nad.ad, ADEID_NAME, strlen( nad.macname ));
622 memcpy( ad_entry( &nad.ad, ADEID_NAME ), nad.macname,
623 ad_getentrylen( &nad.ad, ADEID_NAME ));
624 ad_setentrylen( &nad.ad, ADEID_COMMENT, strlen( fh->comment ));
625 memcpy( ad_entry( &nad.ad, ADEID_COMMENT ), fh->comment,
626 ad_getentrylen( &nad.ad, ADEID_COMMENT ));
627 ad_setentrylen( &nad.ad, ADEID_RFORK, ntohl( fh->forklen[ RESOURCE ] ));
630 fprintf( stderr, "ad_getentrylen\n" );
631 fprintf( stderr, "ADEID_FINDERI\t\t\t%d\n",
632 ad_getentrylen( &nad.ad, ADEID_FINDERI ));
633 fprintf( stderr, "ADEID_RFORK\t\t\t%d\n",
634 ad_getentrylen( &nad.ad, ADEID_RFORK ));
635 fprintf( stderr, "ADEID_NAME\t\t\t%d\n",
636 ad_getentrylen( &nad.ad, ADEID_NAME ));
637 fprintf( stderr, "ad_entry of ADEID_NAME\t\t%.*s\n",
638 ad_getentrylen( &nad.ad, ADEID_NAME ),
639 ad_entry( &nad.ad, ADEID_NAME ));
640 fprintf( stderr, "ADEID_COMMENT\t\t\t%d\n",
641 ad_getentrylen( &nad.ad, ADEID_COMMENT ));
644 memcpy( &temptime, &fh->create_date, sizeof( temptime ));
645 ad_setdate(&nad.ad, AD_DATE_CREATE, temptime);
646 memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
647 ad_setdate(&nad.ad, AD_DATE_MODIFY, temptime);
650 ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
651 temptime = AD_DATE_TO_UNIX(temptime);
652 fprintf(stderr, "FILEIOFF_CREATE seconds\t\t%ld\n", temptime );
653 ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
654 temptime = AD_DATE_TO_UNIX(temptime);
655 fprintf(stderr, "FILEIOFF_MODIFY seconds\t\t%ld\n", temptime );
658 memset( ad_entry( &nad.ad, ADEID_FINDERI ), 0, ADEDLEN_FINDERI );
659 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
660 &fh->finder_info.fdType, sizeof( fh->finder_info.fdType ));
661 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
662 &fh->finder_info.fdCreator, sizeof( fh->finder_info.fdCreator ));
663 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
664 &fh->finder_info.fdFlags, sizeof( fh->finder_info.fdFlags ));
665 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
666 &fh->finder_info.fdLocation,sizeof( fh->finder_info.fdLocation ));
667 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
668 &fh->finder_info.fdFldr, sizeof( fh->finder_info.fdFldr ));
669 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
670 &fh->finder_xinfo.fdScript, sizeof( fh->finder_xinfo.fdScript ));
671 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
672 &fh->finder_xinfo.fdXFlags, sizeof( fh->finder_xinfo.fdXFlags));
678 memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS),
680 fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
681 fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
682 fprintf( stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags );
683 fprintf( stderr, "type and creator\t\t%.*s\n\n",
684 sizeof( fh->finder_info.fdType ) +
685 sizeof( fh->finder_info.fdCreator ),
686 ad_entry( &nad.ad, ADEID_FINDERI ));
691 hexfork[ DATA ] = open( "datafork", O_WRONLY|O_CREAT, 0622 );
692 hexfork[ RESOURCE ] = open( "resfork", O_WRONLY|O_CREAT, 0622 );
693 #endif /* HEXOUTPUT */
695 nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
696 ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF );
701 int forkeid[] = { ADEID_DFORK, ADEID_RFORK };
703 int nad_read( fork, forkbuf, bufc )
711 fprintf( stderr, "Entering nad_read\n" );
714 if (( cc = ad_read( &nad.ad, forkeid[ fork ], nad.offset[ fork ],
715 forkbuf, bufc)) < 0 ) {
716 perror( "Reading the appledouble file:" );
719 nad.offset[ fork ] += cc;
722 fprintf( stderr, "Exiting nad_read\n" );
728 int nad_write( fork, forkbuf, bufc )
738 fprintf( stderr, "Entering nad_write\n" );
742 write( hexfork[ fork ], forkbuf, bufc );
743 #endif /* HEXOUTPUT */
748 while (( writelen > 0 ) && ( cc >= 0 )) {
749 cc = ad_write( &nad.ad, forkeid[ fork ], nad.offset[ fork ],
750 0, buf_ptr, writelen);
751 nad.offset[ fork ] += cc;
756 perror( "Writing the appledouble file:" );
763 int nad_close( status )
767 if ( status == KEEP ) {
768 if (( rv = ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
769 fprintf( stderr, "nad_close rv for flush %d\n", rv );
772 if (( rv = ad_close( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
773 fprintf( stderr, "nad_close rv for close %d\n", rv );
776 } else if ( status == TRASH ) {
777 if ( unlink( nad.adpath[ 0 ] ) < 0 ) {
778 perror ( nad.adpath[ 0 ] );
780 if ( unlink( nad.adpath[ 1 ] ) < 0 ) {
781 perror ( nad.adpath[ 1 ] );