]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/fork.c
this fixes a problem exposed by the os x appleshare client. flushfork
[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
948         /* read in the rfork length */
949         len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
950         ad_refresh(ofork->of_ad);
951
952         /* set the date if we're dirty */
953         if ((ofork->of_flags & AFPFORK_DIRTY) &&
954             (gettimeofday(&tv, NULL) == 0)) {
955           ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
956           ofork->of_flags &= ~AFPFORK_DIRTY;
957           doflush++;
958         }
959
960         /* if we're actually flushing this fork, make sure to set the
961          * length. otherwise, just use the stored length */
962         if ((ofork->of_flags & AFPFORK_RSRC) && 
963             (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
964             ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
965             doflush++;
966         }
967
968
969         /* flush the header. */
970         if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)) 
971           err = -1;
972           
973         if (fsync( ad_hfileno( ofork->of_ad )) < 0)
974           err = -1;
975
976         if (err < 0)
977           syslog( LOG_ERR, "flushfork: hfile(%d) %m", 
978                   ad_hfileno(ofork->of_ad) );
979     }
980
981     return( err );
982 }
983
984 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
985     AFPObj      *obj;
986     char        *ibuf, *rbuf;
987     int         ibuflen, *rbuflen;
988 {
989     struct ofork        *ofork;
990     struct timeval      tv;
991     int                 adflags, aint, doflush = 0;
992     u_int16_t           ofrefnum;
993
994     *rbuflen = 0;
995     ibuf += 2;
996     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
997
998     if (( ofork = of_find( ofrefnum )) == NULL ) {
999         syslog( LOG_ERR, "afp_closefork: of_find: %m" );
1000         return( AFPERR_PARAM );
1001     }
1002
1003     adflags = 0;
1004     if ((ofork->of_flags & AFPFORK_DATA) &&
1005         (ad_dfileno( ofork->of_ad ) != -1)) {
1006         adflags |= ADFLAGS_DF;
1007     }
1008
1009     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1010         adflags |= ADFLAGS_HF;
1011
1012         aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1013         ad_refresh( ofork->of_ad );
1014         if ((ofork->of_flags & AFPFORK_DIRTY) &&
1015             (gettimeofday(&tv, NULL) == 0)) {
1016             ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1017                        tv.tv_sec);
1018             doflush++;
1019         }
1020
1021         /*
1022          * Only set the rfork's length if we're closing the rfork.
1023          */
1024         if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1025                 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1026             ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1027             doflush++;
1028         }
1029         if ( doflush ) {
1030             ad_flush( ofork->of_ad, adflags );
1031         }
1032     }
1033
1034     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1035         syslog( LOG_ERR, "afp_closefork: ad_close: %m" );
1036         return( AFPERR_PARAM );
1037     }
1038
1039     of_dealloc( ofork );
1040     return( AFP_OK );
1041 }
1042
1043
1044 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1045                                      off_t offset, char *rbuf, 
1046                                      size_t rbuflen, const int xlate)
1047 {
1048     char *p, *q;
1049     ssize_t cc;
1050
1051     /*
1052      * If this file is of type TEXT, swap \015 to \012.
1053      */
1054     if (xlate) {
1055         for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1056             if ( *p == '\015' ) {
1057                 *p = '\012';
1058             } else if ( *p == '\012' ) {
1059                 *p = '\015';
1060             }
1061         }
1062     }
1063
1064     if (( cc = ad_write(ofork->of_ad, eid, offset, 0, 
1065                          rbuf, rbuflen)) < 0 ) {
1066         switch ( errno ) {
1067         case EDQUOT :
1068         case EFBIG :
1069         case ENOSPC :
1070             return( AFPERR_DFULL );
1071         default :
1072             syslog( LOG_ERR, "afp_write: ad_write: %m" );
1073             return( AFPERR_PARAM );
1074         }
1075     }
1076     
1077     return cc;
1078 }
1079
1080 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1081  * the client may have sent us a bunch of data that's not reflected 
1082  * in reqcount et al. */
1083 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1084     AFPObj              *obj;
1085     char                *ibuf, *rbuf;
1086     int                 ibuflen, *rbuflen;
1087 {
1088     struct ofork        *ofork;
1089     int32_t             offset, saveoff, reqcount;
1090     int                 endflag, eid, xlate = 0, err = AFP_OK;
1091     u_int16_t           ofrefnum;
1092     ssize_t             cc;
1093
1094     /* figure out parameters */
1095     ibuf++;
1096     endflag = ENDBIT(*ibuf);
1097     ibuf++;
1098     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1099     ibuf += sizeof( ofrefnum );
1100     memcpy(&offset, ibuf, sizeof( offset ));
1101     offset = ntohl( offset );
1102     ibuf += sizeof( offset );
1103     memcpy(&reqcount, ibuf, sizeof( reqcount ));
1104     reqcount = ntohl( reqcount );
1105     ibuf += sizeof( reqcount );
1106
1107     if (( ofork = of_find( ofrefnum )) == NULL ) {
1108         syslog( LOG_ERR, "afp_write: of_find: %m" );
1109         err = AFPERR_PARAM;
1110         goto afp_write_err;
1111     }
1112
1113     if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1114         err = AFPERR_ACCESS;
1115         goto afp_write_err;
1116     }
1117
1118 #ifdef AFS
1119     writtenfork = ofork;
1120 #endif AFS
1121
1122     if ( ofork->of_flags & AFPFORK_DATA) {
1123         eid = ADEID_DFORK;
1124         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1125     } else if (ofork->of_flags & AFPFORK_RSRC) {
1126         eid = ADEID_RFORK;
1127     } else {
1128         err = AFPERR_ACCESS; /* should never happen */
1129         goto afp_write_err;
1130     }
1131
1132     if (endflag) 
1133       offset += ad_size(ofork->of_ad, eid);
1134       
1135     /* handle bogus parameters */
1136     if (reqcount < 0 || offset < 0) {
1137       err = AFPERR_PARAM;
1138       goto afp_write_err;
1139     }
1140
1141     /* offset can overflow on 64-bit capable filesystems.
1142      * report disk full if that's going to happen. */
1143     if (offset + reqcount < 0) {
1144       err = AFPERR_DFULL;
1145       goto afp_write_err;
1146     }
1147
1148     if (!reqcount) { /* handle request counts of 0 */
1149       err = AFP_OK;
1150       offset = htonl(offset);
1151       memcpy(rbuf, &offset, sizeof(offset));
1152       goto afp_write_err;
1153     }
1154
1155     saveoff = offset;
1156     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, 
1157                             reqcount) < 0) {
1158         err = AFPERR_LOCK;
1159         goto afp_write_err;
1160     }
1161
1162     /* this is yucky, but dsi can stream i/o and asp can't */
1163     switch (obj->proto) {
1164 #ifndef NO_DDP
1165     case AFPPROTO_ASP:
1166       if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1167         *rbuflen = 0;
1168         syslog( LOG_ERR, "afp_write: asp_wrtcont: %m" );
1169         return( AFPERR_PARAM );
1170       }
1171
1172       if (obj->options.flags & OPTION_DEBUG) {
1173         printf("(write) len: %d\n", *rbuflen);
1174         bprint(rbuf, *rbuflen);
1175       }
1176
1177       if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1178                            xlate)) < 0) {
1179         *rbuflen = 0;
1180         ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1181         return cc;
1182       }
1183       offset += cc;
1184       break;
1185 #endif /* no afp/asp */
1186
1187     case AFPPROTO_DSI:
1188       {
1189         DSI *dsi = obj->handle;
1190
1191         /* find out what we have already and write it out. */
1192         cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1193         if (!cc ||
1194             (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1195           dsi_writeflush(dsi);
1196           *rbuflen = 0;
1197           ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1198           return cc;
1199         }
1200         offset += cc;
1201         
1202 #if 0 /*def HAVE_SENDFILE_WRITE*/
1203         if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1204           if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1205                                  offset, dsi->datasize)) < 0) {
1206             switch (errno) {
1207             case EDQUOT :
1208             case EFBIG :
1209             case ENOSPC :
1210               cc = AFPERR_DFULL;
1211               break;
1212             default :
1213               syslog( LOG_ERR, "afp_write: ad_writefile: %m" );
1214               goto afp_write_loop;
1215             }
1216             dsi_writeflush(dsi);
1217             *rbuflen = 0;
1218             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 
1219                        reqcount);
1220             return cc;
1221           }
1222
1223           offset += cc;
1224           goto afp_write_done;
1225         }
1226 #endif
1227
1228         /* loop until everything gets written. currently
1229          * dsi_write handles the end case by itself. */
1230 afp_write_loop:
1231         while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1232           if ( obj->options.flags & OPTION_DEBUG ) {
1233             printf("(write) command cont'd: %d\n", cc);
1234             bprint(rbuf, cc);
1235           }
1236
1237           if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1238             dsi_writeflush(dsi);
1239             *rbuflen = 0;
1240             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 
1241                        reqcount);
1242             return cc;
1243           }
1244           offset += cc;
1245         }
1246       }
1247       break;
1248     }
1249
1250 afp_write_done:
1251     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1252     if ( ad_hfileno( ofork->of_ad ) != -1 ) 
1253       ofork->of_flags |= AFPFORK_DIRTY;
1254
1255     offset = htonl( offset );
1256 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1257     bcopy(&offset, rbuf, sizeof(offset));
1258 #else
1259     memcpy(rbuf, &offset, sizeof(offset));
1260 #endif
1261     *rbuflen = sizeof(offset);
1262     return( AFP_OK );
1263
1264 afp_write_err:
1265     if (obj->proto == AFPPROTO_DSI) {
1266       dsi_writeinit(obj->handle, rbuf, *rbuflen);
1267       dsi_writeflush(obj->handle);
1268     }
1269
1270     *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1271     return err;
1272 }
1273
1274
1275 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1276     AFPObj      *obj;
1277     char        *ibuf, *rbuf;
1278     int         ibuflen, *rbuflen;
1279 {
1280     struct ofork        *ofork;
1281     int                 buflen, ret;
1282     u_int16_t           ofrefnum, bitmap;
1283
1284     ibuf += 2;
1285     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1286     ibuf += sizeof( ofrefnum );
1287     memcpy(&bitmap, ibuf, sizeof( bitmap ));
1288     bitmap = ntohs( bitmap );
1289     ibuf += sizeof( bitmap );
1290
1291     *rbuflen = 0;
1292     if (( ofork = of_find( ofrefnum )) == NULL ) {
1293         syslog( LOG_ERR, "afp_getforkparams: of_find: %m" );
1294         return( AFPERR_PARAM );
1295     }
1296
1297     if (( ret = getforkparams( ofork, bitmap,
1298             rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1299         return( ret );
1300     }
1301
1302     *rbuflen = buflen + sizeof( u_short );
1303     bitmap = htons( bitmap );
1304     memcpy(rbuf, &bitmap, sizeof( bitmap ));
1305     return( AFP_OK );
1306 }
1307