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