]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/fork.c
c238d7a5b94b64f4741e030a1c1f177b4fbc164a
[netatalk.git] / etc / afpd / fork.c
1 /*
2  * $Id: fork.c,v 1.28 2002-05-29 17:40:36 jmarcus 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 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
705 AFPObj      *obj;
706 char    *ibuf, *rbuf;
707 int             ibuflen, *rbuflen;
708 {
709     struct ofork        *ofork;
710     off_t               size;
711     int32_t             offset, saveoff, reqcount, savereqcount;
712     int                 cc, err, saveerr, eid, xlate = 0;
713     u_int16_t           ofrefnum;
714     u_char              nlmask, nlchar;
715
716     ibuf += 2;
717     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
718     ibuf += sizeof( u_short );
719
720     if (( ofork = of_find( ofrefnum )) == NULL ) {
721         LOG(log_error, logtype_afpd, "afp_read: of_find");
722         err = AFPERR_PARAM;
723         goto afp_read_err;
724     }
725
726     if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
727         err = AFPERR_ACCESS;
728         goto afp_read_err;
729     }
730
731     memcpy(&offset, ibuf, sizeof( offset ));
732     offset = ntohl( offset );
733     ibuf += sizeof( offset );
734     memcpy(&reqcount, ibuf, sizeof( reqcount ));
735     reqcount = ntohl( reqcount );
736     ibuf += sizeof( reqcount );
737
738     nlmask = *ibuf++;
739     nlchar = *ibuf++;
740
741     /* if we wanted to be picky, we could add in the following
742      * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
743      */
744     if (reqcount < 0 || offset < 0) {
745         err = AFPERR_PARAM;
746         goto afp_read_err;
747     }
748
749     if ( ofork->of_flags & AFPFORK_DATA) {
750         eid = ADEID_DFORK;
751         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
752     } else if (ofork->of_flags & AFPFORK_RSRC) {
753         eid = ADEID_RFORK;
754     } else { /* fork wasn't opened. this should never really happen. */
755         err = AFPERR_ACCESS;
756         goto afp_read_err;
757     }
758
759     /* zero request count */
760     err = AFP_OK;
761     if (!reqcount) {
762         goto afp_read_err;
763     }
764
765     /* reqcount isn't always truthful. we need to deal with that. */
766     size = ad_size(ofork->of_ad, eid);
767
768     if (offset >= size) {
769         err = AFPERR_EOF;
770         goto afp_read_err;
771     }
772
773     /* subtract off the offset */
774     size -= offset;
775     savereqcount = reqcount;
776     if (reqcount > size) {
777         reqcount = size;
778         err = AFPERR_EOF;
779     }
780
781     saveoff = offset;
782     /* if EOF lock on the old reqcount, some prg may need it */
783     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
784         err = AFPERR_LOCK;
785         goto afp_read_err;
786     }
787
788 #define min(a,b)        ((a)<(b)?(a):(b))
789     *rbuflen = min( reqcount, *rbuflen );
790     saveerr = err;
791     err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
792                     xlate);
793     if (err < 0)
794         goto afp_read_done;
795     if (saveerr < 0) {
796        err = saveerr;
797     }
798     /* dsi can stream requests. we can only do this if we're not checking
799      * for an end-of-line character. oh well. */
800     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
801         DSI *dsi = obj->handle;
802
803         if (obj->options.flags & OPTION_DEBUG) {
804             printf( "(read) reply: %d/%d, %d\n", *rbuflen,
805                     reqcount, dsi->clientID);
806             bprint(rbuf, *rbuflen);
807         }
808
809         offset += *rbuflen;
810
811         /* dsi_readinit() returns size of next read buffer. by this point,
812          * we know that we're sending some data. if we fail, something
813          * horrible happened. */
814         if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
815             goto afp_read_exit;
816
817         /* due to the nature of afp packets, we have to exit if we get
818            an error. we can't do this with translation on. */
819 #ifdef HAVE_SENDFILE_READ
820         if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
821             if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
822                             dsi->datasize) < 0) {
823                 if (errno == EINVAL)
824                     goto afp_read_loop;
825                 else {
826                     LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
827                     goto afp_read_exit;
828                 }
829             }
830
831             dsi_readdone(dsi);
832             goto afp_read_done;
833         }
834
835 afp_read_loop:
836 #endif /* HAVE_SENDFILE_READ */
837
838         /* fill up our buffer. */
839         while (*rbuflen > 0) {
840             cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
841                            rbuflen, xlate);
842             if (cc < 0)
843                 goto afp_read_exit;
844
845             offset += *rbuflen;
846             if (obj->options.flags & OPTION_DEBUG) {
847                 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
848                 bprint(rbuf, *rbuflen);
849             }
850
851             /* dsi_read() also returns buffer size of next allocation */
852             cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
853             if (cc < 0)
854                 goto afp_read_exit;
855             *rbuflen = cc;
856         }
857         dsi_readdone(dsi);
858         goto afp_read_done;
859
860 afp_read_exit:
861         LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
862         dsi_readdone(dsi);
863         ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
864         obj->exit(1);
865     }
866
867 afp_read_done:
868     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
869     return err;
870
871 afp_read_err:
872     *rbuflen = 0;
873     return err;
874 }
875
876 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
877 AFPObj      *obj;
878 char    *ibuf, *rbuf;
879 int             ibuflen, *rbuflen;
880 {
881     struct vol *vol;
882     u_int16_t vid;
883
884     *rbuflen = 0;
885     ibuf += 2;
886
887     memcpy(&vid, ibuf, sizeof(vid));
888     if (( vol = getvolbyvid( vid )) == NULL ) {
889         return( AFPERR_PARAM );
890     }
891
892     of_flush(vol);
893     return( AFP_OK );
894 }
895
896 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
897 AFPObj      *obj;
898 char    *ibuf, *rbuf;
899 int             ibuflen, *rbuflen;
900 {
901     struct ofork        *ofork;
902     u_int16_t           ofrefnum;
903
904     *rbuflen = 0;
905     ibuf += 2;
906     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
907
908     if (( ofork = of_find( ofrefnum )) == NULL ) {
909         LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
910         return( AFPERR_PARAM );
911     }
912
913     if ( flushfork( ofork ) < 0 ) {
914         LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
915     }
916
917     return( AFP_OK );
918 }
919
920 /* this is very similar to closefork */
921 int flushfork( ofork )
922 struct ofork    *ofork;
923 {
924     struct timeval tv;
925     int len, err = 0, doflush = 0;
926
927     if ( ad_dfileno( ofork->of_ad ) != -1 &&
928             fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
929         LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
930             ad_dfileno(ofork->of_ad), strerror(errno) );
931         err = -1;
932     }
933
934     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
935
936         /* read in the rfork length */
937         len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
938         ad_refresh(ofork->of_ad);
939
940         /* set the date if we're dirty */
941         if ((ofork->of_flags & AFPFORK_DIRTY) &&
942                 (gettimeofday(&tv, NULL) == 0)) {
943             ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
944             ofork->of_flags &= ~AFPFORK_DIRTY;
945             doflush++;
946         }
947
948         /* if we're actually flushing this fork, make sure to set the
949          * length. otherwise, just use the stored length */
950         if ((ofork->of_flags & AFPFORK_RSRC) &&
951                 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
952             ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
953             doflush++;
954         }
955
956
957         /* flush the header (if it is a resource fork) */
958         if (ofork->of_flags & AFPFORK_RSRC)
959             if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
960                 err = -1;
961
962         if (fsync( ad_hfileno( ofork->of_ad )) < 0)
963             err = -1;
964
965         if (err < 0)
966             LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
967                 ad_hfileno(ofork->of_ad), strerror(errno) );
968     }
969
970     return( err );
971 }
972
973 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
974 AFPObj      *obj;
975 char    *ibuf, *rbuf;
976 int             ibuflen, *rbuflen;
977 {
978     struct ofork        *ofork;
979     struct timeval      tv;
980     int                 adflags, aint, doflush = 0;
981     u_int16_t           ofrefnum;
982
983     *rbuflen = 0;
984     ibuf += 2;
985     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
986
987     if (( ofork = of_find( ofrefnum )) == NULL ) {
988         LOG(log_error, logtype_afpd, "afp_closefork: of_find");
989         return( AFPERR_PARAM );
990     }
991
992     adflags = 0;
993     if ((ofork->of_flags & AFPFORK_DATA) &&
994             (ad_dfileno( ofork->of_ad ) != -1)) {
995         adflags |= ADFLAGS_DF;
996     }
997
998     if ( ad_hfileno( ofork->of_ad ) != -1 ) {
999         adflags |= ADFLAGS_HF;
1000
1001         aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1002         ad_refresh( ofork->of_ad );
1003         if ((ofork->of_flags & AFPFORK_DIRTY) &&
1004                 (gettimeofday(&tv, NULL) == 0)) {
1005             ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1006                        tv.tv_sec);
1007             doflush++;
1008         }
1009
1010         /*
1011          * Only set the rfork's length if we're closing the rfork.
1012          */
1013         if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1014                 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1015             ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1016             doflush++;
1017         }
1018         if ( doflush ) {
1019             ad_flush( ofork->of_ad, adflags );
1020         }
1021     }
1022
1023     if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1024         LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1025         return( AFPERR_PARAM );
1026     }
1027
1028     of_dealloc( ofork );
1029     return( AFP_OK );
1030 }
1031
1032
1033 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1034                                      off_t offset, char *rbuf,
1035                                      size_t rbuflen, const int xlate)
1036 {
1037     char *p, *q;
1038     ssize_t cc;
1039
1040     /*
1041      * If this file is of type TEXT, swap \015 to \012.
1042      */
1043     if (xlate) {
1044         for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1045             if ( *p == '\015' ) {
1046                 *p = '\012';
1047             } else if ( *p == '\012' ) {
1048                 *p = '\015';
1049             }
1050         }
1051     }
1052
1053     if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1054                         rbuf, rbuflen)) < 0 ) {
1055         switch ( errno ) {
1056         case EDQUOT :
1057         case EFBIG :
1058         case ENOSPC :
1059             return( AFPERR_DFULL );
1060         default :
1061             LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1062             return( AFPERR_PARAM );
1063         }
1064     }
1065
1066     return cc;
1067 }
1068
1069 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1070  * the client may have sent us a bunch of data that's not reflected 
1071  * in reqcount et al. */
1072 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1073 AFPObj              *obj;
1074 char                *ibuf, *rbuf;
1075 int                 ibuflen, *rbuflen;
1076 {
1077     struct ofork        *ofork;
1078     int32_t             offset, saveoff, reqcount;
1079     int                 endflag, eid, xlate = 0, err = AFP_OK;
1080     u_int16_t           ofrefnum;
1081     ssize_t             cc;
1082
1083     /* figure out parameters */
1084     ibuf++;
1085     endflag = ENDBIT(*ibuf);
1086     ibuf++;
1087     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1088     ibuf += sizeof( ofrefnum );
1089     memcpy(&offset, ibuf, sizeof( offset ));
1090     offset = ntohl( offset );
1091     ibuf += sizeof( offset );
1092     memcpy(&reqcount, ibuf, sizeof( reqcount ));
1093     reqcount = ntohl( reqcount );
1094     ibuf += sizeof( reqcount );
1095
1096     if (( ofork = of_find( ofrefnum )) == NULL ) {
1097         LOG(log_error, logtype_afpd, "afp_write: of_find");
1098         err = AFPERR_PARAM;
1099         goto afp_write_err;
1100     }
1101
1102     if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1103         err = AFPERR_ACCESS;
1104         goto afp_write_err;
1105     }
1106
1107 #ifdef AFS
1108     writtenfork = ofork;
1109 #endif /* AFS */
1110
1111     if ( ofork->of_flags & AFPFORK_DATA) {
1112         eid = ADEID_DFORK;
1113         xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1114     } else if (ofork->of_flags & AFPFORK_RSRC) {
1115         eid = ADEID_RFORK;
1116     } else {
1117         err = AFPERR_ACCESS; /* should never happen */
1118         goto afp_write_err;
1119     }
1120
1121     if (endflag)
1122         offset += ad_size(ofork->of_ad, eid);
1123
1124     /* handle bogus parameters */
1125     if (reqcount < 0 || offset < 0) {
1126         err = AFPERR_PARAM;
1127         goto afp_write_err;
1128     }
1129
1130     /* offset can overflow on 64-bit capable filesystems.
1131      * report disk full if that's going to happen. */
1132     if (offset + reqcount < 0) {
1133         err = AFPERR_DFULL;
1134         goto afp_write_err;
1135     }
1136
1137     if (!reqcount) { /* handle request counts of 0 */
1138         err = AFP_OK;
1139         offset = htonl(offset);
1140         memcpy(rbuf, &offset, sizeof(offset));
1141         goto afp_write_err;
1142     }
1143
1144     saveoff = offset;
1145     if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1146                    reqcount) < 0) {
1147         err = AFPERR_LOCK;
1148         goto afp_write_err;
1149     }
1150
1151     /* this is yucky, but dsi can stream i/o and asp can't */
1152     switch (obj->proto) {
1153 #ifndef NO_DDP
1154     case AFPPROTO_ASP:
1155         if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1156             *rbuflen = 0;
1157             LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1158             return( AFPERR_PARAM );
1159         }
1160
1161         if (obj->options.flags & OPTION_DEBUG) {
1162             printf("(write) len: %d\n", *rbuflen);
1163             bprint(rbuf, *rbuflen);
1164         }
1165
1166         if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1167                              xlate)) < 0) {
1168             *rbuflen = 0;
1169             ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1170             return cc;
1171         }
1172         offset += cc;
1173         break;
1174 #endif /* no afp/asp */
1175
1176     case AFPPROTO_DSI:
1177         {
1178             DSI *dsi = obj->handle;
1179
1180             /* find out what we have already and write it out. */
1181             cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1182             if (!cc ||
1183                     (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1184                 dsi_writeflush(dsi);
1185                 *rbuflen = 0;
1186                 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1187                 return cc;
1188             }
1189             offset += cc;
1190
1191 #if 0 /*def HAVE_SENDFILE_WRITE*/
1192             if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1193                 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1194                                        offset, dsi->datasize)) < 0) {
1195                     switch (errno) {
1196                     case EDQUOT :
1197                     case EFBIG :
1198                     case ENOSPC :
1199                         cc = AFPERR_DFULL;
1200                         break;
1201                     default :
1202                         LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1203                         goto afp_write_loop;
1204                     }
1205                     dsi_writeflush(dsi);
1206                     *rbuflen = 0;
1207                     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1208                                reqcount);
1209                     return cc;
1210                 }
1211
1212                 offset += cc;
1213                 goto afp_write_done;
1214             }
1215 #endif /* 0, was HAVE_SENDFILE_WRITE */
1216
1217             /* loop until everything gets written. currently
1218                     * dsi_write handles the end case by itself. */
1219             while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1220                 if ( obj->options.flags & OPTION_DEBUG ) {
1221                     printf("(write) command cont'd: %d\n", cc);
1222                     bprint(rbuf, cc);
1223                 }
1224
1225                 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1226                     dsi_writeflush(dsi);
1227                     *rbuflen = 0;
1228                     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1229                                reqcount);
1230                     return cc;
1231                 }
1232                 offset += cc;
1233             }
1234         }
1235         break;
1236     }
1237
1238     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1239     if ( ad_hfileno( ofork->of_ad ) != -1 )
1240         ofork->of_flags |= AFPFORK_DIRTY;
1241
1242     offset = htonl( offset );
1243 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1244     bcopy(&offset, rbuf, sizeof(offset));
1245 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1246     memcpy(rbuf, &offset, sizeof(offset));
1247 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1248     *rbuflen = sizeof(offset);
1249     return( AFP_OK );
1250
1251 afp_write_err:
1252     if (obj->proto == AFPPROTO_DSI) {
1253         dsi_writeinit(obj->handle, rbuf, *rbuflen);
1254         dsi_writeflush(obj->handle);
1255     }
1256
1257     *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1258     return err;
1259 }
1260
1261
1262 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1263 AFPObj      *obj;
1264 char    *ibuf, *rbuf;
1265 int             ibuflen, *rbuflen;
1266 {
1267     struct ofork        *ofork;
1268     int                 buflen, ret;
1269     u_int16_t           ofrefnum, bitmap;
1270
1271     ibuf += 2;
1272     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1273     ibuf += sizeof( ofrefnum );
1274     memcpy(&bitmap, ibuf, sizeof( bitmap ));
1275     bitmap = ntohs( bitmap );
1276     ibuf += sizeof( bitmap );
1277
1278     *rbuflen = 0;
1279     if (( ofork = of_find( ofrefnum )) == NULL ) {
1280         LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1281         return( AFPERR_PARAM );
1282     }
1283
1284     if (( ret = getforkparams( ofork, bitmap,
1285                                rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1286         return( ret );
1287     }
1288
1289     *rbuflen = buflen + sizeof( u_short );
1290     bitmap = htons( bitmap );
1291     memcpy(rbuf, &bitmap, sizeof( bitmap ));
1292     return( AFP_OK );
1293 }
1294