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