]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/fork.c
CNID/DID patch from Uwe Hees (moderately tested)
[netatalk.git] / etc / afpd / fork.c
1 /*
2  * $Id: fork.c,v 1.6 2001-08-14 14:00:10 rufustfirefly Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* 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: %m");
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: %m" );
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: %m" );
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: %m" );
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: %m" );
534             return( AFPERR_PARAM );
535         }
536     } else
537       return AFPERR_BITMAP;
538
539 #ifdef AFS
540     if ( flushfork( ofork ) < 0 ) {
541         syslog( LOG_ERR, "afp_setforkparams: flushfork: %m" );
542     }
543 #endif /* AFS */
544
545     return( AFP_OK );
546
547 afp_setfork_err:
548     if (err == -2) 
549       return AFPERR_LOCK;
550     else {
551       switch (errno) {
552       case EROFS:
553         return AFPERR_VLOCK;
554       case EPERM:
555       case EACCES:
556         return AFPERR_ACCESS;
557       case EDQUOT:
558       case EFBIG:
559       case ENOSPC:
560         return AFPERR_DFULL;
561       default:
562         return AFPERR_PARAM;
563       }
564     }
565 }
566
567 /* for this to work correctly, we need to check for locks before each
568  * read and write. that's most easily handled by always doing an
569  * appropriate check before each ad_read/ad_write. other things
570  * that can change files like truncate are handled internally to those
571  * functions. 
572  */
573 #define ENDBIT(a)  ((a) & 0x80)
574 #define UNLOCKBIT(a) ((a) & 0x01)
575 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
576     AFPObj      *obj;
577     char        *ibuf, *rbuf;
578     int         ibuflen, *rbuflen;
579 {
580     struct ofork        *ofork;
581     int32_t             offset, length;
582     int                 eid;
583     u_int16_t           ofrefnum;
584     u_int8_t            flags;
585
586     *rbuflen = 0;
587
588     /* figure out parameters */
589     ibuf++;
590     flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
591     ibuf++;
592     memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
593     ibuf += sizeof(ofrefnum);
594
595     if (( ofork = of_find( ofrefnum )) == NULL ) {
596         syslog( LOG_ERR, "afp_bytelock: of_find: %m" );
597         return( AFPERR_PARAM );
598     }
599
600     if ( ofork->of_flags & AFPFORK_DATA) {
601         eid = ADEID_DFORK;
602     } else if (ofork->of_flags & AFPFORK_RSRC) {
603         eid = ADEID_RFORK;
604     } else 
605         return AFPERR_PARAM;
606
607     memcpy(&offset, ibuf, sizeof( offset ));
608     offset = ntohl(offset);
609     ibuf += sizeof(offset);
610
611     memcpy(&length, ibuf, sizeof( length ));
612     length = ntohl(length);
613     if (length == 0xFFFFFFFF) 
614       length = BYTELOCK_MAX;
615     else if (length <= 0) {
616       return AFPERR_PARAM;
617     } else if ((length >= AD_FILELOCK_BASE) && 
618                (ad_hfileno(ofork->of_ad) == -1))
619       return AFPERR_LOCK;
620
621     if (ENDBIT(flags)) 
622       offset += ad_size(ofork->of_ad, eid);
623
624     if (offset < 0)    /* error if we have a negative offset */
625       return AFPERR_PARAM;
626
627     /* if the file is a read-only file, we use read locks instead of
628      * write locks. that way, we can prevent anyone from initiating
629      * a write lock. */
630     if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR : 
631                 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ? 
632                  ADLOCK_WR : ADLOCK_RD), offset, length, 
633                 ofork->of_refnum) < 0) {
634       switch (errno) {
635       case EACCES:
636       case EAGAIN:
637         return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
638         break;
639       case ENOLCK:
640         return AFPERR_NLOCK;
641         break;
642       case EINVAL: 
643         return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
644         break;
645       case EBADF:
646       default: 
647         return AFPERR_PARAM;
648         break;
649       }
650     }
651
652     offset = htonl(offset);
653     memcpy(rbuf, &offset, sizeof( offset ));
654     *rbuflen = sizeof( offset );
655     return( AFP_OK );
656 }
657 #undef UNLOCKBIT
658
659
660 static __inline__ int crlf( of )
661     struct ofork        *of;
662 {
663     struct extmap       *em;
664
665     if ( ad_hfileno( of->of_ad ) == -1 ||
666          memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ), 
667                  8) == 0 ) {
668         if (( em = getextmap( of->of_name )) == NULL ||
669                 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
670             return( 1 );
671         } else {
672             return( 0 );
673         }
674     } else {
675       if ( memcmp( ufinderi, 
676                    ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
677             return( 1 );
678         } else {
679             return( 0 );
680         }
681     }
682 }
683
684
685 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
686                                     int offset, u_char nlmask, 
687                                     u_char nlchar, char *rbuf, 
688                                     int *rbuflen, const int xlate)
689
690     ssize_t cc;
691     int eof = 0;
692     char *p, *q;
693
694     cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
695     if ( cc < 0 ) {
696         syslog( LOG_ERR, "afp_read: ad_read: %m" );
697         *rbuflen = 0;
698         return( AFPERR_PARAM );
699     }
700     if ( cc < *rbuflen ) {
701         eof = 1;
702     }
703
704     /*
705      * Do Newline check.
706      */
707     if ( nlmask != 0 ) {
708         for ( p = rbuf, q = p + cc; p < q; ) {
709             if (( *p++ & nlmask ) == nlchar ) {
710                 break;
711             }
712         }
713         if ( p != q ) {
714             cc = p - rbuf;
715             eof = 0;
716         }
717     }
718
719     /*
720      * If this file is of type TEXT, then swap \012 to \015.
721      */
722     if (xlate) {
723         for ( p = rbuf, q = p + cc; p < q; p++ ) {
724             if ( *p == '\012' ) {
725                 *p = '\015';
726             } else if ( *p == '\015' ) {
727                 *p = '\012';
728             }
729               
730         }
731     }
732
733     *rbuflen = cc;
734     if ( eof ) {
735         return( AFPERR_EOF );
736     }
737     return AFP_OK;
738 }
739
740 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
741     AFPObj      *obj;
742     char        *ibuf, *rbuf;
743     int         ibuflen, *rbuflen;
744 {
745     struct ofork        *ofork;
746     off_t               size;
747     int32_t             offset, saveoff, reqcount;
748     int                 cc, err, eid, xlate = 0;
749     u_int16_t           ofrefnum;
750     u_char              nlmask, nlchar;
751
752     ibuf += 2;
753     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
754     ibuf += sizeof( u_short );
755
756     if (( ofork = of_find( ofrefnum )) == NULL ) {
757         syslog( LOG_ERR, "afp_read: of_find: %m" );
758         err = AFPERR_PARAM;
759         goto afp_read_err;
760     }
761
762     if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
763         err = AFPERR_ACCESS;
764         goto afp_read_err;
765     }
766
767     memcpy(&offset, ibuf, sizeof( offset ));
768     offset = ntohl( offset );
769     ibuf += sizeof( offset );
770     memcpy(&reqcount, ibuf, sizeof( reqcount ));
771     reqcount = ntohl( reqcount );
772     ibuf += sizeof( reqcount );
773
774     nlmask = *ibuf++;
775     nlchar = *ibuf++;
776
777     /* if we wanted to be picky, we could add in the following
778      * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
779      */
780     if (reqcount < 0 || offset < 0) {
781       err = AFPERR_PARAM;
782       goto afp_read_err;
783     }
784
785     if ( ofork->of_flags & AFPFORK_DATA) {
786         eid = ADEID_DFORK;
787         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
788     } else if (ofork->of_flags & AFPFORK_RSRC) {
789         eid = ADEID_RFORK;
790     } else { /* fork wasn't opened. this should never really happen. */
791         err = AFPERR_ACCESS;
792         goto afp_read_err;
793     }
794
795     /* zero request count */
796     if (!reqcount) {
797       err = AFP_OK;
798       goto afp_read_err;
799     }
800
801     /* reqcount isn't always truthful. we need to deal with that. */
802     if ((size = ad_size(ofork->of_ad, eid)) == 0) {
803       err = AFPERR_EOF;
804       goto afp_read_err;
805     }
806
807     saveoff = offset;
808     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
809       err = AFPERR_LOCK;
810       goto afp_read_err;
811     }      
812
813 #define min(a,b)        ((a)<(b)?(a):(b))
814     *rbuflen = min( reqcount, *rbuflen );
815     err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
816                     xlate);
817     if (err < 0) 
818       goto afp_read_done;
819
820     /* dsi can stream requests. we can only do this if we're not checking
821      * for an end-of-line character. oh well. */
822     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
823       DSI *dsi = obj->handle;
824       
825       /* subtract off the offset */
826       size -= offset;
827       if (reqcount > size) {
828         reqcount = size;
829         err = AFPERR_EOF;
830       }
831
832       if (obj->options.flags & OPTION_DEBUG) {
833         printf( "(read) reply: %d/%d, %d\n", *rbuflen,
834                 reqcount, dsi->clientID);
835         bprint(rbuf, *rbuflen);
836       }
837
838       offset += *rbuflen;
839
840       /* dsi_readinit() returns size of next read buffer. by this point,
841        * we know that we're sending some data. if we fail, something
842        * horrible happened. */
843       if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) 
844         goto afp_read_exit;
845       
846       /* due to the nature of afp packets, we have to exit if we get
847          an error. we can't do this with translation on. */
848 #ifdef HAVE_SENDFILE_READ
849       if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
850         if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, 
851                         dsi->datasize) < 0) {
852           if (errno == EINVAL)
853             goto afp_read_loop;
854           else {
855             syslog(LOG_ERR, "afp_read: ad_readfile: %m");
856             goto afp_read_exit;
857           }
858         }
859
860         dsi_readdone(dsi);
861         goto afp_read_done;
862       }
863
864 afp_read_loop:
865 #endif /* HAVE_SENDFILE_READ */
866
867       /* fill up our buffer. */
868       while (*rbuflen > 0) {
869         cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, 
870                        rbuflen, xlate);
871         if (cc < 0) 
872           goto afp_read_exit;
873
874         offset += *rbuflen;
875         if (obj->options.flags & OPTION_DEBUG) {
876           printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
877           bprint(rbuf, *rbuflen);
878         }
879
880         /* dsi_read() also returns buffer size of next allocation */
881         cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
882         if (cc < 0) 
883           goto afp_read_exit;
884         *rbuflen = cc;
885       }
886       dsi_readdone(dsi);
887       goto afp_read_done;
888
889 afp_read_exit:
890       syslog(LOG_ERR, "afp_read: %m");
891       dsi_readdone(dsi);
892       ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
893       obj->exit(1);
894     }
895
896 afp_read_done:
897     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
898     return err;
899
900 afp_read_err:
901     *rbuflen = 0;
902     return err;
903 }
904
905 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
906     AFPObj      *obj;
907     char        *ibuf, *rbuf;
908     int         ibuflen, *rbuflen;
909 {
910     struct vol *vol;
911     u_int16_t vid;
912
913     *rbuflen = 0;
914     ibuf += 2;
915
916     memcpy(&vid, ibuf, sizeof(vid));
917     if (( vol = getvolbyvid( vid )) == NULL ) {
918         return( AFPERR_PARAM );
919     }
920
921     of_flush(vol);
922     return( AFP_OK );
923 }
924
925 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
926     AFPObj      *obj;
927     char        *ibuf, *rbuf;
928     int         ibuflen, *rbuflen;
929 {
930     struct ofork        *ofork;
931     u_int16_t           ofrefnum;
932
933     *rbuflen = 0;
934     ibuf += 2;
935     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
936
937     if (( ofork = of_find( ofrefnum )) == NULL ) {
938         syslog( LOG_ERR, "afp_flushfork: of_find: %m" );
939         return( AFPERR_PARAM );
940     }
941
942     if ( flushfork( ofork ) < 0 ) {
943         syslog( LOG_ERR, "afp_flushfork: %m" );
944     }
945
946     return( AFP_OK );
947 }
948
949 /* this is very similar to closefork */
950 int flushfork( ofork )
951     struct ofork        *ofork;
952 {
953     struct timeval tv;
954     int len, err = 0, doflush = 0;
955
956     if ( ad_dfileno( ofork->of_ad ) != -1 &&
957             fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
958         syslog( LOG_ERR, "flushfork: dfile(%d) %m", 
959                 ad_dfileno(ofork->of_ad) );
960         err = -1;
961     }
962
963     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
964
965         /* read in the rfork length */
966         len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
967         ad_refresh(ofork->of_ad);
968
969         /* set the date if we're dirty */
970         if ((ofork->of_flags & AFPFORK_DIRTY) &&
971             (gettimeofday(&tv, NULL) == 0)) {
972           ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
973           ofork->of_flags &= ~AFPFORK_DIRTY;
974           doflush++;
975         }
976
977         /* if we're actually flushing this fork, make sure to set the
978          * length. otherwise, just use the stored length */
979         if ((ofork->of_flags & AFPFORK_RSRC) && 
980             (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
981             ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
982             doflush++;
983         }
984
985
986         /* flush the header (if it is a resource fork) */
987         if (ofork->of_flags & AFPFORK_RSRC)
988           if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)) 
989             err = -1;
990           
991         if (fsync( ad_hfileno( ofork->of_ad )) < 0)
992           err = -1;
993
994         if (err < 0)
995           syslog( LOG_ERR, "flushfork: hfile(%d) %m", 
996                   ad_hfileno(ofork->of_ad) );
997     }
998
999     return( err );
1000 }
1001
1002 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1003     AFPObj      *obj;
1004     char        *ibuf, *rbuf;
1005     int         ibuflen, *rbuflen;
1006 {
1007     struct ofork        *ofork;
1008     struct timeval      tv;
1009     int                 adflags, aint, doflush = 0;
1010     u_int16_t           ofrefnum;
1011
1012     *rbuflen = 0;
1013     ibuf += 2;
1014     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1015
1016     if (( ofork = of_find( ofrefnum )) == NULL ) {
1017         syslog( LOG_ERR, "afp_closefork: of_find: %m" );
1018         return( AFPERR_PARAM );
1019     }
1020
1021     adflags = 0;
1022     if ((ofork->of_flags & AFPFORK_DATA) &&
1023         (ad_dfileno( ofork->of_ad ) != -1)) {
1024         adflags |= ADFLAGS_DF;
1025     }
1026
1027     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1028         adflags |= ADFLAGS_HF;
1029
1030         aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1031         ad_refresh( ofork->of_ad );
1032         if ((ofork->of_flags & AFPFORK_DIRTY) &&
1033             (gettimeofday(&tv, NULL) == 0)) {
1034             ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1035                        tv.tv_sec);
1036             doflush++;
1037         }
1038
1039         /*
1040          * Only set the rfork's length if we're closing the rfork.
1041          */
1042         if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1043                 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1044             ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1045             doflush++;
1046         }
1047         if ( doflush ) {
1048             ad_flush( ofork->of_ad, adflags );
1049         }
1050     }
1051
1052     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1053         syslog( LOG_ERR, "afp_closefork: ad_close: %m" );
1054         return( AFPERR_PARAM );
1055     }
1056
1057     of_dealloc( ofork );
1058     return( AFP_OK );
1059 }
1060
1061
1062 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1063                                      off_t offset, char *rbuf, 
1064                                      size_t rbuflen, const int xlate)
1065 {
1066     char *p, *q;
1067     ssize_t cc;
1068
1069     /*
1070      * If this file is of type TEXT, swap \015 to \012.
1071      */
1072     if (xlate) {
1073         for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1074             if ( *p == '\015' ) {
1075                 *p = '\012';
1076             } else if ( *p == '\012' ) {
1077                 *p = '\015';
1078             }
1079         }
1080     }
1081
1082     if (( cc = ad_write(ofork->of_ad, eid, offset, 0, 
1083                          rbuf, rbuflen)) < 0 ) {
1084         switch ( errno ) {
1085         case EDQUOT :
1086         case EFBIG :
1087         case ENOSPC :
1088             return( AFPERR_DFULL );
1089         default :
1090             syslog( LOG_ERR, "afp_write: ad_write: %m" );
1091             return( AFPERR_PARAM );
1092         }
1093     }
1094     
1095     return cc;
1096 }
1097
1098 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1099  * the client may have sent us a bunch of data that's not reflected 
1100  * in reqcount et al. */
1101 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1102     AFPObj              *obj;
1103     char                *ibuf, *rbuf;
1104     int                 ibuflen, *rbuflen;
1105 {
1106     struct ofork        *ofork;
1107     int32_t             offset, saveoff, reqcount;
1108     int                 endflag, eid, xlate = 0, err = AFP_OK;
1109     u_int16_t           ofrefnum;
1110     ssize_t             cc;
1111
1112     /* figure out parameters */
1113     ibuf++;
1114     endflag = ENDBIT(*ibuf);
1115     ibuf++;
1116     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1117     ibuf += sizeof( ofrefnum );
1118     memcpy(&offset, ibuf, sizeof( offset ));
1119     offset = ntohl( offset );
1120     ibuf += sizeof( offset );
1121     memcpy(&reqcount, ibuf, sizeof( reqcount ));
1122     reqcount = ntohl( reqcount );
1123     ibuf += sizeof( reqcount );
1124
1125     if (( ofork = of_find( ofrefnum )) == NULL ) {
1126         syslog( LOG_ERR, "afp_write: of_find: %m" );
1127         err = AFPERR_PARAM;
1128         goto afp_write_err;
1129     }
1130
1131     if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1132         err = AFPERR_ACCESS;
1133         goto afp_write_err;
1134     }
1135
1136 #ifdef AFS
1137     writtenfork = ofork;
1138 #endif /* AFS */
1139
1140     if ( ofork->of_flags & AFPFORK_DATA) {
1141         eid = ADEID_DFORK;
1142         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1143     } else if (ofork->of_flags & AFPFORK_RSRC) {
1144         eid = ADEID_RFORK;
1145     } else {
1146         err = AFPERR_ACCESS; /* should never happen */
1147         goto afp_write_err;
1148     }
1149
1150     if (endflag) 
1151       offset += ad_size(ofork->of_ad, eid);
1152       
1153     /* handle bogus parameters */
1154     if (reqcount < 0 || offset < 0) {
1155       err = AFPERR_PARAM;
1156       goto afp_write_err;
1157     }
1158
1159     /* offset can overflow on 64-bit capable filesystems.
1160      * report disk full if that's going to happen. */
1161     if (offset + reqcount < 0) {
1162       err = AFPERR_DFULL;
1163       goto afp_write_err;
1164     }
1165
1166     if (!reqcount) { /* handle request counts of 0 */
1167       err = AFP_OK;
1168       offset = htonl(offset);
1169       memcpy(rbuf, &offset, sizeof(offset));
1170       goto afp_write_err;
1171     }
1172
1173     saveoff = offset;
1174     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, 
1175                             reqcount) < 0) {
1176         err = AFPERR_LOCK;
1177         goto afp_write_err;
1178     }
1179
1180     /* this is yucky, but dsi can stream i/o and asp can't */
1181     switch (obj->proto) {
1182 #ifndef NO_DDP
1183     case AFPPROTO_ASP:
1184       if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1185         *rbuflen = 0;
1186         syslog( LOG_ERR, "afp_write: asp_wrtcont: %m" );
1187         return( AFPERR_PARAM );
1188       }
1189
1190       if (obj->options.flags & OPTION_DEBUG) {
1191         printf("(write) len: %d\n", *rbuflen);
1192         bprint(rbuf, *rbuflen);
1193       }
1194
1195       if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1196                            xlate)) < 0) {
1197         *rbuflen = 0;
1198         ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1199         return cc;
1200       }
1201       offset += cc;
1202       break;
1203 #endif /* no afp/asp */
1204
1205     case AFPPROTO_DSI:
1206       {
1207         DSI *dsi = obj->handle;
1208
1209         /* find out what we have already and write it out. */
1210         cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1211         if (!cc ||
1212             (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1213           dsi_writeflush(dsi);
1214           *rbuflen = 0;
1215           ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1216           return cc;
1217         }
1218         offset += cc;
1219         
1220 #if 0 /*def HAVE_SENDFILE_WRITE*/
1221         if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1222           if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1223                                  offset, dsi->datasize)) < 0) {
1224             switch (errno) {
1225             case EDQUOT :
1226             case EFBIG :
1227             case ENOSPC :
1228               cc = AFPERR_DFULL;
1229               break;
1230             default :
1231               syslog( LOG_ERR, "afp_write: ad_writefile: %m" );
1232               goto afp_write_loop;
1233             }
1234             dsi_writeflush(dsi);
1235             *rbuflen = 0;
1236             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 
1237                        reqcount);
1238             return cc;
1239           }
1240
1241           offset += cc;
1242           goto afp_write_done;
1243         }
1244 #endif /* 0, was HAVE_SENDFILE_WRITE */
1245
1246         /* loop until everything gets written. currently
1247          * dsi_write handles the end case by itself. */
1248 afp_write_loop:
1249         while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1250           if ( obj->options.flags & OPTION_DEBUG ) {
1251             printf("(write) command cont'd: %d\n", cc);
1252             bprint(rbuf, cc);
1253           }
1254
1255           if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1256             dsi_writeflush(dsi);
1257             *rbuflen = 0;
1258             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, 
1259                        reqcount);
1260             return cc;
1261           }
1262           offset += cc;
1263         }
1264       }
1265       break;
1266     }
1267
1268 afp_write_done:
1269     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1270     if ( ad_hfileno( ofork->of_ad ) != -1 ) 
1271       ofork->of_flags |= AFPFORK_DIRTY;
1272
1273     offset = htonl( offset );
1274 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1275     bcopy(&offset, rbuf, sizeof(offset));
1276 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1277     memcpy(rbuf, &offset, sizeof(offset));
1278 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1279     *rbuflen = sizeof(offset);
1280     return( AFP_OK );
1281
1282 afp_write_err:
1283     if (obj->proto == AFPPROTO_DSI) {
1284       dsi_writeinit(obj->handle, rbuf, *rbuflen);
1285       dsi_writeflush(obj->handle);
1286     }
1287
1288     *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1289     return err;
1290 }
1291
1292
1293 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1294     AFPObj      *obj;
1295     char        *ibuf, *rbuf;
1296     int         ibuflen, *rbuflen;
1297 {
1298     struct ofork        *ofork;
1299     int                 buflen, ret;
1300     u_int16_t           ofrefnum, bitmap;
1301
1302     ibuf += 2;
1303     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1304     ibuf += sizeof( ofrefnum );
1305     memcpy(&bitmap, ibuf, sizeof( bitmap ));
1306     bitmap = ntohs( bitmap );
1307     ibuf += sizeof( bitmap );
1308
1309     *rbuflen = 0;
1310     if (( ofork = of_find( ofrefnum )) == NULL ) {
1311         syslog( LOG_ERR, "afp_getforkparams: of_find: %m" );
1312         return( AFPERR_PARAM );
1313     }
1314
1315     if (( ret = getforkparams( ofork, bitmap,
1316             rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1317         return( ret );
1318     }
1319
1320     *rbuflen = buflen + sizeof( u_short );
1321     bitmap = htons( bitmap );
1322     memcpy(rbuf, &bitmap, sizeof( bitmap ));
1323     return( AFP_OK );
1324 }
1325