2 * $Id: nad.c,v 1.11 2002-04-29 01:52:50 morgana Exp $
7 #endif /* HAVE_CONFIG_H */
10 #include <sys/param.h>
21 #endif /* HAVE_FCNTL_H */
23 #include <atalk/adouble.h>
24 #include <netatalk/endian.h>
28 static char hexdig[] = "0123456789abcdef";
30 static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
31 static char *mtoupathcap( 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( upath )
75 while ( *u != '\0' ) {
76 if (*u == ':' && *(u + 1) != '\0' && islxdigit(*(u+1)) &&
77 *(u+2) != '\0' && islxdigit(*(u+2))) {
79 h = hextoint(*u) << 4;
97 static void euc2sjis( int *p1, int *p2) /* agrees w/ Samba on valid codes */
99 int row_offset, cell_offset;
100 unsigned char c1, c2;
102 /* first convert EUC to ISO-2022 */
106 /* now convert ISO-2022 to Shift-JIS */
107 row_offset = c1 < 95 ? 112 : 176;
108 cell_offset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;
110 *p1 = ((c1 + 1) >> 1) + row_offset;
111 *p2 = c2 + cell_offset;
114 static void sjis2euc( int *p1, int *p2) /* agrees w/ Samba on valid codes */
116 int row_offset, cell_offset, adjust;
117 unsigned char c1, c2;
122 /* first convert Shift-JIS to ISO-2022 */
124 row_offset = c1 < 160 ? 112 : 176;
125 cell_offset = adjust ? (c2 > 127 ? 32 : 31) : 126;
127 c1 = ((c1 - row_offset) << 1) - adjust;
130 /* now convert ISO-2022 to EUC */
135 static char *mtoupatheuc( char *from)
137 unsigned char *in, *out, *maxout;
140 in = (unsigned char *) from;
141 out = (unsigned char *) mtou_buf;
144 maxout = out + sizeof( mtou_buf) - 3;
146 while( out < maxout ) {
149 if( ((0x81 <= p) && (p <= 0x9F))
150 || ((0xE0 <= p) && (p <= 0xEF)) ) {
153 if( ((0x40 <= p2) && (p2 <= 0x7E))
154 || ((0x80 <= p2) && (p2 <= 0xFC)) )
159 } else if( (0xA1 <= p) && (p <= 0xDF) ) {
160 *out++ = 0x8E; /* halfwidth katakana */
161 } else if( p < 0x80 ) {
163 p = ( isupper( p )) ? tolower( p ) : p;
164 #endif /* DOWNCASE */
166 if( ( p == '/') || ( i == 0 && p == '.' ) ) {
168 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
169 p = hexdig[ p & 0x0f ];
185 static char *utompatheuc( char *from)
187 unsigned char *in, *out, *maxout;
190 in = (unsigned char *) from;
191 out = (unsigned char *) utom_buf;
192 maxout = out + sizeof( utom_buf) - 3;
194 while( out < maxout ) {
197 if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
199 if( (0xA1 <= p2) && (p2 <= 0xFE) )
203 } else if( p == 0x8E ) { /* halfwidth katakana */
205 } else if( p < 0x80 ) {
207 p = ( isupper( p )) ? tolower( p ) : p;
208 #endif /* DOWNCASE */
210 if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
211 *(in+1) != '\0' && islxdigit( *(in+1))) {
212 p = hextoint( *in ) << 4;
214 p |= hextoint( *in );
226 static char *mtoupathsjis( char *from)
228 unsigned char *in, *out, *maxout;
231 in = (unsigned char *) from;
232 out = (unsigned char *) mtou_buf;
235 maxout = out + sizeof( mtou_buf) - 3;
237 while( out < maxout ) {
240 if( ((0x81 <= p) && (p <= 0x9F))
241 || ((0xE0 <= p) && (p <= 0xEF)) ) {
247 } else if( (0xA1 <= p) && (p <= 0xDF) ) {
248 ; /* halfwidth katakana */
249 } else if(p < 0x80 ) {
251 p = ( isupper( p )) ? tolower( p ) : p;
252 #endif /* DOWNCASE */
254 if( ( p == '/') || ( i == 0 && p == '.' ) ) {
256 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
257 p = hexdig[ p & 0x0f ];
273 static char *utompathsjis( char *from)
275 unsigned char *in, *out, *maxout;
278 in = (unsigned char *) from;
279 out = (unsigned char *) utom_buf;
280 maxout = out + sizeof( utom_buf) - 3;
282 while( out < maxout ) {
285 if( (0xA1 <= p) && (p <= 0xFE) ) { /* JIS X 0208 */
289 } else if( p == 0x8E ) { /* do nothing */
291 } else if( p < 0x80 ) {
293 p = ( isupper( p )) ? tolower( p ) : p;
294 #endif /* DOWNCASE */
296 if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
297 *(in+1) != '\0' && islxdigit( *(in+1))) {
298 p = hextoint( *in ) << 4;
300 p |= hextoint( *in );
312 char * (*_mtoupath) ( char *mpath) = mtoupathcap;
313 char * (*_utompath) ( char *upath) = utompathcap;
315 /* choose translators for optional character set */
316 void select_charset( int options)
319 if( options & OPTION_EUCJP ) {
320 _mtoupath = mtoupatheuc;
321 _utompath = utompatheuc;
322 } else if( options & OPTION_SJIS ) {
323 _mtoupath = mtoupathsjis;
324 _utompath = utompathsjis;
326 _mtoupath = mtoupathcap;
327 _utompath = utompathcap;
333 int hexfork[ NUMFORKS ];
334 #endif /* HEXOUTPUT */
336 struct nad_file_data {
337 char macname[ MAXPATHLEN + 1 ];
338 char adpath[ 2 ][ MAXPATHLEN + 1];
339 int offset[ NUMFORKS ];
343 int nad_open( path, openflags, fh, options )
345 int openflags, options;
352 * Depending upon openflags, set up nad.adpath for the open. If it
353 * is for write, then stat the current directory to get its mode.
354 * Open the file. Either fill or grab the adouble information.
356 select_charset( options);
357 memset(&nad.ad, 0, sizeof(nad.ad));
358 if ( openflags == O_RDONLY ) {
359 strcpy( nad.adpath[0], path );
360 strcpy( nad.adpath[1],
361 ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
362 for ( fork = 0 ; fork < NUMFORKS ; fork++ ) {
363 if ( stat( nad.adpath[ fork ], &st ) < 0 ) {
364 if ( errno == ENOENT ) {
365 fprintf( stderr, "%s is not an adouble file.\n", path );
367 perror( "stat of adouble file failed" );
374 fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
375 fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
377 if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
378 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
379 perror( nad.adpath[ 0 ] );
382 return( nad_header_read( fh ));
385 strcpy( nad.macname, fh->name );
386 strcpy( nad.adpath[0], mtoupath( nad.macname ));
387 strcpy( nad.adpath[1],
388 ad_path( nad.adpath[0], ADFLAGS_DF|ADFLAGS_HF ));
390 fprintf(stderr, "%s\n", nad.macname);
391 fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
392 fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
394 if ( stat( ".", &st ) < 0 ) {
395 perror( "stat of . failed" );
399 if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
400 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
401 perror( nad.adpath[ 0 ] );
404 return( nad_header_write( fh ));
408 int nad_header_read( fh )
414 memcpy( nad.macname, ad_entry( &nad.ad, ADEID_NAME ),
415 ad_getentrylen( &nad.ad, ADEID_NAME ));
416 nad.macname[ ad_getentrylen( &nad.ad, ADEID_NAME ) ] = '\0';
417 strcpy( fh->name, nad.macname );
419 /* just in case there's nothing in macname */
420 if (*fh->name == '\0')
421 strcpy(fh->name, utompath(nad.adpath[DATA]));
423 if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
424 perror( "stat of datafork failed" );
427 fh->forklen[ DATA ] = htonl( st.st_size );
428 fh->forklen[ RESOURCE ] = htonl( ad_getentrylen( &nad.ad, ADEID_RFORK ));
429 fh->comment[0] = '\0';
432 fprintf( stderr, "macname of file\t\t\t%.*s\n", strlen( fh->name ),
434 fprintf( stderr, "size of data fork\t\t%d\n",
435 ntohl( fh->forklen[ DATA ] ));
436 fprintf( stderr, "size of resource fork\t\t%d\n",
437 ntohl( fh->forklen[ RESOURCE ] ));
438 fprintf( stderr, "get info comment\t\t\"%s\"\n", fh->comment );
441 ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
442 memcpy( &fh->create_date, &temptime, sizeof( temptime ));
443 ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
444 memcpy( &fh->mod_date, &temptime, sizeof( temptime ));
445 ad_getdate(&nad.ad, AD_DATE_BACKUP, &temptime);
446 memcpy( &fh->backup_date, &temptime, sizeof( temptime ));
449 memcpy( &temptime, &fh->create_date, sizeof( temptime ));
450 temptime = AD_DATE_TO_UNIX(temptime);
451 fprintf( stderr, "create_date seconds\t\t%lu\n", temptime );
452 memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
453 temptime = AD_DATE_TO_UNIX(temptime);
454 fprintf( stderr, "mod_date seconds\t\t%lu\n", temptime );
455 memcpy( &temptime, &fh->backup_date, sizeof( temptime ));
456 temptime = AD_DATE_TO_UNIX(temptime);
457 fprintf( stderr, "backup_date seconds\t\t%lu\n", temptime );
458 fprintf( stderr, "size of finder_info\t\t%d\n", sizeof( fh->finder_info ));
461 memcpy(&fh->finder_info.fdType,
462 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
463 sizeof( fh->finder_info.fdType ));
464 memcpy(&fh->finder_info.fdCreator,
465 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
466 sizeof( fh->finder_info.fdCreator ));
467 memcpy(&fh->finder_info.fdFlags,
468 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
469 sizeof( fh->finder_info.fdFlags ));
470 memcpy(&fh->finder_info.fdLocation,
471 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
472 sizeof( fh->finder_info.fdLocation ));
473 memcpy(&fh->finder_info.fdFldr,
474 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
475 sizeof( fh->finder_info.fdFldr ));
476 memcpy(&fh->finder_xinfo.fdScript,
477 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
478 sizeof(fh->finder_xinfo.fdScript));
479 memcpy(&fh->finder_xinfo.fdXFlags,
480 ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
481 sizeof(fh->finder_xinfo.fdXFlags));
486 fprintf( stderr, "finder_info.fdType\t\t%.*s\n",
487 sizeof( fh->finder_info.fdType ), &fh->finder_info.fdType );
488 fprintf( stderr, "finder_info.fdCreator\t\t%.*s\n",
489 sizeof( fh->finder_info.fdCreator ),
490 &fh->finder_info.fdCreator );
491 fprintf( stderr, "nad type and creator\t\t%.*s\n\n",
492 sizeof( fh->finder_info.fdType ) +
493 sizeof( fh->finder_info.fdCreator ),
494 ad_entry( &nad.ad, ADEID_FINDERI ));
495 memcpy(&flags, ad_entry( &nad.ad, ADEID_FINDERI ) +
496 FINDERIOFF_FLAGS, sizeof( flags ));
497 fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
498 fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
499 fprintf(stderr, "fh script\t\t\t%x\n", fh->finder_xinfo.fdScript);
500 fprintf(stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags);
504 nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
510 int nad_header_write( fh )
515 ad_setentrylen( &nad.ad, ADEID_NAME, strlen( nad.macname ));
516 memcpy( ad_entry( &nad.ad, ADEID_NAME ), nad.macname,
517 ad_getentrylen( &nad.ad, ADEID_NAME ));
518 ad_setentrylen( &nad.ad, ADEID_COMMENT, strlen( fh->comment ));
519 memcpy( ad_entry( &nad.ad, ADEID_COMMENT ), fh->comment,
520 ad_getentrylen( &nad.ad, ADEID_COMMENT ));
521 ad_setentrylen( &nad.ad, ADEID_RFORK, ntohl( fh->forklen[ RESOURCE ] ));
524 fprintf( stderr, "ad_getentrylen\n" );
525 fprintf( stderr, "ADEID_FINDERI\t\t\t%d\n",
526 ad_getentrylen( &nad.ad, ADEID_FINDERI ));
527 fprintf( stderr, "ADEID_RFORK\t\t\t%d\n",
528 ad_getentrylen( &nad.ad, ADEID_RFORK ));
529 fprintf( stderr, "ADEID_NAME\t\t\t%d\n",
530 ad_getentrylen( &nad.ad, ADEID_NAME ));
531 fprintf( stderr, "ad_entry of ADEID_NAME\t\t%.*s\n",
532 ad_getentrylen( &nad.ad, ADEID_NAME ),
533 ad_entry( &nad.ad, ADEID_NAME ));
534 fprintf( stderr, "ADEID_COMMENT\t\t\t%d\n",
535 ad_getentrylen( &nad.ad, ADEID_COMMENT ));
538 memcpy( &temptime, &fh->create_date, sizeof( temptime ));
539 ad_setdate(&nad.ad, AD_DATE_CREATE, temptime);
540 memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
541 ad_setdate(&nad.ad, AD_DATE_MODIFY, temptime);
544 ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
545 temptime = AD_DATE_TO_UNIX(temptime);
546 fprintf(stderr, "FILEIOFF_CREATE seconds\t\t%ld\n", temptime );
547 ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
548 temptime = AD_DATE_TO_UNIX(temptime);
549 fprintf(stderr, "FILEIOFF_MODIFY seconds\t\t%ld\n", temptime );
552 memset( ad_entry( &nad.ad, ADEID_FINDERI ), 0, ADEDLEN_FINDERI );
553 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
554 &fh->finder_info.fdType, sizeof( fh->finder_info.fdType ));
555 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
556 &fh->finder_info.fdCreator, sizeof( fh->finder_info.fdCreator ));
557 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
558 &fh->finder_info.fdFlags, sizeof( fh->finder_info.fdFlags ));
559 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
560 &fh->finder_info.fdLocation,sizeof( fh->finder_info.fdLocation ));
561 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
562 &fh->finder_info.fdFldr, sizeof( fh->finder_info.fdFldr ));
563 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
564 &fh->finder_xinfo.fdScript, sizeof( fh->finder_xinfo.fdScript ));
565 memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
566 &fh->finder_xinfo.fdXFlags, sizeof( fh->finder_xinfo.fdXFlags));
572 memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS),
574 fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
575 fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
576 fprintf( stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags );
577 fprintf( stderr, "type and creator\t\t%.*s\n\n",
578 sizeof( fh->finder_info.fdType ) +
579 sizeof( fh->finder_info.fdCreator ),
580 ad_entry( &nad.ad, ADEID_FINDERI ));
585 hexfork[ DATA ] = open( "datafork", O_WRONLY|O_CREAT, 0622 );
586 hexfork[ RESOURCE ] = open( "resfork", O_WRONLY|O_CREAT, 0622 );
587 #endif /* HEXOUTPUT */
589 nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
590 ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF );
595 int forkeid[] = { ADEID_DFORK, ADEID_RFORK };
597 int nad_read( fork, forkbuf, bufc )
605 fprintf( stderr, "Entering nad_read\n" );
608 if (( cc = ad_read( &nad.ad, forkeid[ fork ], nad.offset[ fork ],
609 forkbuf, bufc)) < 0 ) {
610 perror( "Reading the appledouble file:" );
613 nad.offset[ fork ] += cc;
616 fprintf( stderr, "Exiting nad_read\n" );
622 int nad_write( fork, forkbuf, bufc )
632 fprintf( stderr, "Entering nad_write\n" );
636 write( hexfork[ fork ], forkbuf, bufc );
637 #endif /* HEXOUTPUT */
642 while (( writelen > 0 ) && ( cc >= 0 )) {
643 cc = ad_write( &nad.ad, forkeid[ fork ], nad.offset[ fork ],
644 0, buf_ptr, writelen);
645 nad.offset[ fork ] += cc;
650 perror( "Writing the appledouble file:" );
657 int nad_close( status )
661 if ( status == KEEP ) {
662 if (( rv = ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
663 fprintf( stderr, "nad_close rv for flush %d\n", rv );
666 if (( rv = ad_close( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
667 fprintf( stderr, "nad_close rv for close %d\n", rv );
670 } else if ( status == TRASH ) {
671 if ( unlink( nad.adpath[ 0 ] ) < 0 ) {
672 perror ( nad.adpath[ 0 ] );
674 if ( unlink( nad.adpath[ 1 ] ) < 0 ) {
675 perror ( nad.adpath[ 1 ] );