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