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