]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/fork.c
removed unneeded cnid_lookups; fixed a bug in afp_createid.
[netatalk.git] / etc / afpd / fork.c
1 /*
2  * $Id: fork.c,v 1.8 2001-08-27 15:26:16 uhees Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif /* HAVE_UNISTD_H */
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif /* HAVE_FCNTL_H */
19 #include <dirent.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <syslog.h>
23
24 #include <sys/param.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/socket.h>
29
30 #include <netatalk/endian.h>
31 #include <netatalk/at.h>
32
33 #include <atalk/dsi.h>
34 #include <atalk/atp.h>
35 #include <atalk/asp.h>
36 #include <atalk/afp.h>
37 #include <atalk/adouble.h>
38 #include <atalk/util.h>
39 #ifdef CNID_DB
40 #include <atalk/cnid.h>
41 #endif
42
43 #include "fork.h"
44 #include "file.h"
45 #include "globals.h"
46 #include "directory.h"
47 #include "desktop.h"
48 #include "volume.h"
49
50 #define BYTELOCK_MAX 0x7FFFFFFFU
51
52 struct ofork            *writtenfork;
53
54 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
55     struct ofork        *ofork;
56     u_int16_t           bitmap;
57     char                *buf;
58     int                 *buflen;
59     const u_int16_t     attrbits;
60 {
61     struct stat         st;
62     struct extmap       *em;
63     char                *data, *nameoff = NULL, *upath;
64     int                 bit = 0, isad = 1;
65     u_int32_t           aint;
66     u_int16_t           ashort;
67
68     if ( ad_hfileno( ofork->of_ad ) == -1 ) {
69         isad = 0;
70     } else {
71         aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
72         if ( ad_refresh( ofork->of_ad ) < 0 ) {
73             syslog( LOG_ERR, "getforkparams: ad_refresh: %s", strerror(errno) );
74             return( AFPERR_PARAM );
75         }
76         /* See afp_closefork() for why this is bad */
77         ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
78     }
79
80     /* can only get the length of the opened fork */
81     if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
82         ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
83         return( AFPERR_BITMAP );
84     }
85
86     if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
87                     (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
88                     (1 << FILPBIT_BDATE))) {
89         upath = mtoupath(ofork->of_vol, ofork->of_name);
90         if ( ad_dfileno( ofork->of_ad ) == -1 ) {
91            if ( stat( upath, &st ) < 0 )
92                return( AFPERR_NOOBJ );
93         } else {
94             if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
95                 return( AFPERR_BITMAP );
96             }
97         }
98     }
99
100     data = buf;
101     while ( bitmap != 0 ) {
102         while (( bitmap & 1 ) == 0 ) {
103             bitmap = bitmap>>1;
104             bit++;
105         }
106
107         switch ( bit ) {
108         case FILPBIT_ATTR :
109             if ( isad ) {
110                 ad_getattr(ofork->of_ad, &ashort);
111             } else {
112                 ashort = 0;
113             }
114             if (attrbits)
115               ashort = htons(ntohs(ashort) | attrbits);
116             memcpy(data, &ashort, sizeof( ashort ));
117             data += sizeof( ashort );
118             break;
119
120         case FILPBIT_PDID :
121             memcpy(data, &ofork->of_dir->d_did, sizeof( aint ));
122             data += sizeof( aint );
123             break;
124
125         case FILPBIT_CDATE :
126             if (!isad ||
127                  (ad_getdate(ofork->of_ad, AD_DATE_CREATE, &aint) < 0))
128                 aint = AD_DATE_FROM_UNIX(st.st_mtime);
129             memcpy(data, &aint, sizeof( aint ));
130             data += sizeof( aint );
131             break;
132
133         case FILPBIT_MDATE :
134             if (!isad || 
135                 (ad_getdate(ofork->of_ad, AD_DATE_MODIFY, &aint) < 0) ||
136                 (AD_DATE_TO_UNIX(aint) < st.st_mtime))
137                 aint = AD_DATE_FROM_UNIX(st.st_mtime);
138             memcpy(data, &aint, sizeof( aint ));
139             data += sizeof( aint );
140             break;
141
142         case FILPBIT_BDATE :
143             if (!isad ||
144                 (ad_getdate(ofork->of_ad, AD_DATE_BACKUP, &aint) < 0))
145                 aint = AD_DATE_START;
146             memcpy(data, &aint, sizeof( aint ));
147             data += sizeof( aint );
148             break;
149
150         case FILPBIT_FINFO :
151             memcpy(data, isad ? 
152                    (void *) ad_entry(ofork->of_ad, ADEID_FINDERI) :
153                    (void *) ufinderi, 32);
154             if ( !isad || 
155                  memcmp( ad_entry( ofork->of_ad, ADEID_FINDERI ),
156                          ufinderi, 8 ) == 0 ) {
157                 memcpy(data, ufinderi, 8 );
158                 if (( em = getextmap( ofork->of_name )) != NULL ) {
159                     memcpy(data, em->em_type, sizeof( em->em_type ));
160                     memcpy(data + 4, em->em_creator,
161                             sizeof( em->em_creator ));
162                 }
163             }
164             data += 32;
165             break;
166
167         case FILPBIT_LNAME :
168             nameoff = data;
169             data += sizeof(u_int16_t);
170             break;
171
172         case FILPBIT_SNAME :
173             memset(data, 0, sizeof(u_int16_t));
174             data += sizeof(u_int16_t);
175             break;
176
177         case FILPBIT_FNUM :
178                 aint = 0;
179 #if AD_VERSION > AD_VERSION1
180         /* look in AD v2 header */
181         if (isad)
182                 memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint));
183 #endif /* AD_VERSION > AD_VERSION1 */
184
185 #ifdef CNID_DB
186         aint = cnid_add(ofork->of_vol->v_db, &st,
187                                   ofork->of_dir->d_did,
188                                   upath, strlen(upath), aint);
189 #endif /* CNID_DB */
190
191                 if (aint == 0) {
192 #ifdef AFS
193               aint = st.st_ino;
194 #else /* AFS */
195               aint = ( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff );
196 #endif /* AFS */
197             }
198
199                 memcpy(data, &aint, sizeof( aint ));
200             data += sizeof( aint );
201             break;
202
203         case FILPBIT_DFLEN :
204             aint = htonl( st.st_size );
205             memcpy(data, &aint, sizeof( aint ));
206             data += sizeof( aint );
207             break;
208
209         case FILPBIT_RFLEN :
210             if ( isad ) {
211                 aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK ));
212             } else {
213                 aint = 0;
214             }
215             memcpy(data, &aint, sizeof( aint ));
216             data += sizeof( aint );
217             break;
218
219         default :
220             return( AFPERR_BITMAP );
221         }
222         bitmap = bitmap>>1;
223         bit++;
224     }
225
226     if ( nameoff ) {
227         ashort = htons( data - buf );
228         memcpy(nameoff, &ashort, sizeof( ashort ));
229         aint = strlen( ofork->of_name );
230         aint = ( aint > MACFILELEN ) ? MACFILELEN : aint;
231         *data++ = aint;
232         memcpy(data, ofork->of_name, aint );
233         data += aint;
234     }
235
236     *buflen = data - buf;
237     return( AFP_OK );
238 }
239
240 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
241     AFPObj      *obj;
242     char        *ibuf, *rbuf;
243     int         ibuflen, *rbuflen;
244 {
245     struct vol          *vol;
246     struct dir          *dir;
247     struct ofork        *ofork, *opened;
248     struct adouble      *adsame = NULL;
249     int                 buflen, ret, adflags, eid, lockop;
250     u_int32_t           did;
251     u_int16_t           vid, bitmap, access, ofrefnum, attrbits = 0;
252     char                fork, *path, *upath; 
253
254     ibuf++;
255     fork = *ibuf++;
256     memcpy(&vid, ibuf, sizeof( vid ));
257     ibuf += sizeof(vid);
258
259     *rbuflen = 0;
260     if (( vol = getvolbyvid( vid )) == NULL ) {
261         return( AFPERR_PARAM );
262     }
263
264     memcpy(&did, ibuf, sizeof( did ));
265     ibuf += sizeof( int );
266
267     if (( dir = dirsearch( vol, did )) == NULL ) {
268         return( AFPERR_NOOBJ );
269     }
270
271     memcpy(&bitmap, ibuf, sizeof( bitmap ));
272     bitmap = ntohs( bitmap );
273     ibuf += sizeof( bitmap );
274     memcpy(&access, ibuf, sizeof( access ));
275     access = ntohs( access );
276     ibuf += sizeof( access );
277
278     if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
279         return AFPERR_VLOCK;
280     }
281
282     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
283         return( AFPERR_NOOBJ );
284     }
285
286     if ( fork == OPENFORK_DATA ) {
287         eid = ADEID_DFORK;
288         adflags = ADFLAGS_DF|ADFLAGS_HF;
289     } else {
290         eid = ADEID_RFORK;
291         adflags = ADFLAGS_HF;
292     }
293         
294     /* XXX: this probably isn't the best way to do this. the already
295        open bits should really be set if the fork is opened by any
296        program, not just this one. however, that's problematic to do
297        if we can't write lock files somewhere. opened is also passed to 
298        ad_open so that we can keep file locks together. */
299     if ((opened = of_findname(vol, curdir, path))) {
300       attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) | 
301         ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
302       adsame = opened->of_ad;
303     }
304
305     if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
306                            adsame)) == NULL ) {
307         return( AFPERR_NFILE );
308     }
309
310     /* try opening in read-write mode with a fallback to read-only 
311      * if we don't need write access. */
312     upath = mtoupath(vol, path);
313     ret = AFPERR_NOOBJ;
314     if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
315        switch ( errno ) {
316        case EROFS:
317          ret = AFPERR_VLOCK;
318        case EACCES: 
319          if (access & OPENACC_WR)
320            goto openfork_err;
321          
322          if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
323            /* check for a read-only data fork */
324            if ((adflags != ADFLAGS_HF) &&
325                (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
326              goto openfork_err;
327
328            adflags = ADFLAGS_DF;               
329          }
330          break;
331        case ENOENT:
332          { 
333            struct stat st;
334            
335            /* see if client asked for the data fork */
336            if (fork == OPENFORK_DATA) {
337              if (((access & OPENACC_WR) && 
338                   (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0)) 
339                  || (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, 
340                              ofork->of_ad) < 0)) {
341                goto openfork_err;
342              }
343              adflags = ADFLAGS_DF;
344              
345            } else if (stat(upath, &st) == 0) {
346              /* here's the deal. we only try to create the resource
347               * fork if the user wants to open it for write access. */
348              if ((access & OPENACC_WR) && 
349                  (ad_open(upath, adflags, O_RDWR | O_CREAT, 
350                           0666, ofork->of_ad) < 0))
351                goto openfork_err;
352            } else 
353              goto openfork_err;
354          }
355          break;
356        case EMFILE :
357        case ENFILE :
358          ret = AFPERR_NFILE;
359          goto openfork_err;
360          break;
361        case EISDIR :
362          ret = AFPERR_BADTYPE;
363          goto openfork_err;
364          break;
365        default:
366          syslog( LOG_ERR, "afp_openfork: ad_open: %s", strerror(errno) );
367          ret = AFPERR_PARAM;
368          goto openfork_err;
369          break;
370        }
371     }
372
373     if ((adflags & ADFLAGS_HF) &&
374         (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
375         ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
376         memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path, 
377                ad_getentrylen( ofork->of_ad, ADEID_NAME ));
378         ad_flush( ofork->of_ad, adflags );
379     }
380
381     if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
382                               &buflen, attrbits )) != AFP_OK ) {
383         ad_close( ofork->of_ad, adflags );
384         goto openfork_err;
385     }
386
387     *rbuflen = buflen + 2 * sizeof( u_int16_t );
388     bitmap = htons( bitmap );
389     memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
390     rbuf += sizeof( u_int16_t );
391
392     /*
393      * synchronization locks:
394      *
395      * here's the ritual:
396      *  1) attempt a read lock to see if we have read or write
397      *     privileges.
398      *  2) if that succeeds, set a write lock to correspond to the
399      *     deny mode requested.
400      *  3) whenever a file is read/written, locks get set which
401      *     prevent conflicts.
402      */
403
404     /* don't try to lock non-existent rforks. */
405     if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
406
407       /* try to see if we have access. */
408       ret = 0;
409       if (access & OPENACC_WR) {
410         ofork->of_flags |= AFPFORK_ACCWR;
411         ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK, 
412                       AD_FILELOCK_WR, 1, ofrefnum);
413       } 
414
415       if (!ret && (access & OPENACC_RD)) {
416         ofork->of_flags |= AFPFORK_ACCRD;
417         ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK, 
418                       AD_FILELOCK_RD, 1, ofrefnum);
419       }
420     
421       /* can we access the fork? */
422       if (ret < 0) {
423         ad_close( ofork->of_ad, adflags );
424         of_dealloc( ofork );
425         ofrefnum = 0;
426         memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
427         return (AFPERR_DENYCONF);
428       }
429       
430       /* now try to set the deny lock. if the fork is open for read or
431        * write, a read lock will already have been set. otherwise, we upgrade
432        * our lock to a write lock. 
433        *
434        * NOTE: we can't write lock a read-only file. on those, we just
435        * make sure that we have a read lock set. that way, we at least prevent
436        * someone else from really setting a deny read/write on the file. */
437       lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ? 
438         ADLOCK_WR : ADLOCK_RD;
439       ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid, 
440                                              lockop | ADLOCK_FILELOCK |
441                                              ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
442                                              ofrefnum) : 0;
443       if (!ret && (access & OPENACC_DRD))
444         ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
445                       ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
446       
447       if (ret < 0) {
448         ret = errno;
449         ad_close( ofork->of_ad, adflags );
450         of_dealloc( ofork );
451         switch (ret) {
452         case EAGAIN: /* return data anyway */
453         case EACCES:
454         case EINVAL:
455           ofrefnum = 0;
456           memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
457           return( AFPERR_DENYCONF );
458           break;
459         default:
460           *rbuflen = 0;
461           syslog( LOG_ERR, "afp_openfork: ad_lock: %s", strerror(errno) );
462           return( AFPERR_PARAM );
463         }
464       }
465     }
466
467     memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
468     return( AFP_OK );
469
470 openfork_err:
471     of_dealloc( ofork );
472     if (errno == EACCES)
473       return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
474     return ret;
475 }
476
477 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
478     AFPObj      *obj;
479     char        *ibuf, *rbuf;
480     int         ibuflen, *rbuflen;
481 {
482     struct ofork        *ofork;
483     int32_t             size;
484     u_int16_t           ofrefnum, bitmap;
485     int                 err;
486
487     ibuf += 2;
488     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
489     ibuf += sizeof( ofrefnum );
490     memcpy(&bitmap, ibuf, sizeof(bitmap));
491     bitmap = ntohs(bitmap);
492     ibuf += sizeof( bitmap );
493     memcpy(&size, ibuf, sizeof( size ));
494     size = ntohl( size );
495
496     *rbuflen = 0;
497     if (( ofork = of_find( ofrefnum )) == NULL ) {
498         syslog( LOG_ERR, "afp_setforkparams: of_find: %s", strerror(errno) );
499         return( AFPERR_PARAM );
500     }
501
502     if (ofork->of_vol->v_flags & AFPVOL_RO)
503         return AFPERR_VLOCK;
504
505     if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
506         return AFPERR_ACCESS;
507
508     if (size < 0)
509         return AFPERR_PARAM;
510       
511     if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
512         err = ad_dtruncate( ofork->of_ad, size );
513         if (err < 0)
514           goto afp_setfork_err;
515     } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
516                (ofork->of_flags & AFPFORK_RSRC)) {
517         ad_refresh( ofork->of_ad );
518         err = ad_rtruncate(ofork->of_ad, size);
519         if (err < 0)
520           goto afp_setfork_err;
521         
522         if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
523             syslog( LOG_ERR, "afp_setforkparams: ad_flush: %s",
524                     strerror(errno) );
525             return( AFPERR_PARAM );
526         }
527     } else
528       return AFPERR_BITMAP;
529
530 #ifdef AFS
531     if ( flushfork( ofork ) < 0 ) {
532         syslog( LOG_ERR, "afp_setforkparams: flushfork: %m" );
533     }
534 #endif /* AFS */
535
536     return( AFP_OK );
537
538 afp_setfork_err:
539     if (err == -2) 
540       return AFPERR_LOCK;
541     else {
542       switch (errno) {
543       case EROFS:
544         return AFPERR_VLOCK;
545       case EPERM:
546       case EACCES:
547         return AFPERR_ACCESS;
548       case EDQUOT:
549       case EFBIG:
550       case ENOSPC:
551         return AFPERR_DFULL;
552       default:
553         return AFPERR_PARAM;
554       }
555     }
556 }
557
558 /* for this to work correctly, we need to check for locks before each
559  * read and write. that's most easily handled by always doing an
560  * appropriate check before each ad_read/ad_write. other things
561  * that can change files like truncate are handled internally to those
562  * functions. 
563  */
564 #define ENDBIT(a)  ((a) & 0x80)
565 #define UNLOCKBIT(a) ((a) & 0x01)
566 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
567     AFPObj      *obj;
568     char        *ibuf, *rbuf;
569     int         ibuflen, *rbuflen;
570 {
571     struct ofork        *ofork;
572     int32_t             offset, length;
573     int                 eid;
574     u_int16_t           ofrefnum;
575     u_int8_t            flags;
576
577     *rbuflen = 0;
578
579     /* figure out parameters */
580     ibuf++;
581     flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
582     ibuf++;
583     memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
584     ibuf += sizeof(ofrefnum);
585
586     if (( ofork = of_find( ofrefnum )) == NULL ) {
587         syslog( LOG_ERR, "afp_bytelock: of_find: %s", strerror(errno) );
588         return( AFPERR_PARAM );
589     }
590
591     if ( ofork->of_flags & AFPFORK_DATA) {
592         eid = ADEID_DFORK;
593     } else if (ofork->of_flags & AFPFORK_RSRC) {
594         eid = ADEID_RFORK;
595     } else 
596         return AFPERR_PARAM;
597
598     memcpy(&offset, ibuf, sizeof( offset ));
599     offset = ntohl(offset);
600     ibuf += sizeof(offset);
601
602     memcpy(&length, ibuf, sizeof( length ));
603     length = ntohl(length);
604     if (length == 0xFFFFFFFF) 
605       length = BYTELOCK_MAX;
606     else if (length <= 0) {
607       return AFPERR_PARAM;
608     } else if ((length >= AD_FILELOCK_BASE) && 
609                (ad_hfileno(ofork->of_ad) == -1))
610       return AFPERR_LOCK;
611
612     if (ENDBIT(flags)) 
613       offset += ad_size(ofork->of_ad, eid);
614
615     if (offset < 0)    /* error if we have a negative offset */
616       return AFPERR_PARAM;
617
618     /* if the file is a read-only file, we use read locks instead of
619      * write locks. that way, we can prevent anyone from initiating
620      * a write lock. */
621     if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR : 
622                 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ? 
623                  ADLOCK_WR : ADLOCK_RD), offset, length, 
624                 ofork->of_refnum) < 0) {
625       switch (errno) {
626       case EACCES:
627       case EAGAIN:
628         return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
629         break;
630       case ENOLCK:
631         return AFPERR_NLOCK;
632         break;
633       case EINVAL: 
634         return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
635         break;
636       case EBADF:
637       default: 
638         return AFPERR_PARAM;
639         break;
640       }
641     }
642
643     offset = htonl(offset);
644     memcpy(rbuf, &offset, sizeof( offset ));
645     *rbuflen = sizeof( offset );
646     return( AFP_OK );
647 }
648 #undef UNLOCKBIT
649
650
651 static __inline__ int crlf( of )
652     struct ofork        *of;
653 {
654     struct extmap       *em;
655
656     if ( ad_hfileno( of->of_ad ) == -1 ||
657          memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ), 
658                  8) == 0 ) {
659         if (( em = getextmap( of->of_name )) == NULL ||
660                 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
661             return( 1 );
662         } else {
663             return( 0 );
664         }
665     } else {
666       if ( memcmp( ufinderi, 
667                    ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
668             return( 1 );
669         } else {
670             return( 0 );
671         }
672     }
673 }
674
675
676 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
677                                     int offset, u_char nlmask, 
678                                     u_char nlchar, char *rbuf, 
679                                     int *rbuflen, const int xlate)
680
681     ssize_t cc;
682     int eof = 0;
683     char *p, *q;
684
685     cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
686     if ( cc < 0 ) {
687         syslog( LOG_ERR, "afp_read: ad_read: %s", strerror(errno) );
688         *rbuflen = 0;
689         return( AFPERR_PARAM );
690     }
691     if ( cc < *rbuflen ) {
692         eof = 1;
693     }
694
695     /*
696      * Do Newline check.
697      */
698     if ( nlmask != 0 ) {
699         for ( p = rbuf, q = p + cc; p < q; ) {
700             if (( *p++ & nlmask ) == nlchar ) {
701                 break;
702             }
703         }
704         if ( p != q ) {
705             cc = p - rbuf;
706             eof = 0;
707         }
708     }
709
710     /*
711      * If this file is of type TEXT, then swap \012 to \015.
712      */
713     if (xlate) {
714         for ( p = rbuf, q = p + cc; p < q; p++ ) {
715             if ( *p == '\012' ) {
716                 *p = '\015';
717             } else if ( *p == '\015' ) {
718                 *p = '\012';
719             }
720               
721         }
722     }
723
724     *rbuflen = cc;
725     if ( eof ) {
726         return( AFPERR_EOF );
727     }
728     return AFP_OK;
729 }
730
731 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
732     AFPObj      *obj;
733     char        *ibuf, *rbuf;
734     int         ibuflen, *rbuflen;
735 {
736     struct ofork        *ofork;
737     off_t               size;
738     int32_t             offset, saveoff, reqcount;
739     int                 cc, err, eid, xlate = 0;
740     u_int16_t           ofrefnum;
741     u_char              nlmask, nlchar;
742
743     ibuf += 2;
744     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
745     ibuf += sizeof( u_short );
746
747     if (( ofork = of_find( ofrefnum )) == NULL ) {
748         syslog( LOG_ERR, "afp_read: of_find: %s", strerror(errno) );
749         err = AFPERR_PARAM;
750         goto afp_read_err;
751     }
752
753     if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
754         err = AFPERR_ACCESS;
755         goto afp_read_err;
756     }
757
758     memcpy(&offset, ibuf, sizeof( offset ));
759     offset = ntohl( offset );
760     ibuf += sizeof( offset );
761     memcpy(&reqcount, ibuf, sizeof( reqcount ));
762     reqcount = ntohl( reqcount );
763     ibuf += sizeof( reqcount );
764
765     nlmask = *ibuf++;
766     nlchar = *ibuf++;
767
768     /* if we wanted to be picky, we could add in the following
769      * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
770      */
771     if (reqcount < 0 || offset < 0) {
772       err = AFPERR_PARAM;
773       goto afp_read_err;
774     }
775
776     if ( ofork->of_flags & AFPFORK_DATA) {
777         eid = ADEID_DFORK;
778         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
779     } else if (ofork->of_flags & AFPFORK_RSRC) {
780         eid = ADEID_RFORK;
781     } else { /* fork wasn't opened. this should never really happen. */
782         err = AFPERR_ACCESS;
783         goto afp_read_err;
784     }
785
786     /* zero request count */
787     if (!reqcount) {
788       err = AFP_OK;
789       goto afp_read_err;
790     }
791
792     /* reqcount isn't always truthful. we need to deal with that. */
793     if ((size = ad_size(ofork->of_ad, eid)) == 0) {
794       err = AFPERR_EOF;
795       goto afp_read_err;
796     }
797
798     saveoff = offset;
799     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
800       err = AFPERR_LOCK;
801       goto afp_read_err;
802     }      
803
804 #define min(a,b)        ((a)<(b)?(a):(b))
805     *rbuflen = min( reqcount, *rbuflen );
806     err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
807                     xlate);
808     if (err < 0) 
809       goto afp_read_done;
810
811     /* dsi can stream requests. we can only do this if we're not checking
812      * for an end-of-line character. oh well. */
813     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
814       DSI *dsi = obj->handle;
815       
816       /* subtract off the offset */
817       size -= offset;
818       if (reqcount > size) {
819         reqcount = size;
820         err = AFPERR_EOF;
821       }
822
823       if (obj->options.flags & OPTION_DEBUG) {
824         printf( "(read) reply: %d/%d, %d\n", *rbuflen,
825                 reqcount, dsi->clientID);
826         bprint(rbuf, *rbuflen);
827       }
828
829       offset += *rbuflen;
830
831       /* dsi_readinit() returns size of next read buffer. by this point,
832        * we know that we're sending some data. if we fail, something
833        * horrible happened. */
834       if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) 
835         goto afp_read_exit;
836       
837       /* due to the nature of afp packets, we have to exit if we get
838          an error. we can't do this with translation on. */
839 #ifdef HAVE_SENDFILE_READ
840       if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
841         if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, 
842                         dsi->datasize) < 0) {
843           if (errno == EINVAL)
844             goto afp_read_loop;
845           else {
846             syslog(LOG_ERR, "afp_read: ad_readfile: %s", strerror(errno));
847             goto afp_read_exit;
848           }
849         }
850
851         dsi_readdone(dsi);
852         goto afp_read_done;
853       }
854
855 afp_read_loop:
856 #endif /* HAVE_SENDFILE_READ */
857
858       /* fill up our buffer. */
859       while (*rbuflen > 0) {
860         cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, 
861                        rbuflen, xlate);
862         if (cc < 0) 
863           goto afp_read_exit;
864
865         offset += *rbuflen;
866         if (obj->options.flags & OPTION_DEBUG) {
867           printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
868           bprint(rbuf, *rbuflen);
869         }
870
871         /* dsi_read() also returns buffer size of next allocation */
872         cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
873         if (cc < 0) 
874           goto afp_read_exit;
875         *rbuflen = cc;
876       }
877       dsi_readdone(dsi);
878       goto afp_read_done;
879
880 afp_read_exit:
881       syslog(LOG_ERR, "afp_read: %s", strerror(errno));
882       dsi_readdone(dsi);
883       ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
884       obj->exit(1);
885     }
886
887 afp_read_done:
888     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
889     return err;
890
891 afp_read_err:
892     *rbuflen = 0;
893     return err;
894 }
895
896 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
897     AFPObj      *obj;
898     char        *ibuf, *rbuf;
899     int         ibuflen, *rbuflen;
900 {
901     struct vol *vol;
902     u_int16_t vid;
903
904     *rbuflen = 0;
905     ibuf += 2;
906
907     memcpy(&vid, ibuf, sizeof(vid));
908     if (( vol = getvolbyvid( vid )) == NULL ) {
909         return( AFPERR_PARAM );
910     }
911
912     of_flush(vol);
913     return( AFP_OK );
914 }
915
916 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
917     AFPObj      *obj;
918     char        *ibuf, *rbuf;
919     int         ibuflen, *rbuflen;
920 {
921     struct ofork        *ofork;
922     u_int16_t           ofrefnum;
923
924     *rbuflen = 0;
925     ibuf += 2;
926     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
927
928     if (( ofork = of_find( ofrefnum )) == NULL ) {
929         syslog( LOG_ERR, "afp_flushfork: of_find: %s", strerror(errno) );
930         return( AFPERR_PARAM );
931     }
932
933     if ( flushfork( ofork ) < 0 ) {
934         syslog( LOG_ERR, "afp_flushfork: %s", strerror(errno) );
935     }
936
937     return( AFP_OK );
938 }
939
940 /* this is very similar to closefork */
941 int flushfork( ofork )
942     struct ofork        *ofork;
943 {
944     struct timeval tv;
945     int len, err = 0, doflush = 0;
946
947     if ( ad_dfileno( ofork->of_ad ) != -1 &&
948             fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
949         syslog( LOG_ERR, "flushfork: dfile(%d) %s", 
950                 ad_dfileno(ofork->of_ad), strerror(errno) );
951         err = -1;
952     }
953
954     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
955
956         /* read in the rfork length */
957         len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
958         ad_refresh(ofork->of_ad);
959
960         /* set the date if we're dirty */
961         if ((ofork->of_flags & AFPFORK_DIRTY) &&
962             (gettimeofday(&tv, NULL) == 0)) {
963           ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
964           ofork->of_flags &= ~AFPFORK_DIRTY;
965           doflush++;
966         }
967
968         /* if we're actually flushing this fork, make sure to set the
969          * length. otherwise, just use the stored length */
970         if ((ofork->of_flags & AFPFORK_RSRC) && 
971             (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
972             ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
973             doflush++;
974         }
975
976
977         /* flush the header (if it is a resource fork) */
978         if (ofork->of_flags & AFPFORK_RSRC)
979           if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)) 
980             err = -1;
981           
982         if (fsync( ad_hfileno( ofork->of_ad )) < 0)
983           err = -1;
984
985         if (err < 0)
986           syslog( LOG_ERR, "flushfork: hfile(%d) %m", 
987                   ad_hfileno(ofork->of_ad) );
988     }
989
990     return( err );
991 }
992
993 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
994     AFPObj      *obj;
995     char        *ibuf, *rbuf;
996     int         ibuflen, *rbuflen;
997 {
998     struct ofork        *ofork;
999     struct timeval      tv;
1000     int                 adflags, aint, doflush = 0;
1001     u_int16_t           ofrefnum;
1002
1003     *rbuflen = 0;
1004     ibuf += 2;
1005     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1006
1007     if (( ofork = of_find( ofrefnum )) == NULL ) {
1008         syslog( LOG_ERR, "afp_closefork: of_find: %m" );
1009         return( AFPERR_PARAM );
1010     }
1011
1012     adflags = 0;
1013     if ((ofork->of_flags & AFPFORK_DATA) &&
1014         (ad_dfileno( ofork->of_ad ) != -1)) {
1015         adflags |= ADFLAGS_DF;
1016     }
1017
1018     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1019         adflags |= ADFLAGS_HF;
1020
1021         aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1022         ad_refresh( ofork->of_ad );
1023         if ((ofork->of_flags & AFPFORK_DIRTY) &&
1024             (gettimeofday(&tv, NULL) == 0)) {
1025             ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1026                        tv.tv_sec);
1027             doflush++;
1028         }
1029
1030         /*
1031          * Only set the rfork's length if we're closing the rfork.
1032          */
1033         if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1034                 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1035             ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1036             doflush++;
1037         }
1038         if ( doflush ) {
1039             ad_flush( ofork->of_ad, adflags );
1040         }
1041     }
1042
1043     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1044         syslog( LOG_ERR, "afp_closefork: ad_close: %m" );
1045         return( AFPERR_PARAM );
1046     }
1047
1048     of_dealloc( ofork );
1049     return( AFP_OK );
1050 }
1051
1052
1053 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1054                                      off_t offset, char *rbuf, 
1055                                      size_t rbuflen, const int xlate)
1056 {
1057     char *p, *q;
1058     ssize_t cc;
1059
1060     /*
1061      * If this file is of type TEXT, swap \015 to \012.
1062      */
1063     if (xlate) {
1064         for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1065             if ( *p == '\015' ) {
1066                 *p = '\012';
1067             } else if ( *p == '\012' ) {
1068                 *p = '\015';
1069             }
1070         }
1071     }
1072
1073     if (( cc = ad_write(ofork->of_ad, eid, offset, 0, 
1074                          rbuf, rbuflen)) < 0 ) {
1075         switch ( errno ) {
1076         case EDQUOT :
1077         case EFBIG :
1078         case ENOSPC :
1079             return( AFPERR_DFULL );
1080         default :
1081             syslog( LOG_ERR, "afp_write: ad_write: %m" );
1082             return( AFPERR_PARAM );
1083         }
1084     }
1085     
1086     return cc;
1087 }
1088
1089 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1090  * the client may have sent us a bunch of data that's not reflected 
1091  * in reqcount et al. */
1092 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1093     AFPObj              *obj;
1094     char                *ibuf, *rbuf;
1095     int                 ibuflen, *rbuflen;
1096 {
1097     struct ofork        *ofork;
1098     int32_t             offset, saveoff, reqcount;
1099     int                 endflag, eid, xlate = 0, err = AFP_OK;
1100     u_int16_t           ofrefnum;
1101     ssize_t             cc;
1102
1103     /* figure out parameters */
1104     ibuf++;
1105     endflag = ENDBIT(*ibuf);
1106     ibuf++;
1107     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1108     ibuf += sizeof( ofrefnum );
1109     memcpy(&offset, ibuf, sizeof( offset ));
1110     offset = ntohl( offset );
1111     ibuf += sizeof( offset );
1112     memcpy(&reqcount, ibuf, sizeof( reqcount ));
1113     reqcount = ntohl( reqcount );
1114     ibuf += sizeof( reqcount );
1115
1116     if (( ofork = of_find( ofrefnum )) == NULL ) {
1117         syslog( LOG_ERR, "afp_write: of_find: %m" );
1118         err = AFPERR_PARAM;
1119         goto afp_write_err;
1120     }
1121
1122     if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1123         err = AFPERR_ACCESS;
1124         goto afp_write_err;
1125     }
1126
1127 #ifdef AFS
1128     writtenfork = ofork;
1129 #endif /* AFS */
1130
1131     if ( ofork->of_flags & AFPFORK_DATA) {
1132         eid = ADEID_DFORK;
1133         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1134     } else if (ofork->of_flags & AFPFORK_RSRC) {
1135         eid = ADEID_RFORK;
1136     } else {
1137         err = AFPERR_ACCESS; /* should never happen */
1138         goto afp_write_err;
1139     }
1140
1141     if (endflag) 
1142       offset += ad_size(ofork->of_ad, eid);
1143       
1144     /* handle bogus parameters */
1145     if (reqcount < 0 || offset < 0) {
1146       err = AFPERR_PARAM;
1147       goto afp_write_err;
1148     }
1149
1150     /* offset can overflow on 64-bit capable filesystems.
1151      * report disk full if that's going to happen. */
1152     if (offset + reqcount < 0) {
1153       err = AFPERR_DFULL;
1154       goto afp_write_err;
1155     }
1156
1157     if (!reqcount) { /* handle request counts of 0 */
1158       err = AFP_OK;
1159       offset = htonl(offset);
1160       memcpy(rbuf, &offset, sizeof(offset));
1161       goto afp_write_err;
1162     }
1163
1164     saveoff = offset;
1165     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, 
1166                             reqcount) < 0) {
1167         err = AFPERR_LOCK;
1168         goto afp_write_err;
1169     }
1170
1171     /* this is yucky, but dsi can stream i/o and asp can't */
1172     switch (obj->proto) {
1173 #ifndef NO_DDP
1174     case AFPPROTO_ASP:
1175       if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1176         *rbuflen = 0;
1177         syslog( LOG_ERR, "afp_write: asp_wrtcont: %m" );
1178         return( AFPERR_PARAM );
1179       }
1180
1181       if (obj->options.flags & OPTION_DEBUG) {
1182         printf("(write) len: %d\n", *rbuflen);
1183         bprint(rbuf, *rbuflen);
1184       }
1185
1186       if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1187                            xlate)) < 0) {
1188         *rbuflen = 0;
1189         ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1190         return cc;
1191       }
1192       offset += cc;
1193       break;
1194 #endif /* no afp/asp */
1195
1196     case AFPPROTO_DSI:
1197       {
1198         DSI *dsi = obj->handle;
1199
1200         /* find out what we have already and write it out. */
1201         cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1202         if (!cc ||
1203             (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1204           dsi_writeflush(dsi);
1205           *rbuflen = 0;
1206           ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1207           return cc;
1208         }
1209         offset += cc;
1210         
1211 #if 0 /*def HAVE_SENDFILE_WRITE*/
1212         if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1213           if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1214                                  offset, dsi->datasize)) < 0) {
1215             switch (errno) {
1216             case EDQUOT :
1217             case EFBIG :
1218             case ENOSPC :
1219               cc = AFPERR_DFULL;
1220               break;
1221             default :
1222               syslog( LOG_ERR, "afp_write: ad_writefile: %m" );
1223               goto afp_write_loop;
1224             }
1225             dsi_writeflush(dsi);
1226             *rbuflen = 0;
1227             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 
1228                        reqcount);
1229             return cc;
1230           }
1231
1232           offset += cc;
1233           goto afp_write_done;
1234         }
1235 #endif /* 0, was HAVE_SENDFILE_WRITE */
1236
1237         /* loop until everything gets written. currently
1238          * dsi_write handles the end case by itself. */
1239 afp_write_loop:
1240         while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1241           if ( obj->options.flags & OPTION_DEBUG ) {
1242             printf("(write) command cont'd: %d\n", cc);
1243             bprint(rbuf, cc);
1244           }
1245
1246           if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1247             dsi_writeflush(dsi);
1248             *rbuflen = 0;
1249             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 
1250                        reqcount);
1251             return cc;
1252           }
1253           offset += cc;
1254         }
1255       }
1256       break;
1257     }
1258
1259 afp_write_done:
1260     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1261     if ( ad_hfileno( ofork->of_ad ) != -1 ) 
1262       ofork->of_flags |= AFPFORK_DIRTY;
1263
1264     offset = htonl( offset );
1265 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1266     bcopy(&offset, rbuf, sizeof(offset));
1267 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1268     memcpy(rbuf, &offset, sizeof(offset));
1269 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1270     *rbuflen = sizeof(offset);
1271     return( AFP_OK );
1272
1273 afp_write_err:
1274     if (obj->proto == AFPPROTO_DSI) {
1275       dsi_writeinit(obj->handle, rbuf, *rbuflen);
1276       dsi_writeflush(obj->handle);
1277     }
1278
1279     *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1280     return err;
1281 }
1282
1283
1284 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1285     AFPObj      *obj;
1286     char        *ibuf, *rbuf;
1287     int         ibuflen, *rbuflen;
1288 {
1289     struct ofork        *ofork;
1290     int                 buflen, ret;
1291     u_int16_t           ofrefnum, bitmap;
1292
1293     ibuf += 2;
1294     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1295     ibuf += sizeof( ofrefnum );
1296     memcpy(&bitmap, ibuf, sizeof( bitmap ));
1297     bitmap = ntohs( bitmap );
1298     ibuf += sizeof( bitmap );
1299
1300     *rbuflen = 0;
1301     if (( ofork = of_find( ofrefnum )) == NULL ) {
1302         syslog( LOG_ERR, "afp_getforkparams: of_find: %m" );
1303         return( AFPERR_PARAM );
1304     }
1305
1306     if (( ret = getforkparams( ofork, bitmap,
1307             rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1308         return( ret );
1309     }
1310
1311     *rbuflen = buflen + sizeof( u_short );
1312     bitmap = htons( bitmap );
1313     memcpy(rbuf, &bitmap, sizeof( bitmap ));
1314     return( AFP_OK );
1315 }
1316