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