2 * $Id: nad.c,v 1.18 2010-01-27 21:27:53 didg Exp $
7 #endif /* HAVE_CONFIG_H */
10 #include <sys/param.h>
21 #include <atalk/adouble.h>
22 #include <atalk/util.h>
23 #include <atalk/volinfo.h>
24 #include <netatalk/endian.h>
28 static struct volinfo vol;
29 static char hexdig[] = "0123456789abcdef";
31 static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
32 static char *mtoupathcap(char *mpath)
39 umax = u + sizeof(mtou_buf) - 4;
40 while ( *m != '\0' && u < umax) {
41 #if AD_VERSION == AD_VERSION1
42 if ( !isascii( *m ) || *m == '/' || ( i == 0 && *m == '.' )) {
43 #else /* AD_VERSION == AD_VERSION1 */
44 if (!isprint(*m) || *m == '/' || ( i == 0 && (*m == '.' ))) {
45 #endif /* AD_VERSION == AD_VERSION1 */
47 *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
48 *u++ = hexdig[ *m & 0x0f ];
51 *u++ = ( isupper( *m )) ? tolower( *m ) : *m;
64 #define hextoint( c ) ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
65 #define islxdigit(x) (!isupper(x)&&isxdigit(x))
67 static char *utompathcap( char *upath)
74 while ( *u != '\0' ) {
75 if (*u == ':' && *(u + 1) != '\0' && islxdigit(*(u+1)) &&
76 *(u+2) != '\0' && islxdigit(*(u+2))) {
78 h = hextoint(*u) << 4;
96 static void euc2sjis( int *p1, int *p2) /* agrees w/ Samba on valid codes */
98 int row_offset, cell_offset;
101 /* first convert EUC to ISO-2022 */
105 /* now convert ISO-2022 to Shift-JIS */
106 row_offset = c1 < 95 ? 112 : 176;
107 cell_offset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;
109 *p1 = ((c1 + 1) >> 1) + row_offset;
110 *p2 = c2 + cell_offset;
113 static void sjis2euc( int *p1, int *p2) /* agrees w/ Samba on valid codes */
115 int row_offset, cell_offset, adjust;
116 unsigned char c1, c2;
121 /* first convert Shift-JIS to ISO-2022 */
123 row_offset = c1 < 160 ? 112 : 176;
124 cell_offset = adjust ? (c2 > 127 ? 32 : 31) : 126;
126 c1 = ((c1 - row_offset) << 1) - adjust;
129 /* now convert ISO-2022 to EUC */
134 static char *mtoupatheuc( char *from)
136 unsigned char *in, *out, *maxout;
139 in = (unsigned char *) from;
140 out = (unsigned char *) mtou_buf;
143 maxout = out + sizeof( mtou_buf) - 3;
145 while( out < maxout ) {
148 if( ((0x81 <= p) && (p <= 0x9F))
149 || ((0xE0 <= p) && (p <= 0xEF)) ) {
152 if( ((0x40 <= p2) && (p2 <= 0x7E))
153 || ((0x80 <= p2) && (p2 <= 0xFC)) )
158 } else if( (0xA1 <= p) && (p <= 0xDF) ) {
159 *out++ = 0x8E; /* halfwidth katakana */
160 } else if( p < 0x80 ) {
162 p = ( isupper( p )) ? tolower( p ) : p;
163 #endif /* DOWNCASE */
165 if( ( p == '/') || ( i == 0 && p == '.' ) ) {
167 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
168 p = hexdig[ p & 0x0f ];
184 static char *utompatheuc( char *from)
186 unsigned char *in, *out, *maxout;
189 in = (unsigned char *) from;
190 out = (unsigned char *) utom_buf;
191 maxout = out + sizeof( utom_buf) - 3;
193 while( out < maxout ) {
196 if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
198 if( (0xA1 <= p2) && (p2 <= 0xFE) )
202 } else if( p == 0x8E ) { /* halfwidth katakana */
204 } else if( p < 0x80 ) {
206 p = ( isupper( p )) ? tolower( p ) : p;
207 #endif /* DOWNCASE */
209 if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
210 *(in+1) != '\0' && islxdigit( *(in+1))) {
211 p = hextoint( *in ) << 4;
213 p |= hextoint( *in );
225 static char *mtoupathsjis( char *from)
227 unsigned char *in, *out, *maxout;
230 in = (unsigned char *) from;
231 out = (unsigned char *) mtou_buf;
234 maxout = out + sizeof( mtou_buf) - 3;
236 while( out < maxout ) {
239 if( ((0x81 <= p) && (p <= 0x9F))
240 || ((0xE0 <= p) && (p <= 0xEF)) ) {
246 } else if( (0xA1 <= p) && (p <= 0xDF) ) {
247 ; /* halfwidth katakana */
248 } else if(p < 0x80 ) {
250 p = ( isupper( p )) ? tolower( p ) : p;
251 #endif /* DOWNCASE */
253 if( ( p == '/') || ( i == 0 && p == '.' ) ) {
255 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
256 p = hexdig[ p & 0x0f ];
272 static char *utompathsjis( char *from)
274 unsigned char *in, *out, *maxout;
277 in = (unsigned char *) from;
278 out = (unsigned char *) utom_buf;
279 maxout = out + sizeof( utom_buf) - 3;
281 while( out < maxout ) {
284 if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
288 } else if( p == 0x8E ) { /* do nothing */
290 } else if( p < 0x80 ) {
292 p = ( isupper( p )) ? tolower( p ) : p;
293 #endif /* DOWNCASE */
295 if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
296 *(in+1) != '\0' && islxdigit( *(in+1))) {
297 p = hextoint( *in ) << 4;
299 p |= hextoint( *in );
311 static char *utompathiconv(char *upath)
314 u_int16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
316 static char mpath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
319 outlen = strlen(upath);
322 if (vol->v_casefold & AFPVOL_UTOMUPPER)
323 flags |= CONV_TOUPPER;
324 else if (vol->v_casefold & AFPVOL_UTOMLOWER)
325 flags |= CONV_TOLOWER;
330 /* convert charsets */
331 if ((size_t)-1 == ( outlen = convert_charset ( vol.v_volcharset, vol.v_maccharset, vol.v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) {
332 fprintf( stderr, "Conversion from %s to %s for %s failed.", vol.v_volcodepage, vol.v_maccodepage, u);
336 if (flags & CONV_REQMANGLE)
342 return(utompathcap( upath ));
345 static char *mtoupathiconv(char *mpath)
351 static char upath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
353 if ( *mpath == '\0' ) {
357 /* set conversion flags */
358 if (!(vol.v_flags & AFPVOL_NOHEX))
359 flags |= CONV_ESCAPEHEX;
360 if (!(vol.v_flags & AFPVOL_USEDOTS))
361 flags |= CONV_ESCAPEDOTS;
364 if ((vol->v_casefold & AFPVOL_MTOUUPPER))
365 flags |= CONV_TOUPPER;
366 else if ((vol->v_casefold & AFPVOL_MTOULOWER))
367 flags |= CONV_TOLOWER;
376 if ((size_t)-1 == (outlen = convert_charset ( vol.v_maccharset, vol.v_volcharset, vol.v_maccharset, m, inplen, u, outlen, &flags)) ) {
377 fprintf (stderr, "conversion from %s to %s for %s failed.", vol.v_maccodepage, vol.v_volcodepage, mpath);
378 return(mtoupathcap( upath ));
386 char * (*_mtoupath) ( char *mpath) = mtoupathcap;
387 char * (*_utompath) ( char *upath) = utompathcap;
389 /* choose translators for optional character set */
390 void select_charset( int options)
393 if( options & OPTION_EUCJP ) {
394 _mtoupath = mtoupatheuc;
395 _utompath = utompatheuc;
396 } else if( options & OPTION_SJIS ) {
397 _mtoupath = mtoupathsjis;
398 _utompath = utompathsjis;
400 _mtoupath = mtoupathcap;
401 _utompath = utompathcap;
407 int hexfork[ NUMFORKS ];
408 #endif /* HEXOUTPUT */
410 static struct nad_file_data {
411 char macname[ MAXPATHLEN + 1 ];
412 char adpath[ 2 ][ MAXPATHLEN + 1];
413 int offset[ NUMFORKS ];
417 static void initvol(char *path)
419 if (!loadvolinfo(path, &vol)) {
420 vol_load_charsets(&vol);
421 ad_init(&nad.ad, vol.v_adouble, 0);
422 _mtoupath = mtoupathiconv;
423 _utompath = utompathiconv;
426 ad_init(&nad.ad, 0, 0);
430 int nad_open( char *path, int openflags, struct FHeader *fh, int options)
436 * Depending upon openflags, set up nad.adpath for the open. If it
437 * is for write, then stat the current directory to get its mode.
438 * Open the file. Either fill or grab the adouble information.
440 select_charset( options);
441 memset(&nad.ad, 0, sizeof(nad.ad));
443 if ( openflags == O_RDONLY ) {
445 strcpy( nad.adpath[0], path );
446 strcpy( nad.adpath[1],
447 nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF ));
448 for ( fork = 0 ; fork < NUMFORKS ; fork++ ) {
449 if ( stat( nad.adpath[ fork ], &st ) < 0 ) {
450 if ( errno == ENOENT ) {
451 fprintf( stderr, "%s is not an adouble file.\n", path );
453 perror( "stat of adouble file failed" );
460 fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
461 fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
463 if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
464 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
465 perror( nad.adpath[ 0 ] );
468 return( nad_header_read( fh ));
472 strcpy( nad.macname, fh->name );
473 strcpy( nad.adpath[0], mtoupath( nad.macname ));
474 strcpy( nad.adpath[1],
475 nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF ));
477 fprintf(stderr, "%s\n", nad.macname);
478 fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
479 fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
481 if ( stat( ".", &st ) < 0 ) {
482 perror( "stat of . failed" );
486 if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
487 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
488 perror( nad.adpath[ 0 ] );
491 return( nad_header_write( fh ));
495 int nad_header_read(struct FHeader *fh)
502 memcpy( nad.macname, ad_entry( &nad.ad, ADEID_NAME ),
503 ad_getentrylen( &nad.ad, ADEID_NAME ));
504 nad.macname[ ad_getentrylen( &nad.ad, ADEID_NAME ) ] = '\0';
505 strcpy( fh->name, nad.macname );
508 /* just in case there's nothing in macname */
509 if (*fh->name == '\0') {
510 if ( NULL == (p = strrchr(nad.adpath[DATA], '/')) )
511 p = nad.adpath[DATA];
514 strcpy(fh->name, utompath(nad.adpath[DATA]));
516 strcpy(fh->name, utompath(p));
519 if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
520 perror( "stat of datafork failed" );
523 fh->forklen[ DATA ] = htonl( st.st_size );
524 fh->forklen[ RESOURCE ] = htonl( ad_getentrylen( &nad.ad, ADEID_RFORK ));
525 fh->comment[0] = '\0';
528 fprintf( stderr, "macname of file\t\t\t%.*s\n", strlen( fh->name ),
530 fprintf( stderr, "size of data fork\t\t%d\n",
531 ntohl( fh->forklen[ DATA ] ));
532 fprintf( stderr, "size of resource fork\t\t%d\n",
533 ntohl( fh->forklen[ RESOURCE ] ));
534 fprintf( stderr, "get info comment\t\t\"%s\"\n", fh->comment );
537 ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
538 memcpy( &fh->create_date, &temptime, sizeof( temptime ));
539 ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
540 memcpy( &fh->mod_date, &temptime, sizeof( temptime ));
541 ad_getdate(&nad.ad, AD_DATE_BACKUP, &temptime);
542 memcpy( &fh->backup_date, &temptime, sizeof( temptime ));
545 memcpy( &temptime, &fh->create_date, sizeof( temptime ));
546 temptime = AD_DATE_TO_UNIX(temptime);
547 fprintf( stderr, "create_date seconds\t\t%lu\n", temptime );
548 memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
549 temptime = AD_DATE_TO_UNIX(temptime);
550 fprintf( stderr, "mod_date seconds\t\t%lu\n", temptime );
551 memcpy( &temptime, &fh->backup_date, sizeof( temptime ));
552 temptime = AD_DATE_TO_UNIX(temptime);
553 fprintf( stderr, "backup_date seconds\t\t%lu\n", temptime );
554 fprintf( stderr, "size of finder_info\t\t%d\n", sizeof( fh->finder_info ));
557 memcpy(&fh->finder_info.fdType,
558 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
559 sizeof( fh->finder_info.fdType ));
560 memcpy(&fh->finder_info.fdCreator,
561 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
562 sizeof( fh->finder_info.fdCreator ));
563 memcpy(&fh->finder_info.fdFlags,
564 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
565 sizeof( fh->finder_info.fdFlags ));
566 memcpy(&fh->finder_info.fdLocation,
567 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
568 sizeof( fh->finder_info.fdLocation ));
569 memcpy(&fh->finder_info.fdFldr,
570 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
571 sizeof( fh->finder_info.fdFldr ));
572 memcpy(&fh->finder_xinfo.fdScript,
573 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
574 sizeof(fh->finder_xinfo.fdScript));
575 memcpy(&fh->finder_xinfo.fdXFlags,
576 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
577 sizeof(fh->finder_xinfo.fdXFlags));
582 fprintf( stderr, "finder_info.fdType\t\t%.*s\n",
583 sizeof( fh->finder_info.fdType ), &fh->finder_info.fdType );
584 fprintf( stderr, "finder_info.fdCreator\t\t%.*s\n",
585 sizeof( fh->finder_info.fdCreator ),
586 &fh->finder_info.fdCreator );
587 fprintf( stderr, "nad type and creator\t\t%.*s\n\n",
588 sizeof( fh->finder_info.fdType ) +
589 sizeof( fh->finder_info.fdCreator ),
590 ad_entry( &nad.ad, ADEID_FINDERI ));
591 memcpy(&flags, ad_entry( &nad.ad, ADEID_FINDERI ) +
592 FINDERIOFF_FLAGS, sizeof( flags ));
593 fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
594 fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
595 fprintf(stderr, "fh script\t\t\t%x\n", fh->finder_xinfo.fdScript);
596 fprintf(stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags);
600 nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
606 int nad_header_write(struct FHeader *fh)
610 ad_setentrylen( &nad.ad, ADEID_NAME, strlen( nad.macname ));
611 memcpy( ad_entry( &nad.ad, ADEID_NAME ), nad.macname,
612 ad_getentrylen( &nad.ad, ADEID_NAME ));
613 ad_setentrylen( &nad.ad, ADEID_COMMENT, strlen( fh->comment ));
614 memcpy( ad_entry( &nad.ad, ADEID_COMMENT ), fh->comment,
615 ad_getentrylen( &nad.ad, ADEID_COMMENT ));
616 ad_setentrylen( &nad.ad, ADEID_RFORK, ntohl( fh->forklen[ RESOURCE ] ));
619 fprintf( stderr, "ad_getentrylen\n" );
620 fprintf( stderr, "ADEID_FINDERI\t\t\t%d\n",
621 ad_getentrylen( &nad.ad, ADEID_FINDERI ));
622 fprintf( stderr, "ADEID_RFORK\t\t\t%d\n",
623 ad_getentrylen( &nad.ad, ADEID_RFORK ));
624 fprintf( stderr, "ADEID_NAME\t\t\t%d\n",
625 ad_getentrylen( &nad.ad, ADEID_NAME ));
626 fprintf( stderr, "ad_entry of ADEID_NAME\t\t%.*s\n",
627 ad_getentrylen( &nad.ad, ADEID_NAME ),
628 ad_entry( &nad.ad, ADEID_NAME ));
629 fprintf( stderr, "ADEID_COMMENT\t\t\t%d\n",
630 ad_getentrylen( &nad.ad, ADEID_COMMENT ));
633 memcpy( &temptime, &fh->create_date, sizeof( temptime ));
634 ad_setdate(&nad.ad, AD_DATE_CREATE, temptime);
635 memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
636 ad_setdate(&nad.ad, AD_DATE_MODIFY, temptime);
639 ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
640 temptime = AD_DATE_TO_UNIX(temptime);
641 fprintf(stderr, "FILEIOFF_CREATE seconds\t\t%ld\n", temptime );
642 ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
643 temptime = AD_DATE_TO_UNIX(temptime);
644 fprintf(stderr, "FILEIOFF_MODIFY seconds\t\t%ld\n", temptime );
647 memset( ad_entry( &nad.ad, ADEID_FINDERI ), 0, ADEDLEN_FINDERI );
648 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
649 &fh->finder_info.fdType, sizeof( fh->finder_info.fdType ));
650 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
651 &fh->finder_info.fdCreator, sizeof( fh->finder_info.fdCreator ));
652 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
653 &fh->finder_info.fdFlags, sizeof( fh->finder_info.fdFlags ));
654 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
655 &fh->finder_info.fdLocation,sizeof( fh->finder_info.fdLocation ));
656 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
657 &fh->finder_info.fdFldr, sizeof( fh->finder_info.fdFldr ));
658 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
659 &fh->finder_xinfo.fdScript, sizeof( fh->finder_xinfo.fdScript ));
660 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
661 &fh->finder_xinfo.fdXFlags, sizeof( fh->finder_xinfo.fdXFlags));
667 memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS),
669 fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
670 fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
671 fprintf( stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags );
672 fprintf( stderr, "type and creator\t\t%.*s\n\n",
673 sizeof( fh->finder_info.fdType ) +
674 sizeof( fh->finder_info.fdCreator ),
675 ad_entry( &nad.ad, ADEID_FINDERI ));
680 hexfork[ DATA ] = open( "datafork", O_WRONLY|O_CREAT, 0622 );
681 hexfork[ RESOURCE ] = open( "resfork", O_WRONLY|O_CREAT, 0622 );
682 #endif /* HEXOUTPUT */
684 nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
690 static int forkeid[] = { ADEID_DFORK, ADEID_RFORK };
692 ssize_t nad_read(int fork, char *forkbuf, size_t bufc)
697 fprintf( stderr, "Entering nad_read\n" );
700 if (( cc = ad_read( &nad.ad, forkeid[ fork ], nad.offset[ fork ],
701 forkbuf, bufc)) < 0 ) {
702 perror( "Reading the appledouble file:" );
705 nad.offset[ fork ] += cc;
708 fprintf( stderr, "Exiting nad_read\n" );
714 ssize_t nad_write(int fork, char *forkbuf, size_t bufc)
721 fprintf( stderr, "Entering nad_write\n" );
725 write( hexfork[ fork ], forkbuf, bufc );
726 #endif /* HEXOUTPUT */
731 while (( writelen > 0 ) && ( cc >= 0 )) {
732 cc = ad_write( &nad.ad, forkeid[ fork ], nad.offset[ fork ],
733 0, buf_ptr, writelen);
734 nad.offset[ fork ] += cc;
739 perror( "Writing the appledouble file:" );
746 int nad_close(int status)
749 if ( status == KEEP ) {
750 if (( rv = ad_flush( &nad.ad )) < 0 ) {
751 fprintf( stderr, "nad_close rv for flush %d\n", rv );
754 if (( rv = ad_close( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
755 fprintf( stderr, "nad_close rv for close %d\n", rv );
758 } else if ( status == TRASH ) {
759 if ( unlink( nad.adpath[ 0 ] ) < 0 ) {
760 perror ( nad.adpath[ 0 ] );
762 if ( unlink( nad.adpath[ 1 ] ) < 0 ) {
763 perror ( nad.adpath[ 1 ] );