2 * $Id: fork.c,v 1.45 2003-01-16 21:18:15 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
15 #endif /* HAVE_UNISTD_H */
18 #endif /* HAVE_FCNTL_H */
22 #include <atalk/logger.h>
24 #include <sys/param.h>
26 #include <sys/types.h>
28 #include <sys/socket.h>
30 #include <netatalk/endian.h>
31 #include <netatalk/at.h>
33 #include <atalk/dsi.h>
34 #include <atalk/atp.h>
35 #include <atalk/asp.h>
36 #include <atalk/afp.h>
37 #include <atalk/adouble.h>
38 #include <atalk/util.h>
40 #include <atalk/cnid.h>
46 #include "directory.h"
50 struct ofork *writtenfork;
51 extern int getmetadata(struct vol *vol,
53 char *path, struct dir *dir, struct stat *st,
54 char *buf, int *buflen, struct adouble *adp, int attrbits );
56 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
61 const u_int16_t attrbits;
71 /* can only get the length of the opened fork */
72 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
73 && (ofork->of_flags & AFPFORK_RSRC))
75 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
76 && (ofork->of_flags & AFPFORK_DATA))) {
77 return( AFPERR_BITMAP );
80 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
89 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
90 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
91 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
92 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
93 upath = mtoupath(vol, ofork->of_name);
94 if (movecwd(vol, dir) < 0)
95 return( AFPERR_NOOBJ );
96 if ( stat( upath, &st ) < 0 )
97 return( AFPERR_NOOBJ );
99 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
100 return( AFPERR_BITMAP );
104 return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
107 /* ---------------------------- */
108 static off_t get_off_t(ibuf, is64)
116 memcpy(&temp, *ibuf, sizeof( temp ));
117 ret = ntohl(temp); /* ntohl is unsigned */
118 *ibuf += sizeof(temp);
121 memcpy(&temp, *ibuf, sizeof( temp ));
122 *ibuf += sizeof(temp);
123 ret = ntohl(temp)| (ret << 32);
126 ret = (int)ret; /* sign extend */
131 /* ---------------------- */
132 static int set_off_t(offset, rbuf, is64)
142 temp = htonl(offset >> 32);
143 memcpy(rbuf, &temp, sizeof( temp ));
144 rbuf += sizeof(temp);
145 ret = sizeof( temp );
146 offset &= 0xffffffff;
148 temp = htonl(offset);
149 memcpy(rbuf, &temp, sizeof( temp ));
150 ret += sizeof( temp );
155 /* ------------------------
157 static int is_neg(int is64, off_t val)
159 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
164 static __inline__ int sum_neg(int is64, off_t offset, off_t reqcount)
166 if (is_neg(is64, offset +reqcount) )
171 /* -------------------------
173 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
175 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
178 /* -------------------------
180 extern int ad_testlock(struct adouble *adp, int eid, int off);
182 static int getforkmode(struct adouble *adp, int eid, int what)
184 return ad_testlock(adp, eid, what);
187 static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
196 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
197 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
200 if ((access & (OPENACC_RD | OPENACC_DRD))) {
201 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
203 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
206 if ((access & OPENACC_RD) && denyreadset) {
210 if ((access & OPENACC_DRD) && readset) {
214 /* boolean logic is not enough, because getforkmode is not always telling the
217 if ((access & OPENACC_RD)) {
218 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
222 if ((access & OPENACC_DRD)) {
223 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
228 /* ------------same for writing -------------- */
229 if ((access & (OPENACC_WR | OPENACC_DWR))) {
230 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
232 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
235 if ((access & OPENACC_WR) && denywriteset) {
239 if ((access & OPENACC_DWR) && writeset) {
243 if ((access & OPENACC_WR)) {
244 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
248 if ((access & OPENACC_DWR)) {
249 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
257 /* ----------------------- */
258 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
261 int ibuflen, *rbuflen;
265 struct ofork *ofork, *opened;
266 struct adouble *adsame = NULL;
267 int buflen, ret, adflags, eid, lockop;
269 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
270 char fork, *path, *upath;
277 memcpy(&vid, ibuf, sizeof( vid ));
281 if (NULL == ( vol = getvolbyvid( vid ))) {
282 return( AFPERR_PARAM );
285 memcpy(&did, ibuf, sizeof( did ));
286 ibuf += sizeof( int );
288 if (NULL == ( dir = dirlookup( vol, did ))) {
292 memcpy(&bitmap, ibuf, sizeof( bitmap ));
293 bitmap = ntohs( bitmap );
294 ibuf += sizeof( bitmap );
295 memcpy(&access, ibuf, sizeof( access ));
296 access = ntohs( access );
297 ibuf += sizeof( access );
299 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
303 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
307 if (*s_path->m_name == '\0') {
309 return AFPERR_BADTYPE;
312 /* stat() data fork st is set because it's not a dir */
313 switch ( s_path->st_errno ) {
319 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
321 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
324 /* FIXME should we check it first ? */
325 upath = s_path->u_name;
326 if (check_access(upath, access ) < 0) {
327 return AFPERR_ACCESS;
331 /* XXX: this probably isn't the best way to do this. the already
332 open bits should really be set if the fork is opened by any
333 program, not just this one. however, that's problematic to do
334 if we can't write lock files somewhere. opened is also passed to
335 ad_open so that we can keep file locks together.
336 FIXME: add the fork we are opening?
338 if ((opened = of_findname(s_path))) {
339 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
340 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
342 adsame = opened->of_ad;
345 if ( fork == OPENFORK_DATA ) {
347 adflags = ADFLAGS_DF|ADFLAGS_HF;
350 adflags = ADFLAGS_HF;
353 path = s_path->m_name;
354 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
355 adsame, st)) == NULL ) {
356 return( AFPERR_NFILE );
360 if (access & OPENACC_WR) {
361 /* try opening in read-write mode */
362 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
370 if (fork == OPENFORK_DATA) {
371 /* try to open only the data fork */
372 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
375 adflags = ADFLAGS_DF;
378 /* here's the deal. we only try to create the resource
379 * fork if the user wants to open it for write acess. */
380 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
390 ret = AFPERR_BADTYPE;
394 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
400 /* the fork is open */
401 ofork->of_flags |= AFPFORK_OPEN;
403 /* try opening in read-only mode */
405 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
413 /* see if client asked for a read only data fork */
414 if (fork == OPENFORK_DATA) {
415 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
418 adflags = ADFLAGS_DF;
419 ofork->of_flags |= AFPFORK_OPEN;
421 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
422 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
423 * then create in open read-write.
432 ret = AFPERR_BADTYPE;
436 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
442 /* the fork is open */
443 ofork->of_flags |= AFPFORK_OPEN;
447 if ((adflags & ADFLAGS_HF) &&
448 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
449 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
450 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
451 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
452 ad_flush( ofork->of_ad, adflags );
455 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
456 &buflen, attrbits )) != AFP_OK ) {
457 ad_close( ofork->of_ad, adflags );
461 *rbuflen = buflen + 2 * sizeof( u_int16_t );
462 bitmap = htons( bitmap );
463 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
464 rbuf += sizeof( u_int16_t );
466 /* check WriteInhibit bit if we have a ressource fork
467 * the test is done here, after some Mac trafic capture
469 if (ad_hfileno(ofork->of_ad) != -1) {
470 ad_getattr(ofork->of_ad, &bshort);
471 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
472 ad_close( ofork->of_ad, adflags );
475 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
476 return(AFPERR_OLOCK);
481 * synchronization locks:
484 /* don't try to lock non-existent rforks. */
485 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
487 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
488 /* can we access the fork? */
491 ad_close( ofork->of_ad, adflags );
494 case EAGAIN: /* return data anyway */
498 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
499 return( AFPERR_DENYCONF );
503 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
504 return( AFPERR_PARAM );
507 if ((access & OPENACC_WR))
508 ofork->of_flags |= AFPFORK_ACCWR;
510 /* the file may be open read only without ressource fork */
511 if ((access & OPENACC_RD))
512 ofork->of_flags |= AFPFORK_ACCRD;
514 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
520 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
524 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
527 int ibuflen, *rbuflen;
531 u_int16_t ofrefnum, bitmap;
539 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
540 ibuf += sizeof( ofrefnum );
542 memcpy(&bitmap, ibuf, sizeof(bitmap));
543 bitmap = ntohs(bitmap);
544 ibuf += sizeof( bitmap );
547 if (NULL == ( ofork = of_find( ofrefnum )) ) {
548 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
549 return( AFPERR_PARAM );
552 if (ofork->of_vol->v_flags & AFPVOL_RO)
555 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
556 return AFPERR_ACCESS;
558 if ( ofork->of_flags & AFPFORK_DATA) {
560 } else if (ofork->of_flags & AFPFORK_RSRC) {
565 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
566 && eid == ADEID_RFORK
568 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
569 && eid == ADEID_DFORK)) {
570 return AFPERR_BITMAP;
574 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
575 if (afp_version >= 30) {
579 return AFPERR_BITMAP;
582 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
583 return AFPERR_PARAM ;
585 size = get_off_t(&ibuf, is64);
588 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
591 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
592 st_size = ad_size(ofork->of_ad, eid);
594 if (st_size > size &&
595 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
596 goto afp_setfork_err;
598 err = ad_dtruncate( ofork->of_ad, size );
600 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
602 goto afp_setfork_err;
603 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
604 ad_refresh( ofork->of_ad );
606 st_size = ad_size(ofork->of_ad, eid);
608 if (st_size > size &&
609 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
610 goto afp_setfork_err;
612 err = ad_rtruncate(ofork->of_ad, size);
614 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
616 goto afp_setfork_err;
618 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
619 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
623 return AFPERR_BITMAP;
626 if ( flushfork( ofork ) < 0 ) {
627 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
642 return AFPERR_ACCESS;
653 /* for this to work correctly, we need to check for locks before each
654 * read and write. that's most easily handled by always doing an
655 * appropriate check before each ad_read/ad_write. other things
656 * that can change files like truncate are handled internally to those
659 #define ENDBIT(a) ((a) & 0x80)
660 #define UNLOCKBIT(a) ((a) & 0x01)
663 /* ---------------------- */
664 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
667 int ibuflen, *rbuflen;
671 off_t offset, length;
679 /* figure out parameters */
681 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
683 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
684 ibuf += sizeof(ofrefnum);
686 if (NULL == ( ofork = of_find( ofrefnum )) ) {
687 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
688 return( AFPERR_PARAM );
691 if ( ofork->of_flags & AFPFORK_DATA) {
693 } else if (ofork->of_flags & AFPFORK_RSRC) {
698 offset = get_off_t(&ibuf, is64);
699 length = get_off_t(&ibuf, is64);
701 /* FIXME AD_FILELOCK test is surely wrong */
703 length = BYTELOCK_MAX;
704 else if (!length || is_neg(is64, length)) {
706 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
711 offset += ad_size(ofork->of_ad, eid);
712 /* FIXME what do we do if file size > 2 GB and
713 it's not byte_lock_ext?
716 if (offset < 0) /* error if we have a negative offset */
719 /* if the file is a read-only file, we use read locks instead of
720 * write locks. that way, we can prevent anyone from initiating
722 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
723 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
724 ofork->of_refnum) < 0) {
728 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
734 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
742 *rbuflen = set_off_t (offset, rbuf, is64);
746 /* --------------------------- */
747 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
750 int ibuflen, *rbuflen;
752 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
755 /* --------------------------- */
756 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
759 int ibuflen, *rbuflen;
761 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
766 /* --------------------------- */
767 static __inline__ int crlf( of )
772 if ( ad_hfileno( of->of_ad ) == -1 ||
773 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
775 if (( em = getextmap( of->of_name )) == NULL ||
776 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
782 if ( memcmp( ufinderi,
783 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
792 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
793 off_t offset, u_char nlmask,
794 u_char nlchar, char *rbuf,
795 int *rbuflen, const int xlate)
801 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
803 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
805 return( AFPERR_PARAM );
807 if ( cc < *rbuflen ) {
815 for ( p = rbuf, q = p + cc; p < q; ) {
816 if (( *p++ & nlmask ) == nlchar ) {
827 * If this file is of type TEXT, then swap \012 to \015.
830 for ( p = rbuf, q = p + cc; p < q; p++ ) {
831 if ( *p == '\012' ) {
833 } else if ( *p == '\015' ) {
842 return( AFPERR_EOF );
847 /* -----------------------------
848 * with ddp, afp_read can return fewer bytes than in reqcount
849 * so return EOF only if read actually past end of file not
850 * if offset +reqcount > size of file
852 * getfork size ==> 10430
853 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
854 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
855 * read fork offset 9248 size 1508 ==> 1182 (EOF)
856 * 10752 is a bug in Mac 7.5.x finder
858 * with dsi, should we check that reqcount < server quantum?
860 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
863 int ibuflen, *rbuflen;
868 off_t offset, saveoff, reqcount, savereqcount;
869 int cc, err, eid, xlate = 0;
871 u_char nlmask, nlchar;
874 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
875 ibuf += sizeof( u_short );
877 if (NULL == ( ofork = of_find( ofrefnum )) ) {
878 LOG(log_error, logtype_afpd, "afp_read: of_find");
883 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
887 offset = get_off_t(&ibuf, is64);
888 reqcount = get_off_t(&ibuf, is64);
897 /* if we wanted to be picky, we could add in the following
898 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
900 if (reqcount < 0 || offset < 0) {
905 if ( ofork->of_flags & AFPFORK_DATA) {
907 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
908 } else if (ofork->of_flags & AFPFORK_RSRC) {
910 } else { /* fork wasn't opened. this should never really happen. */
915 /* zero request count */
921 /* reqcount isn't always truthful. we need to deal with that. */
922 size = ad_size(ofork->of_ad, eid);
924 if (offset >= size) {
929 savereqcount = reqcount;
931 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
936 #define min(a,b) ((a)<(b)?(a):(b))
937 *rbuflen = min( reqcount, *rbuflen );
938 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
943 /* dsi can stream requests. we can only do this if we're not checking
944 * for an end-of-line character. oh well. */
945 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
946 DSI *dsi = obj->handle;
948 if (obj->options.flags & OPTION_DEBUG) {
949 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
950 (int) reqcount, dsi->clientID);
951 bprint(rbuf, *rbuflen);
953 /* subtract off the offset */
955 if (reqcount > size) {
962 /* dsi_readinit() returns size of next read buffer. by this point,
963 * we know that we're sending some data. if we fail, something
964 * horrible happened. */
965 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
968 /* due to the nature of afp packets, we have to exit if we get
969 an error. we can't do this with translation on. */
970 #ifdef HAVE_SENDFILE_READ
971 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
972 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
973 dsi->datasize) < 0) {
977 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
987 #endif /* HAVE_SENDFILE_READ */
989 /* fill up our buffer. */
990 while (*rbuflen > 0) {
991 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
997 if (obj->options.flags & OPTION_DEBUG) {
998 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
999 bprint(rbuf, *rbuflen);
1002 /* dsi_read() also returns buffer size of next allocation */
1003 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1012 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1014 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1019 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1027 /* ---------------------- */
1028 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1031 int ibuflen, *rbuflen;
1033 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1036 /* ---------------------- */
1037 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1040 int ibuflen, *rbuflen;
1042 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1045 /* ---------------------- */
1046 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1049 int ibuflen, *rbuflen;
1057 memcpy(&vid, ibuf, sizeof(vid));
1058 if (NULL == ( vol = getvolbyvid( vid )) ) {
1059 return( AFPERR_PARAM );
1066 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1069 int ibuflen, *rbuflen;
1071 struct ofork *ofork;
1076 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1078 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1079 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1080 return( AFPERR_PARAM );
1083 if ( flushfork( ofork ) < 0 ) {
1084 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1090 /* this is very similar to closefork */
1091 int flushfork( ofork )
1092 struct ofork *ofork;
1096 int err = 0, doflush = 0;
1098 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1099 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1100 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1101 ad_dfileno(ofork->of_ad), strerror(errno) );
1105 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1106 (ofork->of_flags & AFPFORK_RSRC)) {
1108 /* read in the rfork length */
1109 ad_refresh(ofork->of_ad);
1111 /* set the date if we're dirty */
1112 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1113 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1114 ofork->of_flags &= ~AFPFORK_DIRTY;
1118 /* flush the header */
1119 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1122 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1126 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1127 ad_hfileno(ofork->of_ad), strerror(errno) );
1133 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1136 int ibuflen, *rbuflen;
1138 struct ofork *ofork;
1140 int adflags, doflush = 0;
1145 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1147 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1148 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1149 return( AFPERR_PARAM );
1153 if ((ofork->of_flags & AFPFORK_OPEN)) {
1154 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1155 adflags |= ADFLAGS_DF;
1157 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1158 adflags |= ADFLAGS_HF;
1160 * Only set the rfork's length if we're closing the rfork.
1162 if ((ofork->of_flags & AFPFORK_RSRC)) {
1163 ad_refresh( ofork->of_ad );
1164 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1165 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1169 ad_flush( ofork->of_ad, adflags );
1174 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1175 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1176 return( AFPERR_PARAM );
1180 of_dealloc( ofork );
1185 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1186 off_t offset, char *rbuf,
1187 size_t rbuflen, const int xlate)
1193 * If this file is of type TEXT, swap \015 to \012.
1196 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1197 if ( *p == '\015' ) {
1199 } else if ( *p == '\012' ) {
1205 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1206 rbuf, rbuflen)) < 0 ) {
1211 return( AFPERR_DFULL );
1213 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1214 return( AFPERR_PARAM );
1222 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1223 * the client may have sent us a bunch of data that's not reflected
1224 * in reqcount et al. */
1225 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1228 int ibuflen, *rbuflen;
1231 struct ofork *ofork;
1232 off_t offset, saveoff, reqcount;
1233 int endflag, eid, xlate = 0, err = AFP_OK;
1237 /* figure out parameters */
1239 endflag = ENDBIT(*ibuf);
1241 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1242 ibuf += sizeof( ofrefnum );
1244 offset = get_off_t(&ibuf, is64);
1245 reqcount = get_off_t(&ibuf, is64);
1247 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1248 LOG(log_error, logtype_afpd, "afp_write: of_find");
1253 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1254 err = AFPERR_ACCESS;
1259 writtenfork = ofork;
1262 if ( ofork->of_flags & AFPFORK_DATA) {
1264 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1265 } else if (ofork->of_flags & AFPFORK_RSRC) {
1268 err = AFPERR_ACCESS; /* should never happen */
1273 offset += ad_size(ofork->of_ad, eid);
1275 /* handle bogus parameters */
1276 if (reqcount < 0 || offset < 0) {
1281 /* offset can overflow on 64-bit capable filesystems.
1282 * report disk full if that's going to happen. */
1283 if (sum_neg(is64, offset, reqcount)) {
1288 if (!reqcount) { /* handle request counts of 0 */
1290 *rbuflen = set_off_t (offset, rbuf, is64);
1295 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1296 reqcount, ofork->of_refnum) < 0) {
1301 /* this is yucky, but dsi can stream i/o and asp can't */
1302 switch (obj->proto) {
1305 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1307 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1308 return( AFPERR_PARAM );
1311 if (obj->options.flags & OPTION_DEBUG) {
1312 printf("(write) len: %d\n", *rbuflen);
1313 bprint(rbuf, *rbuflen);
1316 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1319 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1324 #endif /* no afp/asp */
1328 DSI *dsi = obj->handle;
1330 /* find out what we have already and write it out. */
1331 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1333 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1334 dsi_writeflush(dsi);
1336 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1341 #if 0 /*def HAVE_SENDFILE_WRITE*/
1342 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1343 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1344 offset, dsi->datasize)) < 0) {
1352 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1353 goto afp_write_loop;
1355 dsi_writeflush(dsi);
1357 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1358 reqcount, ofork->of_refnum);
1363 goto afp_write_done;
1365 #endif /* 0, was HAVE_SENDFILE_WRITE */
1367 /* loop until everything gets written. currently
1368 * dsi_write handles the end case by itself. */
1369 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1370 if ( obj->options.flags & OPTION_DEBUG ) {
1371 printf("(write) command cont'd: %d\n", cc);
1375 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1376 dsi_writeflush(dsi);
1378 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1379 reqcount, ofork->of_refnum);
1388 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1389 if ( ad_hfileno( ofork->of_ad ) != -1 )
1390 ofork->of_flags |= AFPFORK_DIRTY;
1392 *rbuflen = set_off_t (offset, rbuf, is64);
1396 if (obj->proto == AFPPROTO_DSI) {
1397 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1398 dsi_writeflush(obj->handle);
1401 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1405 /* ---------------------------- */
1406 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1409 int ibuflen, *rbuflen;
1411 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1414 /* ----------------------------
1415 * FIXME need to deal with SIGXFSZ signal
1417 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1420 int ibuflen, *rbuflen;
1422 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1425 /* ---------------------------- */
1426 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1429 int ibuflen, *rbuflen;
1431 struct ofork *ofork;
1433 u_int16_t ofrefnum, bitmap;
1434 u_int16_t attrbits = 0;
1437 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1438 ibuf += sizeof( ofrefnum );
1439 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1440 bitmap = ntohs( bitmap );
1441 ibuf += sizeof( bitmap );
1444 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1445 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1446 return( AFPERR_PARAM );
1448 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1449 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1451 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1452 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1453 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1454 return( AFPERR_PARAM );
1458 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1459 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1463 *rbuflen = buflen + sizeof( u_short );
1464 bitmap = htons( bitmap );
1465 memcpy(rbuf, &bitmap, sizeof( bitmap ));