]> arthur.barton.de Git - netatalk.git/blob - bin/megatron/nad.c
Writing metadata xattr on directories with sticky bit set, FR#94
[netatalk.git] / bin / megatron / nad.c
1 /*
2  */
3
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif /* HAVE_CONFIG_H */
7
8 #include <sys/types.h>
9 #include <sys/param.h>
10 #include <sys/stat.h>
11 #include <sys/time.h>
12 #include <sys/uio.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <dirent.h>
18 #include <fcntl.h>
19
20 #include <atalk/adouble.h>
21 #include <atalk/util.h>
22 #include <atalk/volinfo.h>
23 #include <netatalk/endian.h>
24 #include "megatron.h"
25 #include "nad.h"
26
27 static struct volinfo   vol;
28 static char             hexdig[] = "0123456789abcdef";
29
30 static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
31 static char *mtoupathcap(char *mpath)
32 {
33     char        *m, *u, *umax;
34     int         i = 0;
35
36     m = mpath;
37     u = mtou_buf;
38     umax = u + sizeof(mtou_buf) - 4;
39     while ( *m != '\0' && u < umax) {
40 #if AD_VERSION == AD_VERSION1
41         if ( !isascii( *m ) || *m == '/' || ( i == 0 && *m == '.' )) {
42 #else /* AD_VERSION == AD_VERSION1 */
43         if (!isprint(*m) || *m == '/' || ( i == 0 && (*m == '.' ))) {
44 #endif /* AD_VERSION == AD_VERSION1 */
45             *u++ = ':';
46             *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ];
47             *u++ = hexdig[ *m & 0x0f ];
48         } else {
49 #ifdef DOWNCASE
50             *u++ = ( isupper( *m )) ? tolower( *m ) : *m;
51 #else /* DOWNCASE */
52             *u++ = *m;
53 #endif /* DOWNCASE */
54         }
55         i++;
56         m++;
57     }
58     *u = '\0';
59     return( mtou_buf );
60 }
61
62
63 #define hextoint( c )   ( isdigit( c ) ? c - '0' : c + 10 - 'a' )
64 #define islxdigit(x)    (!isupper(x)&&isxdigit(x))
65
66 static char *utompathcap( char *upath)
67 {
68     char        *m, *u;
69     int h;
70
71     m = utom_buf;
72     u = upath;
73     while ( *u != '\0' ) {
74         if (*u == ':' && *(u + 1) != '\0' && islxdigit(*(u+1)) &&
75             *(u+2) != '\0' && islxdigit(*(u+2))) {
76           u++;
77           h = hextoint(*u) << 4;
78           u++;
79           h |= hextoint(*u);
80           *m = h;
81         } else {
82 #ifdef DOWNCASE
83           *m = diatolower(*u);
84 #else /* DOWNCASE */
85           *m = *u;
86 #endif /* DOWNCASE */
87         }
88         u++;
89         m++;
90     }
91     *m = '\0';
92     return( utom_buf );
93 }
94
95 static void euc2sjis( int *p1, int *p2) /* agrees w/ Samba on valid codes */
96 {
97     int row_offset, cell_offset;
98     unsigned char c1, c2;
99
100     /* first convert EUC to ISO-2022 */
101     c1 = *p1 & 0x7F;
102     c2 = *p2 & 0x7F;
103
104     /* now convert ISO-2022 to Shift-JIS */
105     row_offset = c1 < 95 ? 112 : 176;
106     cell_offset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;
107
108     *p1 = ((c1 + 1) >> 1) + row_offset;
109     *p2 = c2 + cell_offset;
110 }
111
112 static void sjis2euc( int *p1, int *p2)  /* agrees w/ Samba on valid codes */
113 {
114     int row_offset, cell_offset, adjust;
115     unsigned char c1, c2;
116
117     c1 = *p1;
118     c2 = *p2;
119
120     /* first convert Shift-JIS to ISO-2022 */
121     adjust = c2 < 159;
122     row_offset = c1 < 160 ? 112 : 176;
123     cell_offset = adjust ? (c2 > 127 ? 32 : 31) : 126;
124
125     c1 = ((c1 - row_offset) << 1) - adjust;
126     c2 -= cell_offset;
127
128     /* now convert ISO-2022 to EUC */
129     *p1 = c1 | 0x80;
130     *p2 = c2 | 0x80;
131 }
132
133 static char *mtoupatheuc( char *from)
134 {
135     unsigned char *in, *out, *maxout;
136     int p, p2, i = 0;
137
138     in = (unsigned char *) from;
139     out = (unsigned char *) mtou_buf;
140
141     if( *in ) {
142         maxout = out + sizeof( mtou_buf) - 3;
143
144         while( out < maxout ) {
145             p = *in++;
146
147             if( ((0x81 <= p) && (p <= 0x9F))
148              || ((0xE0 <= p) && (p <= 0xEF)) ) {
149                 /* JIS X 0208 */
150                 p2 = *in++;
151                 if( ((0x40 <= p2) && (p2 <= 0x7E))
152                  || ((0x80 <= p2) && (p2 <= 0xFC)) )
153                     sjis2euc( &p, &p2);
154                 *out++ = p;
155                 p = p2;
156
157             } else if( (0xA1 <= p) && (p <= 0xDF) ) {
158                 *out++ = 0x8E;  /* halfwidth katakana */
159             } else if( p < 0x80 ) {
160 #ifdef DOWNCASE
161                 p = ( isupper( p )) ? tolower( p ) : p;
162 #endif /* DOWNCASE */
163             }
164             if( ( p == '/') || ( i == 0 && p == '.' ) ) {
165                 *out++ = ':';
166                 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
167                 p = hexdig[ p & 0x0f ];
168             }
169             i++;
170             *out++ = p;
171             if( p )
172                 continue;
173             break;
174         }
175     } else {
176         *out++ = '.';
177         *out = 0;
178     }
179
180     return mtou_buf;
181 }
182
183 static char *utompatheuc( char *from)
184 {
185     unsigned char *in, *out, *maxout;
186     int p, p2;
187
188     in = (unsigned char *) from;
189     out = (unsigned char *) utom_buf;
190     maxout = out + sizeof( utom_buf) - 3;
191
192     while( out < maxout ) {
193         p = *in++;
194
195         if( (0xA1 <= p) && (p <= 0xFE) ) {      /* JIS X 0208 */
196             p2 = *in++;
197             if( (0xA1 <= p2) && (p2 <= 0xFE) )
198                 euc2sjis( &p, &p2);
199             *out++ = p;
200             p = p2;
201         } else if( p == 0x8E ) {                /* halfwidth katakana */
202             p = *in++;
203         } else if( p < 0x80 ) {
204 #ifdef DOWNCASE
205             p = ( isupper( p )) ? tolower( p ) : p;
206 #endif /* DOWNCASE */
207         }
208         if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
209                 *(in+1) != '\0' && islxdigit( *(in+1))) {
210            p = hextoint( *in ) << 4;
211            in++;
212            p |= hextoint( *in );
213            in++;
214         }
215         *out++ = p;
216         if( p )
217             continue;
218         break;
219     }
220
221     return utom_buf;
222 }
223
224 static char *mtoupathsjis( char *from)
225 {
226     unsigned char *in, *out, *maxout;
227     int p, p2, i = 0;
228
229     in = (unsigned char *) from;
230     out = (unsigned char *) mtou_buf;
231
232     if( *in ) {
233         maxout = out + sizeof( mtou_buf) - 3;
234
235         while( out < maxout ) {
236             p = *in++;
237
238             if( ((0x81 <= p) && (p <= 0x9F))
239              || ((0xE0 <= p) && (p <= 0xEF)) ) {
240                 /* JIS X 0208 */
241                 p2 = *in++;
242                 *out++ = p;
243                 p = p2;
244
245             } else if( (0xA1 <= p) && (p <= 0xDF) ) {
246                 ;       /* halfwidth katakana */
247             } else if(p < 0x80 ) {
248 #ifdef DOWNCASE
249                 p = ( isupper( p )) ? tolower( p ) : p;
250 #endif /* DOWNCASE */
251             }
252             if( ( p == '/') || ( i == 0 && p == '.' ) ) {
253                 *out++ = ':';
254                 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
255                 p = hexdig[ p & 0x0f ];
256             }
257             i++;
258             *out++ = p;
259             if( p )
260                 continue;
261             break;
262         }
263     } else {
264         *out++ = '.';
265         *out = 0;
266     }
267
268     return mtou_buf;
269 }
270
271 static char *utompathsjis( char *from)
272 {
273     unsigned char *in, *out, *maxout;
274     int p, p2;
275
276     in = (unsigned char *) from;
277     out = (unsigned char *) utom_buf;
278     maxout = out + sizeof( utom_buf) - 3;
279
280     while( out < maxout ) {
281         p = *in++;
282
283         if( (0xA1 <= p) && (p <= 0xFE) ) {      /* JIS X 0208 */
284             p2 = *in++;
285             *out++ = p;
286             p = p2;
287         } else if( p == 0x8E ) {                /* do nothing */
288             ;
289         } else if( p < 0x80 ) {
290 #ifdef DOWNCASE
291            p = ( isupper( p )) ? tolower( p ) : p;
292 #endif /* DOWNCASE */
293         }
294         if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
295                 *(in+1) != '\0' && islxdigit( *(in+1))) {
296            p = hextoint( *in ) << 4;
297            in++;
298            p |= hextoint( *in );
299            in++;
300         }
301         *out++ = p;
302         if( p )
303             continue;
304         break;
305     }
306
307     return utom_buf;
308  }
309
310 static char *utompathiconv(char *upath)
311 {
312     char        *m, *u;
313     u_int16_t    flags = CONV_IGNORE | CONV_UNESCAPEHEX;
314     size_t       outlen;
315     static char  mpath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
316
317     m = mpath;
318     outlen = strlen(upath);
319
320 #if 0
321     if (vol->v_casefold & AFPVOL_UTOMUPPER)
322         flags |= CONV_TOUPPER;
323     else if (vol->v_casefold & AFPVOL_UTOMLOWER)
324         flags |= CONV_TOLOWER;
325 #endif
326
327     u = upath;
328
329     /* convert charsets */
330     if ((size_t)-1 == ( outlen = convert_charset ( vol.v_volcharset, vol.v_maccharset, vol.v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) {
331         fprintf( stderr, "Conversion from %s to %s for %s failed.", vol.v_volcodepage, vol.v_maccodepage, u);
332         goto utompath_error;
333     }
334
335     if (flags & CONV_REQMANGLE) 
336         goto utompath_error;
337
338     return(m);
339
340 utompath_error:
341     return(utompathcap( upath ));
342 }
343
344 static char *mtoupathiconv(char *mpath)
345 {
346     char        *m, *u;
347     size_t       inplen;
348     size_t       outlen;
349     u_int16_t    flags = 0;
350     static char  upath[MAXPATHLEN +2]; /* for convert_charset dest_len parameter +2 */
351
352     if ( *mpath == '\0' ) {
353         return( "." );
354     }
355
356     /* set conversion flags */
357     if (!(vol.v_flags & AFPVOL_NOHEX))
358         flags |= CONV_ESCAPEHEX;
359     if (!(vol.v_flags & AFPVOL_USEDOTS))
360         flags |= CONV_ESCAPEDOTS;
361
362 #if 0
363     if ((vol->v_casefold & AFPVOL_MTOUUPPER))
364         flags |= CONV_TOUPPER;
365     else if ((vol->v_casefold & AFPVOL_MTOULOWER))
366         flags |= CONV_TOLOWER;
367 #endif
368
369     m = mpath;
370     u = upath;
371
372     inplen = strlen(m);
373     outlen = MAXPATHLEN;
374
375     if ((size_t)-1 == (outlen = convert_charset ( vol.v_maccharset, vol.v_volcharset, vol.v_maccharset, m, inplen, u, outlen, &flags)) ) {
376         fprintf (stderr, "conversion from %s to %s for %s failed.", vol.v_maccodepage, vol.v_volcodepage, mpath);
377         return(mtoupathcap( upath ));
378     }
379
380     return( upath );
381 }
382
383
384  
385 char * (*_mtoupath) ( char *mpath) = mtoupathcap;
386 char * (*_utompath) ( char *upath) = utompathcap;
387
388 /* choose translators for optional character set */
389 void select_charset( int options)
390 {
391
392     if( options & OPTION_EUCJP ) {
393         _mtoupath = mtoupatheuc;
394         _utompath = utompatheuc;
395     } else if( options & OPTION_SJIS ) {
396         _mtoupath = mtoupathsjis;
397         _utompath = utompathsjis;
398     } else {
399         _mtoupath = mtoupathcap;
400         _utompath = utompathcap;
401     }
402 }
403
404
405 #if HEXOUTPUT
406     int                 hexfork[ NUMFORKS ];
407 #endif /* HEXOUTPUT */
408
409 static struct nad_file_data {
410     char                macname[ MAXPATHLEN + 1 ];
411     char                adpath[ 2 ][ MAXPATHLEN + 1];
412     int                 offset[ NUMFORKS ];
413     struct adouble      ad;
414 } nad;
415
416 static void initvol(char *path)
417 {
418     if (!loadvolinfo(path, &vol)) {
419         vol_load_charsets(&vol);
420         ad_init(&nad.ad, vol.v_adouble, 0);
421         _mtoupath = mtoupathiconv;
422         _utompath = utompathiconv;
423     }
424     else
425         ad_init(&nad.ad, 0, 0);
426 }
427
428
429 int nad_open( char *path, int openflags, struct FHeader *fh, int options)
430 {
431     struct stat         st;
432     int                 fork;
433
434 /*
435  * Depending upon openflags, set up nad.adpath for the open.  If it 
436  * is for write, then stat the current directory to get its mode.
437  * Open the file.  Either fill or grab the adouble information.
438  */
439     select_charset( options);
440     memset(&nad.ad, 0, sizeof(nad.ad));
441
442     if ( openflags == O_RDONLY ) {
443         initvol(path);
444         strcpy( nad.adpath[0], path );
445         strcpy( nad.adpath[1], 
446                 nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF ));
447         for ( fork = 0 ; fork < NUMFORKS ; fork++ ) {
448             if ( stat( nad.adpath[ fork ], &st ) < 0 ) {
449                 if ( errno == ENOENT ) {
450                     fprintf( stderr, "%s is not an adouble file.\n", path );
451                 } else {
452                     perror( "stat of adouble file failed" );
453                 }
454                 return( -1 );
455             }
456         }
457
458 #if DEBUG
459     fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
460     fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
461 #endif /* DEBUG */
462         if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
463                 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
464             perror( nad.adpath[ 0 ] );
465             return( -1 );
466         }
467         return( nad_header_read( fh ));
468
469     } else {
470         initvol (".");
471         strcpy( nad.macname, fh->name );
472         strcpy( nad.adpath[0], mtoupath( nad.macname ));
473         strcpy( nad.adpath[1], 
474                 nad.ad.ad_ops->ad_path( nad.adpath[0], ADFLAGS_HF ));
475 #if DEBUG
476     fprintf(stderr, "%s\n", nad.macname);
477     fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
478     fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
479 #endif /* DEBUG */
480         if ( stat( ".", &st ) < 0 ) {
481             perror( "stat of . failed" );
482             return( -1 );
483         }
484         (void)umask( 0 );
485         if ( ad_open( nad.adpath[ 0 ], ADFLAGS_DF|ADFLAGS_HF,
486                 openflags, (int)( st.st_mode & 0666 ), &nad.ad) < 0 ) {
487             perror( nad.adpath[ 0 ] );
488             return( -1 );
489         }
490         return( nad_header_write( fh ));
491     }
492 }
493
494 int nad_header_read(struct FHeader *fh)
495 {
496     u_int32_t           temptime;
497     struct stat         st;
498     char                *p;
499
500 #if 0
501     memcpy( nad.macname, ad_entry( &nad.ad, ADEID_NAME ), 
502             ad_getentrylen( &nad.ad, ADEID_NAME ));
503     nad.macname[ ad_getentrylen( &nad.ad, ADEID_NAME ) ] = '\0';
504     strcpy( fh->name, nad.macname );
505 #endif
506
507     /* just in case there's nothing in macname */
508     if (*fh->name == '\0') {
509       if ( NULL == (p = strrchr(nad.adpath[DATA], '/')) )
510         p = nad.adpath[DATA];
511       else p++;
512 #if 0      
513       strcpy(fh->name, utompath(nad.adpath[DATA]));
514 #endif      
515       strcpy(fh->name, utompath(p));
516     }
517
518     if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
519         perror( "stat of datafork failed" );
520         return( -1 );
521     }
522     fh->forklen[ DATA ] = htonl( st.st_size );
523     fh->forklen[ RESOURCE ] = htonl( ad_getentrylen( &nad.ad, ADEID_RFORK ));
524     fh->comment[0] = '\0';
525
526 #if DEBUG
527     fprintf( stderr, "macname of file\t\t\t%.*s\n", strlen( fh->name ), 
528             fh->name );
529     fprintf( stderr, "size of data fork\t\t%d\n", 
530             ntohl( fh->forklen[ DATA ] ));
531     fprintf( stderr, "size of resource fork\t\t%d\n", 
532             ntohl( fh->forklen[ RESOURCE ] ));
533     fprintf( stderr, "get info comment\t\t\"%s\"\n", fh->comment );
534 #endif /* DEBUG */
535
536     ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
537     memcpy( &fh->create_date, &temptime, sizeof( temptime ));
538     ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
539     memcpy( &fh->mod_date, &temptime, sizeof( temptime ));
540     ad_getdate(&nad.ad, AD_DATE_BACKUP, &temptime);
541     memcpy( &fh->backup_date, &temptime, sizeof( temptime ));
542
543 #if DEBUG
544     memcpy( &temptime, &fh->create_date, sizeof( temptime ));
545     temptime = AD_DATE_TO_UNIX(temptime);
546     fprintf( stderr, "create_date seconds\t\t%lu\n", temptime );
547     memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
548     temptime = AD_DATE_TO_UNIX(temptime);
549     fprintf( stderr, "mod_date seconds\t\t%lu\n", temptime );
550     memcpy( &temptime, &fh->backup_date, sizeof( temptime ));
551     temptime = AD_DATE_TO_UNIX(temptime);
552     fprintf( stderr, "backup_date seconds\t\t%lu\n", temptime );
553     fprintf( stderr, "size of finder_info\t\t%d\n", sizeof( fh->finder_info ));
554 #endif /* DEBUG */
555
556     memcpy(&fh->finder_info.fdType,
557             ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE,
558            sizeof( fh->finder_info.fdType ));
559     memcpy(&fh->finder_info.fdCreator,
560            ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
561            sizeof( fh->finder_info.fdCreator ));
562     memcpy(&fh->finder_info.fdFlags,
563            ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
564            sizeof( fh->finder_info.fdFlags ));
565     memcpy(&fh->finder_info.fdLocation,
566            ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
567            sizeof( fh->finder_info.fdLocation ));
568     memcpy(&fh->finder_info.fdFldr,
569           ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
570           sizeof( fh->finder_info.fdFldr ));
571     memcpy(&fh->finder_xinfo.fdScript,
572            ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
573            sizeof(fh->finder_xinfo.fdScript));
574     memcpy(&fh->finder_xinfo.fdXFlags,
575            ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
576            sizeof(fh->finder_xinfo.fdXFlags));
577
578 #if DEBUG
579     {
580         short           flags;
581         fprintf( stderr, "finder_info.fdType\t\t%.*s\n", 
582                 sizeof( fh->finder_info.fdType ), &fh->finder_info.fdType );
583         fprintf( stderr, "finder_info.fdCreator\t\t%.*s\n", 
584                 sizeof( fh->finder_info.fdCreator ),
585                 &fh->finder_info.fdCreator );
586         fprintf( stderr, "nad type and creator\t\t%.*s\n\n", 
587                 sizeof( fh->finder_info.fdType ) + 
588                 sizeof( fh->finder_info.fdCreator ), 
589                 ad_entry( &nad.ad, ADEID_FINDERI ));
590         memcpy(&flags, ad_entry( &nad.ad, ADEID_FINDERI ) + 
591                FINDERIOFF_FLAGS, sizeof( flags ));
592         fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
593         fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
594         fprintf(stderr, "fh script\t\t\t%x\n", fh->finder_xinfo.fdScript);
595         fprintf(stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags);
596     }
597 #endif /* DEBUG */
598
599     nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
600
601     return( 0 );
602
603 }
604
605 int nad_header_write(struct FHeader *fh)
606 {
607     u_int32_t           temptime;
608
609     ad_setentrylen( &nad.ad, ADEID_NAME, strlen( nad.macname ));
610     memcpy( ad_entry( &nad.ad, ADEID_NAME ), nad.macname, 
611             ad_getentrylen( &nad.ad, ADEID_NAME ));
612     ad_setentrylen( &nad.ad, ADEID_COMMENT, strlen( fh->comment ));
613     memcpy( ad_entry( &nad.ad, ADEID_COMMENT ), fh->comment, 
614             ad_getentrylen( &nad.ad, ADEID_COMMENT ));
615     ad_setentrylen( &nad.ad, ADEID_RFORK, ntohl( fh->forklen[ RESOURCE ] ));
616
617 #if DEBUG
618     fprintf( stderr, "ad_getentrylen\n" );
619     fprintf( stderr, "ADEID_FINDERI\t\t\t%d\n", 
620             ad_getentrylen( &nad.ad, ADEID_FINDERI ));
621     fprintf( stderr, "ADEID_RFORK\t\t\t%d\n", 
622             ad_getentrylen( &nad.ad, ADEID_RFORK ));
623     fprintf( stderr, "ADEID_NAME\t\t\t%d\n",
624             ad_getentrylen( &nad.ad, ADEID_NAME ));
625     fprintf( stderr, "ad_entry of ADEID_NAME\t\t%.*s\n",
626             ad_getentrylen( &nad.ad, ADEID_NAME ), 
627             ad_entry( &nad.ad, ADEID_NAME ));
628     fprintf( stderr, "ADEID_COMMENT\t\t\t%d\n",
629              ad_getentrylen( &nad.ad, ADEID_COMMENT ));
630 #endif /* DEBUG */
631
632     memcpy( &temptime, &fh->create_date, sizeof( temptime ));
633     ad_setdate(&nad.ad, AD_DATE_CREATE, temptime);
634     memcpy( &temptime, &fh->mod_date, sizeof( temptime ));
635     ad_setdate(&nad.ad, AD_DATE_MODIFY, temptime);
636
637 #if DEBUG
638     ad_getdate(&nad.ad, AD_DATE_CREATE, &temptime);
639     temptime = AD_DATE_TO_UNIX(temptime);
640     fprintf(stderr, "FILEIOFF_CREATE seconds\t\t%ld\n", temptime );
641     ad_getdate(&nad.ad, AD_DATE_MODIFY, &temptime);
642     temptime = AD_DATE_TO_UNIX(temptime);
643     fprintf(stderr, "FILEIOFF_MODIFY seconds\t\t%ld\n", temptime );
644 #endif /* DEBUG */
645
646     memset( ad_entry( &nad.ad, ADEID_FINDERI ), 0, ADEDLEN_FINDERI );
647     memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_TYPE, 
648             &fh->finder_info.fdType, sizeof( fh->finder_info.fdType ));
649     memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_CREATOR,
650            &fh->finder_info.fdCreator, sizeof( fh->finder_info.fdCreator ));
651     memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS,
652             &fh->finder_info.fdFlags, sizeof( fh->finder_info.fdFlags ));
653     memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_LOC,
654             &fh->finder_info.fdLocation,sizeof( fh->finder_info.fdLocation ));
655     memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLDR,
656             &fh->finder_info.fdFldr, sizeof( fh->finder_info.fdFldr ));
657     memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_SCRIPT,
658             &fh->finder_xinfo.fdScript, sizeof( fh->finder_xinfo.fdScript ));
659     memcpy( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_XFLAGS,
660             &fh->finder_xinfo.fdXFlags, sizeof( fh->finder_xinfo.fdXFlags));
661
662
663 #if DEBUG
664     {
665         short           flags;
666         memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS),
667                 sizeof( flags ));
668         fprintf( stderr, "nad.ad flags\t\t\t%x\n", flags );
669         fprintf( stderr, "fh flags\t\t\t%x\n", fh->finder_info.fdFlags );
670         fprintf( stderr, "fh xflags\t\t\t%x\n", fh->finder_xinfo.fdXFlags );
671         fprintf( stderr, "type and creator\t\t%.*s\n\n", 
672                 sizeof( fh->finder_info.fdType ) + 
673                 sizeof( fh->finder_info.fdCreator ),
674                 ad_entry( &nad.ad, ADEID_FINDERI ));
675     }
676 #endif /* DEBUG */
677
678 #if HEXOUTPUT
679     hexfork[ DATA ] = open( "datafork", O_WRONLY|O_CREAT, 0622 );
680     hexfork[ RESOURCE ] = open( "resfork", O_WRONLY|O_CREAT, 0622 );
681 #endif /* HEXOUTPUT */
682
683     nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
684     ad_flush( &nad.ad );
685
686     return( 0 );
687 }
688
689 static int              forkeid[] = { ADEID_DFORK, ADEID_RFORK };
690
691 ssize_t nad_read(int fork, char *forkbuf, size_t bufc)
692 {
693     ssize_t             cc = 0;
694
695 #if DEBUG
696     fprintf( stderr, "Entering nad_read\n" );
697 #endif /* DEBUG */
698
699     if (( cc = ad_read( &nad.ad, forkeid[ fork ], nad.offset[ fork ], 
700             forkbuf, bufc)) < 0 )  {
701         perror( "Reading the appledouble file:" );
702         return( cc );
703     }
704     nad.offset[ fork ] += cc;
705
706 #if DEBUG
707     fprintf( stderr, "Exiting nad_read\n" );
708 #endif /* DEBUG */
709
710     return( cc );
711 }
712
713 ssize_t nad_write(int fork, char *forkbuf, size_t bufc)
714 {
715     char                *buf_ptr;
716     size_t              writelen;
717     ssize_t             cc = 0;
718
719 #if DEBUG
720     fprintf( stderr, "Entering nad_write\n" );
721 #endif /* DEBUG */
722
723 #if HEXOUTPUT
724     write( hexfork[ fork ], forkbuf, bufc );
725 #endif /* HEXOUTPUT */
726
727     writelen = bufc;
728     buf_ptr = forkbuf;
729
730     while (( writelen > 0 ) && ( cc >= 0 )) {
731         cc =  ad_write( &nad.ad, forkeid[ fork ], nad.offset[ fork ], 
732                 0, buf_ptr, writelen);
733         nad.offset[ fork ] += cc;
734         buf_ptr += cc;
735         writelen -= cc;
736     }
737     if ( cc < 0 ) {
738         perror( "Writing the appledouble file:" );
739         return( cc );
740     }
741
742     return( bufc );
743 }
744
745 int nad_close(int status)
746 {
747     int                 rv;
748     if ( status == KEEP ) {
749         if (( rv = ad_flush( &nad.ad )) < 0 ) {
750             fprintf( stderr, "nad_close rv for flush %d\n", rv );
751             return( rv );
752         }
753         if (( rv = ad_close( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
754             fprintf( stderr, "nad_close rv for close %d\n", rv );
755             return( rv );
756         }
757     } else if ( status == TRASH ) {
758         if ( unlink( nad.adpath[ 0 ] ) < 0 ) {
759             perror ( nad.adpath[ 0 ] );
760         }
761         if ( unlink( nad.adpath[ 1 ] ) < 0 ) {
762             perror ( nad.adpath[ 1 ] );
763         }
764         return( 0 );
765     } else return( -1 );
766     return( 0 );
767 }