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