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