]> arthur.barton.de Git - netatalk.git/blob - bin/megatron/nad.c
Merge 2-2
[netatalk.git] / bin / megatron / nad.c
1 /*
2  * $Id: nad.c,v 1.18 2010-01-27 21:27:53 didg Exp $
3  */
4
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif /* HAVE_CONFIG_H */
8
9 #include <sys/types.h>
10 #include <sys/param.h>
11 #include <sys/stat.h>
12 #include <sys/time.h>
13 #include <sys/uio.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <dirent.h>
19 #include <fcntl.h>
20
21 #include <atalk/adouble.h>
22 #include <atalk/util.h>
23 #include <atalk/volinfo.h>
24 #include <netatalk/endian.h>
25 #include "megatron.h"
26 #include "nad.h"
27
28 static struct volinfo   vol;
29 static char             hexdig[] = "0123456789abcdef";
30
31 static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
32 static char *mtoupathcap(char *mpath)
33 {
34     char        *m, *u, *umax;
35     int         i = 0;
36
37     m = mpath;
38     u = mtou_buf;
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 */
46             *u++ = ':';
47             *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
48             *u++ = hexdig[ *m & 0x0f ];
49         } else {
50 #ifdef DOWNCASE
51             *u++ = ( isupper( *m )) ? tolower( *m ) : *m;
52 #else /* DOWNCASE */
53             *u++ = *m;
54 #endif /* DOWNCASE */
55         }
56         i++;
57         m++;
58     }
59     *u = '\0';
60     return( mtou_buf );
61 }
62
63
64 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
65 #define islxdigit(x)    (!isupper(x)&&isxdigit(x))
66
67 static char *utompathcap( char *upath)
68 {
69     char        *m, *u;
70     int h;
71
72     m = utom_buf;
73     u = upath;
74     while ( *u != '\0' ) {
75         if (*u == ':' && *(u + 1) != '\0' && islxdigit(*(u+1)) &&
76             *(u+2) != '\0' && islxdigit(*(u+2))) {
77           u++;
78           h = hextoint(*u) << 4;
79           u++;
80           h |= hextoint(*u);
81           *m = h;
82         } else {
83 #ifdef DOWNCASE
84           *m = diatolower(*u);
85 #else /* DOWNCASE */
86           *m = *u;
87 #endif /* DOWNCASE */
88         }
89         u++;
90         m++;
91     }
92     *m = '\0';
93     return( utom_buf );
94 }
95
96 static void euc2sjis( int *p1, int *p2) /* agrees w/ Samba on valid codes */
97 {
98     int row_offset, cell_offset;
99     unsigned char c1, c2;
100
101     /* first convert EUC to ISO-2022 */
102     c1 = *p1 & 0x7F;
103     c2 = *p2 & 0x7F;
104
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;
108
109     *p1 = ((c1 + 1) >> 1) + row_offset;
110     *p2 = c2 + cell_offset;
111 }
112
113 static void sjis2euc( int *p1, int *p2)  /* agrees w/ Samba on valid codes */
114 {
115     int row_offset, cell_offset, adjust;
116     unsigned char c1, c2;
117
118     c1 = *p1;
119     c2 = *p2;
120
121     /* first convert Shift-JIS to ISO-2022 */
122     adjust = c2 < 159;
123     row_offset = c1 < 160 ? 112 : 176;
124     cell_offset = adjust ? (c2 > 127 ? 32 : 31) : 126;
125
126     c1 = ((c1 - row_offset) << 1) - adjust;
127     c2 -= cell_offset;
128
129     /* now convert ISO-2022 to EUC */
130     *p1 = c1 | 0x80;
131     *p2 = c2 | 0x80;
132 }
133
134 static char *mtoupatheuc( char *from)
135 {
136     unsigned char *in, *out, *maxout;
137     int p, p2, i = 0;
138
139     in = (unsigned char *) from;
140     out = (unsigned char *) mtou_buf;
141
142     if( *in ) {
143         maxout = out + sizeof( mtou_buf) - 3;
144
145         while( out < maxout ) {
146             p = *in++;
147
148             if( ((0x81 <= p) && (p <= 0x9F))
149              || ((0xE0 <= p) && (p <= 0xEF)) ) {
150                 /* JIS X 0208 */
151                 p2 = *in++;
152                 if( ((0x40 <= p2) && (p2 <= 0x7E))
153                  || ((0x80 <= p2) && (p2 <= 0xFC)) )
154                     sjis2euc( &p, &p2);
155                 *out++ = p;
156                 p = p2;
157
158             } else if( (0xA1 <= p) && (p <= 0xDF) ) {
159                 *out++ = 0x8E;  /* halfwidth katakana */
160             } else if( p < 0x80 ) {
161 #ifdef DOWNCASE
162                 p = ( isupper( p )) ? tolower( p ) : p;
163 #endif /* DOWNCASE */
164             }
165             if( ( p == '/') || ( i == 0 && p == '.' ) ) {
166                 *out++ = ':';
167                 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
168                 p = hexdig[ p & 0x0f ];
169             }
170             i++;
171             *out++ = p;
172             if( p )
173                 continue;
174             break;
175         }
176     } else {
177         *out++ = '.';
178         *out = 0;
179     }
180
181     return mtou_buf;
182 }
183
184 static char *utompatheuc( char *from)
185 {
186     unsigned char *in, *out, *maxout;
187     int p, p2;
188
189     in = (unsigned char *) from;
190     out = (unsigned char *) utom_buf;
191     maxout = out + sizeof( utom_buf) - 3;
192
193     while( out < maxout ) {
194         p = *in++;
195
196         if( (0xA1 <= p) && (p <= 0xFE) ) {      /* JIS X 0208 */
197             p2 = *in++;
198             if( (0xA1 <= p2) && (p2 <= 0xFE) )
199                 euc2sjis( &p, &p2);
200             *out++ = p;
201             p = p2;
202         } else if( p == 0x8E ) {                /* halfwidth katakana */
203             p = *in++;
204         } else if( p < 0x80 ) {
205 #ifdef DOWNCASE
206             p = ( isupper( p )) ? tolower( p ) : p;
207 #endif /* DOWNCASE */
208         }
209         if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
210                 *(in+1) != '\0' && islxdigit( *(in+1))) {
211            p = hextoint( *in ) << 4;
212            in++;
213            p |= hextoint( *in );
214            in++;
215         }
216         *out++ = p;
217         if( p )
218             continue;
219         break;
220     }
221
222     return utom_buf;
223 }
224
225 static char *mtoupathsjis( char *from)
226 {
227     unsigned char *in, *out, *maxout;
228     int p, p2, i = 0;
229
230     in = (unsigned char *) from;
231     out = (unsigned char *) mtou_buf;
232
233     if( *in ) {
234         maxout = out + sizeof( mtou_buf) - 3;
235
236         while( out < maxout ) {
237             p = *in++;
238
239             if( ((0x81 <= p) && (p <= 0x9F))
240              || ((0xE0 <= p) && (p <= 0xEF)) ) {
241                 /* JIS X 0208 */
242                 p2 = *in++;
243                 *out++ = p;
244                 p = p2;
245
246             } else if( (0xA1 <= p) && (p <= 0xDF) ) {
247                 ;       /* halfwidth katakana */
248             } else if(p < 0x80 ) {
249 #ifdef DOWNCASE
250                 p = ( isupper( p )) ? tolower( p ) : p;
251 #endif /* DOWNCASE */
252             }
253             if( ( p == '/') || ( i == 0 && p == '.' ) ) {
254                 *out++ = ':';
255                 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
256                 p = hexdig[ p & 0x0f ];
257             }
258             i++;
259             *out++ = p;
260             if( p )
261                 continue;
262             break;
263         }
264     } else {
265         *out++ = '.';
266         *out = 0;
267     }
268
269     return mtou_buf;
270 }
271
272 static char *utompathsjis( char *from)
273 {
274     unsigned char *in, *out, *maxout;
275     int p, p2;
276
277     in = (unsigned char *) from;
278     out = (unsigned char *) utom_buf;
279     maxout = out + sizeof( utom_buf) - 3;
280
281     while( out < maxout ) {
282         p = *in++;
283
284         if( (0xA1 <= p) && (p <= 0xFE) ) {      /* JIS X 0208 */
285             p2 = *in++;
286             *out++ = p;
287             p = p2;
288         } else if( p == 0x8E ) {                /* do nothing */
289             ;
290         } else if( p < 0x80 ) {
291 #ifdef DOWNCASE
292            p = ( isupper( p )) ? tolower( p ) : p;
293 #endif /* DOWNCASE */
294         }
295         if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
296                 *(in+1) != '\0' && islxdigit( *(in+1))) {
297            p = hextoint( *in ) << 4;
298            in++;
299            p |= hextoint( *in );
300            in++;
301         }
302         *out++ = p;
303         if( p )
304             continue;
305         break;
306     }
307
308     return utom_buf;
309  }
310
311 static char *utompathiconv(char *upath)
312 {
313     char        *m, *u;
314     u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
315     size_t       outlen;
316     static char  mpath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
317
318     m = mpath;
319     outlen = strlen(upath);
320
321 #if 0
322     if (vol->v_casefold & AFPVOL_UTOMUPPER)
323         flags |= CONV_TOUPPER;
324     else if (vol->v_casefold & AFPVOL_UTOMLOWER)
325         flags |= CONV_TOLOWER;
326 #endif
327
328     u = upath;
329
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);
333         goto utompath_error;
334     }
335
336     if (flags & CONV_REQMANGLE) 
337         goto utompath_error;
338
339     return(m);
340
341 utompath_error:
342     return(utompathcap( upath ));
343 }
344
345 static char *mtoupathiconv(char *mpath)
346 {
347     char        *m, *u;
348     size_t       inplen;
349     size_t       outlen;
350     u_int16_t    flags = 0;
351     static char  upath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
352
353     if ( *mpath == '\0' ) {
354         return( "." );
355     }
356
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;
362
363 #if 0
364     if ((vol->v_casefold & AFPVOL_MTOUUPPER))
365         flags |= CONV_TOUPPER;
366     else if ((vol->v_casefold & AFPVOL_MTOULOWER))
367         flags |= CONV_TOLOWER;
368 #endif
369
370     m = mpath;
371     u = upath;
372
373     inplen = strlen(m);
374     outlen = MAXPATHLEN;
375
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 ));
379     }
380
381     return( upath );
382 }
383
384
385  
386 char * (*_mtoupath) ( char *mpath) = mtoupathcap;
387 char * (*_utompath) ( char *upath) = utompathcap;
388
389 /* choose translators for optional character set */
390 void select_charset( int options)
391 {
392
393     if( options & OPTION_EUCJP ) {
394         _mtoupath = mtoupatheuc;
395         _utompath = utompatheuc;
396     } else if( options & OPTION_SJIS ) {
397         _mtoupath = mtoupathsjis;
398         _utompath = utompathsjis;
399     } else {
400         _mtoupath = mtoupathcap;
401         _utompath = utompathcap;
402     }
403 }
404
405
406 #if HEXOUTPUT
407     int                 hexfork[ NUMFORKS ];
408 #endif /* HEXOUTPUT */
409
410 static struct nad_file_data {
411     char                macname[ MAXPATHLEN + 1 ];
412     char                adpath[ 2 ][ MAXPATHLEN + 1];
413     int                 offset[ NUMFORKS ];
414     struct adouble      ad;
415 } nad;
416
417 static void initvol(char *path)
418 {
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;
424     }
425     else
426         ad_init(&nad.ad, 0, 0);
427 }
428
429
430 int nad_open( char *path, int openflags, struct FHeader *fh, int options)
431 {
432     struct stat         st;
433     int                 fork;
434
435 /*
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.
439  */
440     select_charset( options);
441     memset(&nad.ad, 0, sizeof(nad.ad));
442
443     if ( openflags == O_RDONLY ) {
444         initvol(path);
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 );
452                 } else {
453                     perror( "stat of adouble file failed" );
454                 }
455                 return( -1 );
456             }
457         }
458
459 #if DEBUG
460     fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
461     fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
462 #endif /* DEBUG */
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 ] );
466             return( -1 );
467         }
468         return( nad_header_read( fh ));
469
470     } else {
471         initvol (".");
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 ));
476 #if DEBUG
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]);
480 #endif /* DEBUG */
481         if ( stat( ".", &st ) < 0 ) {
482             perror( "stat of . failed" );
483             return( -1 );
484         }
485         (void)umask( 0 );
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 ] );
489             return( -1 );
490         }
491         return( nad_header_write( fh ));
492     }
493 }
494
495 int nad_header_read(struct FHeader *fh)
496 {
497     u_int32_t           temptime;
498     struct stat         st;
499     char                *p;
500
501 #if 0
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 );
506 #endif
507
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];
512       else p++;
513 #if 0      
514       strcpy(fh->name, utompath(nad.adpath[DATA]));
515 #endif      
516       strcpy(fh->name, utompath(p));
517     }
518
519     if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
520         perror( "stat of datafork failed" );
521         return( -1 );
522     }
523     fh->forklen[ DATA ] = htonl( st.st_size );
524     fh->forklen[ RESOURCE ] = htonl( ad_getentrylen( &nad.ad, ADEID_RFORK ));
525     fh->comment[0] = '\0';
526
527 #if DEBUG
528     fprintf( stderr, "macname of file\t\t\t%.*s\n", strlen( fh->name ), 
529             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 );
535 #endif /* DEBUG */
536
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 ));
543
544 #if DEBUG
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 ));
555 #endif /* DEBUG */
556
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));
578
579 #if DEBUG
580     {
581         short           flags;
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);
597     }
598 #endif /* DEBUG */
599
600     nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
601
602     return( 0 );
603
604 }
605
606 int nad_header_write(struct FHeader *fh)
607 {
608     u_int32_t           temptime;
609
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 ] ));
617
618 #if DEBUG
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 ));
631 #endif /* DEBUG */
632
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);
637
638 #if DEBUG
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 );
645 #endif /* DEBUG */
646
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));
662
663
664 #if DEBUG
665     {
666         short           flags;
667         memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS),
668                 sizeof( 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 ));
676     }
677 #endif /* DEBUG */
678
679 #if HEXOUTPUT
680     hexfork[ DATA ] = open( "datafork", O_WRONLY|O_CREAT, 0622 );
681     hexfork[ RESOURCE ] = open( "resfork", O_WRONLY|O_CREAT, 0622 );
682 #endif /* HEXOUTPUT */
683
684     nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
685     ad_flush( &nad.ad );
686
687     return( 0 );
688 }
689
690 static int              forkeid[] = { ADEID_DFORK, ADEID_RFORK };
691
692 ssize_t nad_read(int fork, char *forkbuf, size_t bufc)
693 {
694     ssize_t             cc = 0;
695
696 #if DEBUG
697     fprintf( stderr, "Entering nad_read\n" );
698 #endif /* DEBUG */
699
700     if (( cc = ad_read( &nad.ad, forkeid[ fork ], nad.offset[ fork ], 
701             forkbuf, bufc)) < 0 )  {
702         perror( "Reading the appledouble file:" );
703         return( cc );
704     }
705     nad.offset[ fork ] += cc;
706
707 #if DEBUG
708     fprintf( stderr, "Exiting nad_read\n" );
709 #endif /* DEBUG */
710
711     return( cc );
712 }
713
714 ssize_t nad_write(int fork, char *forkbuf, size_t bufc)
715 {
716     char                *buf_ptr;
717     size_t              writelen;
718     ssize_t             cc = 0;
719
720 #if DEBUG
721     fprintf( stderr, "Entering nad_write\n" );
722 #endif /* DEBUG */
723
724 #if HEXOUTPUT
725     write( hexfork[ fork ], forkbuf, bufc );
726 #endif /* HEXOUTPUT */
727
728     writelen = bufc;
729     buf_ptr = forkbuf;
730
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;
735         buf_ptr += cc;
736         writelen -= cc;
737     }
738     if ( cc < 0 ) {
739         perror( "Writing the appledouble file:" );
740         return( cc );
741     }
742
743     return( bufc );
744 }
745
746 int nad_close(int status)
747 {
748     int                 rv;
749     if ( status == KEEP ) {
750         if (( rv = ad_flush( &nad.ad )) < 0 ) {
751             fprintf( stderr, "nad_close rv for flush %d\n", rv );
752             return( rv );
753         }
754         if (( rv = ad_close( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
755             fprintf( stderr, "nad_close rv for close %d\n", rv );
756             return( rv );
757         }
758     } else if ( status == TRASH ) {
759         if ( unlink( nad.adpath[ 0 ] ) < 0 ) {
760             perror ( nad.adpath[ 0 ] );
761         }
762         if ( unlink( nad.adpath[ 1 ] ) < 0 ) {
763             perror ( nad.adpath[ 1 ] );
764         }
765         return( 0 );
766     } else return( -1 );
767     return( 0 );
768 }