]> arthur.barton.de Git - netatalk.git/blob - bin/megatron/nad.c
Check for struct tm.tm_gmtoff instead of defining NO_STRUCT_TM_GMTOFF on
[netatalk.git] / bin / megatron / nad.c
1 /*
2  * $Id: nad.c,v 1.11 2002-04-29 01:52:50 morgana 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 #ifdef HAVE_FCNTL_H
20 #include <fcntl.h>
21 #endif /* HAVE_FCNTL_H */
22
23 #include <atalk/adouble.h>
24 #include <netatalk/endian.h>
25 #include "megatron.h"
26 #include "nad.h"
27
28 static char             hexdig[] = "0123456789abcdef";
29
30 static char mtou_buf[MAXPATHLEN + 1], utom_buf[MAXPATHLEN + 1];
31 static char *mtoupathcap( mpath )
32     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( upath )
68     char        *upath;
69 {
70     char        *m, *u;
71     int h;
72
73     m = utom_buf;
74     u = upath;
75     while ( *u != '\0' ) {
76         if (*u == ':' && *(u + 1) != '\0' && islxdigit(*(u+1)) &&
77             *(u+2) != '\0' && islxdigit(*(u+2))) {
78           u++;
79           h = hextoint(*u) << 4;
80           u++;
81           h |= hextoint(*u);
82           *m = h;
83         } else {
84 #ifdef DOWNCASE
85           *m = diatolower(*u);
86 #else /* DOWNCASE */
87           *m = *u;
88 #endif /* DOWNCASE */
89         }
90         u++;
91         m++;
92     }
93     *m = '\0';
94     return( utom_buf );
95 }
96
97 static void euc2sjis( int *p1, int *p2) /* agrees w/ Samba on valid codes */
98 {
99     int row_offset, cell_offset;
100     unsigned char c1, c2;
101
102     /* first convert EUC to ISO-2022 */
103     c1 = *p1 & 0x7F;
104     c2 = *p2 & 0x7F;
105
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;
109
110     *p1 = ((c1 + 1) >> 1) + row_offset;
111     *p2 = c2 + cell_offset;
112 }
113
114 static void sjis2euc( int *p1, int *p2)  /* agrees w/ Samba on valid codes */
115 {
116     int row_offset, cell_offset, adjust;
117     unsigned char c1, c2;
118
119     c1 = *p1;
120     c2 = *p2;
121
122     /* first convert Shift-JIS to ISO-2022 */
123     adjust = c2 < 159;
124     row_offset = c1 < 160 ? 112 : 176;
125     cell_offset = adjust ? (c2 > 127 ? 32 : 31) : 126;
126
127     c1 = ((c1 - row_offset) << 1) - adjust;
128     c2 -= cell_offset;
129
130     /* now convert ISO-2022 to EUC */
131     *p1 = c1 | 0x80;
132     *p2 = c2 | 0x80;
133 }
134
135 static char *mtoupatheuc( char *from)
136 {
137     unsigned char *in, *out, *maxout;
138     int p, p2, i = 0;
139
140     in = (unsigned char *) from;
141     out = (unsigned char *) mtou_buf;
142
143     if( *in ) {
144         maxout = out + sizeof( mtou_buf) - 3;
145
146         while( out < maxout ) {
147             p = *in++;
148
149             if( ((0x81 <= p) && (p <= 0x9F))
150              || ((0xE0 <= p) && (p <= 0xEF)) ) {
151                 /* JIS X 0208 */
152                 p2 = *in++;
153                 if( ((0x40 <= p2) && (p2 <= 0x7E))
154                  || ((0x80 <= p2) && (p2 <= 0xFC)) )
155                     sjis2euc( &p, &p2);
156                 *out++ = p;
157                 p = p2;
158
159             } else if( (0xA1 <= p) && (p <= 0xDF) ) {
160                 *out++ = 0x8E;  /* halfwidth katakana */
161             } else if( p < 0x80 ) {
162 #ifdef DOWNCASE
163                 p = ( isupper( p )) ? tolower( p ) : p;
164 #endif /* DOWNCASE */
165             }
166             if( ( p == '/') || ( i == 0 && p == '.' ) ) {
167                 *out++ = ':';
168                 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
169                 p = hexdig[ p & 0x0f ];
170             }
171             i++;
172             *out++ = p;
173             if( p )
174                 continue;
175             break;
176         }
177     } else {
178         *out++ = '.';
179         *out = 0;
180     }
181
182     return mtou_buf;
183 }
184
185 static char *utompatheuc( char *from)
186 {
187     unsigned char *in, *out, *maxout;
188     int p, p2;
189
190     in = (unsigned char *) from;
191     out = (unsigned char *) utom_buf;
192     maxout = out + sizeof( utom_buf) - 3;
193
194     while( out < maxout ) {
195         p = *in++;
196
197         if( (0xA1 <= p) && (p <= 0xFE) ) {      /* JIS X 0208 */
198             p2 = *in++;
199             if( (0xA1 <= p2) && (p2 <= 0xFE) )
200                 euc2sjis( &p, &p2);
201             *out++ = p;
202             p = p2;
203         } else if( p == 0x8E ) {                /* halfwidth katakana */
204             p = *in++;
205         } else if( p < 0x80 ) {
206 #ifdef DOWNCASE
207             p = ( isupper( p )) ? tolower( p ) : p;
208 #endif /* DOWNCASE */
209         }
210         if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
211                 *(in+1) != '\0' && islxdigit( *(in+1))) {
212            p = hextoint( *in ) << 4;
213            in++;
214            p |= hextoint( *in );
215            in++;
216         }
217         *out++ = p;
218         if( p )
219             continue;
220         break;
221     }
222
223     return utom_buf;
224 }
225
226 static char *mtoupathsjis( char *from)
227 {
228     unsigned char *in, *out, *maxout;
229     int p, p2, i = 0;
230
231     in = (unsigned char *) from;
232     out = (unsigned char *) mtou_buf;
233
234     if( *in ) {
235         maxout = out + sizeof( mtou_buf) - 3;
236
237         while( out < maxout ) {
238             p = *in++;
239
240             if( ((0x81 <= p) && (p <= 0x9F))
241              || ((0xE0 <= p) && (p <= 0xEF)) ) {
242                 /* JIS X 0208 */
243                 p2 = *in++;
244                 *out++ = p;
245                 p = p2;
246
247             } else if( (0xA1 <= p) && (p <= 0xDF) ) {
248                 ;       /* halfwidth katakana */
249             } else if(p < 0x80 ) {
250 #ifdef DOWNCASE
251                 p = ( isupper( p )) ? tolower( p ) : p;
252 #endif /* DOWNCASE */
253             }
254             if( ( p == '/') || ( i == 0 && p == '.' ) ) {
255                 *out++ = ':';
256                 *out++ = hexdig[ ( p & 0xf0 ) >> 4 ];
257                 p = hexdig[ p & 0x0f ];
258             }
259             i++;
260             *out++ = p;
261             if( p )
262                 continue;
263             break;
264         }
265     } else {
266         *out++ = '.';
267         *out = 0;
268     }
269
270     return mtou_buf;
271 }
272
273 static char *utompathsjis( char *from)
274 {
275     unsigned char *in, *out, *maxout;
276     int p, p2;
277
278     in = (unsigned char *) from;
279     out = (unsigned char *) utom_buf;
280     maxout = out + sizeof( utom_buf) - 3;
281
282     while( out < maxout ) {
283         p = *in++;
284
285         if( (0xA1 <= p) && (p <= 0xFE) ) {      /* JIS X 0208 */
286             p2 = *in++;
287             *out++ = p;
288             p = p2;
289         } else if( p == 0x8E ) {                /* do nothing */
290             ;
291         } else if( p < 0x80 ) {
292 #ifdef DOWNCASE
293            p = ( isupper( p )) ? tolower( p ) : p;
294 #endif /* DOWNCASE */
295         }
296         if ( p == ':' && *(in) != '\0' && islxdigit( *(in)) &&
297                 *(in+1) != '\0' && islxdigit( *(in+1))) {
298            p = hextoint( *in ) << 4;
299            in++;
300            p |= hextoint( *in );
301            in++;
302         }
303         *out++ = p;
304         if( p )
305             continue;
306         break;
307     }
308
309     return utom_buf;
310  }
311  
312 char * (*_mtoupath) ( char *mpath) = mtoupathcap;
313 char * (*_utompath) ( char *upath) = utompathcap;
314
315 /* choose translators for optional character set */
316 void select_charset( int options)
317 {
318
319     if( options & OPTION_EUCJP ) {
320         _mtoupath = mtoupatheuc;
321         _utompath = utompatheuc;
322     } else if( options & OPTION_SJIS ) {
323         _mtoupath = mtoupathsjis;
324         _utompath = utompathsjis;
325     } else {
326         _mtoupath = mtoupathcap;
327         _utompath = utompathcap;
328     }
329 }
330
331
332 #if HEXOUTPUT
333     int                 hexfork[ NUMFORKS ];
334 #endif /* HEXOUTPUT */
335
336 struct nad_file_data {
337     char                macname[ MAXPATHLEN + 1 ];
338     char                adpath[ 2 ][ MAXPATHLEN + 1];
339     int                 offset[ NUMFORKS ];
340     struct adouble      ad;
341 } nad;
342
343 int nad_open( path, openflags, fh, options )
344     char                *path;
345     int                 openflags, options;
346     struct FHeader      *fh;
347 {
348     struct stat         st;
349     int                 fork;
350
351 /*
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.
355  */
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 );
366                 } else {
367                     perror( "stat of adouble file failed" );
368                 }
369                 return( -1 );
370             }
371         }
372
373 #if DEBUG
374     fprintf(stderr, "%s is adpath[0]\n", nad.adpath[0]);
375     fprintf(stderr, "%s is adpath[1]\n", nad.adpath[1]);
376 #endif /* DEBUG */
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 ] );
380             return( -1 );
381         }
382         return( nad_header_read( fh ));
383
384     } else {
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 ));
389 #if DEBUG
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]);
393 #endif /* DEBUG */
394         if ( stat( ".", &st ) < 0 ) {
395             perror( "stat of . failed" );
396             return( -1 );
397         }
398         (void)umask( 0 );
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 ] );
402             return( -1 );
403         }
404         return( nad_header_write( fh ));
405     }
406 }
407
408 int nad_header_read( fh )
409     struct FHeader      *fh;
410 {
411     u_int32_t           temptime;
412     struct stat         st;
413
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 );
418
419     /* just in case there's nothing in macname */
420     if (*fh->name == '\0')
421       strcpy(fh->name, utompath(nad.adpath[DATA]));
422
423     if ( stat( nad.adpath[ DATA ], &st ) < 0 ) {
424         perror( "stat of datafork failed" );
425         return( -1 );
426     }
427     fh->forklen[ DATA ] = htonl( st.st_size );
428     fh->forklen[ RESOURCE ] = htonl( ad_getentrylen( &nad.ad, ADEID_RFORK ));
429     fh->comment[0] = '\0';
430
431 #if DEBUG
432     fprintf( stderr, "macname of file\t\t\t%.*s\n", strlen( fh->name ), 
433             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 );
439 #endif /* DEBUG */
440
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 ));
447
448 #if DEBUG
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 ));
459 #endif /* DEBUG */
460
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));
482
483 #if DEBUG
484     {
485         short           flags;
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);
501     }
502 #endif /* DEBUG */
503
504     nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
505
506     return( 0 );
507
508 }
509
510 int nad_header_write( fh )
511     struct FHeader      *fh;
512 {
513     u_int32_t           temptime;
514
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 ] ));
522
523 #if DEBUG
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 ));
536 #endif /* DEBUG */
537
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);
542
543 #if DEBUG
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 );
550 #endif /* DEBUG */
551
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));
567
568
569 #if DEBUG
570     {
571         short           flags;
572         memcpy(&flags, ( ad_entry( &nad.ad, ADEID_FINDERI ) + FINDERIOFF_FLAGS),
573                 sizeof( 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 ));
581     }
582 #endif /* DEBUG */
583
584 #if HEXOUTPUT
585     hexfork[ DATA ] = open( "datafork", O_WRONLY|O_CREAT, 0622 );
586     hexfork[ RESOURCE ] = open( "resfork", O_WRONLY|O_CREAT, 0622 );
587 #endif /* HEXOUTPUT */
588
589     nad.offset[ DATA ] = nad.offset[ RESOURCE ] = 0;
590     ad_flush( &nad.ad, ADFLAGS_DF|ADFLAGS_HF );
591
592     return( 0 );
593 }
594
595 int                     forkeid[] = { ADEID_DFORK, ADEID_RFORK };
596
597 int nad_read( fork, forkbuf, bufc )
598     int                 fork;
599     char                *forkbuf;
600     int                 bufc;
601 {
602     int                 cc = 0;
603
604 #if DEBUG
605     fprintf( stderr, "Entering nad_read\n" );
606 #endif /* DEBUG */
607
608     if (( cc = ad_read( &nad.ad, forkeid[ fork ], nad.offset[ fork ], 
609             forkbuf, bufc)) < 0 )  {
610         perror( "Reading the appledouble file:" );
611         return( cc );
612     }
613     nad.offset[ fork ] += cc;
614
615 #if DEBUG
616     fprintf( stderr, "Exiting nad_read\n" );
617 #endif /* DEBUG */
618
619     return( cc );
620 }
621
622 int nad_write( fork, forkbuf, bufc )
623     int                 fork;
624     char                *forkbuf;
625     int                 bufc;
626 {
627     char                *buf_ptr;
628     int                 writelen;
629     int                 cc = 0;
630
631 #if DEBUG
632     fprintf( stderr, "Entering nad_write\n" );
633 #endif /* DEBUG */
634
635 #if HEXOUTPUT
636     write( hexfork[ fork ], forkbuf, bufc );
637 #endif /* HEXOUTPUT */
638
639     writelen = bufc;
640     buf_ptr = forkbuf;
641
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;
646         buf_ptr += cc;
647         writelen -= cc;
648     }
649     if ( cc < 0 ) {
650         perror( "Writing the appledouble file:" );
651         return( cc );
652     }
653
654     return( bufc );
655 }
656
657 int nad_close( status )
658 int                     status;
659 {
660     int                 rv;
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 );
664             return( rv );
665         }
666         if (( rv = ad_close( &nad.ad, ADFLAGS_DF|ADFLAGS_HF )) < 0 ) {
667             fprintf( stderr, "nad_close rv for close %d\n", rv );
668             return( rv );
669         }
670     } else if ( status == TRASH ) {
671         if ( unlink( nad.adpath[ 0 ] ) < 0 ) {
672             perror ( nad.adpath[ 0 ] );
673         }
674         if ( unlink( nad.adpath[ 1 ] ) < 0 ) {
675             perror ( nad.adpath[ 1 ] );
676         }
677         return( 0 );
678     } else return( -1 );
679     return( 0 );
680 }