2 * $Id: fork.c,v 1.51.2.2.2.7 2004-03-11 02:02:01 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #include <atalk/adouble.h>
19 #include <atalk/logger.h>
21 #include <sys/param.h>
22 #include <sys/socket.h>
24 #include <netatalk/at.h>
26 #include <atalk/dsi.h>
27 #include <atalk/atp.h>
28 #include <atalk/asp.h>
29 #include <atalk/afp.h>
31 #include <atalk/util.h>
32 #include <atalk/cnid.h>
37 #include "directory.h"
42 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
47 struct ofork *writtenfork;
48 extern int getmetadata(struct vol *vol,
50 struct path *path, struct dir *dir, char *buf,
51 int *buflen, struct adouble *adp, int attrbits );
53 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
58 const u_int16_t attrbits;
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))
72 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
73 && (ofork->of_flags & AFPFORK_DATA))) {
74 return( AFPERR_BITMAP );
77 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
86 if (NULL == (path.u_name = mtoupath(vol, ofork->of_name, dir->d_did, utf8_encoding()))) {
87 return( AFPERR_MISC );
89 path.m_name = ofork->of_name;
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 );
100 if ( fstat( ad_dfileno( ofork->of_ad ), st ) < 0 ) {
101 return( AFPERR_BITMAP );
105 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp, attrbits );
108 /* ---------------------------- */
109 static off_t get_off_t(ibuf, is64)
117 memcpy(&temp, *ibuf, sizeof( temp ));
118 ret = ntohl(temp); /* ntohl is unsigned */
119 *ibuf += sizeof(temp);
122 memcpy(&temp, *ibuf, sizeof( temp ));
123 *ibuf += sizeof(temp);
124 ret = ntohl(temp)| (ret << 32);
127 ret = (int)ret; /* sign extend */
132 /* ---------------------- */
133 static int set_off_t(offset, rbuf, is64)
143 temp = htonl(offset >> 32);
144 memcpy(rbuf, &temp, sizeof( temp ));
145 rbuf += sizeof(temp);
146 ret = sizeof( temp );
147 offset &= 0xffffffff;
149 temp = htonl(offset);
150 memcpy(rbuf, &temp, sizeof( temp ));
151 ret += sizeof( temp );
156 /* ------------------------
158 static int is_neg(int is64, off_t val)
160 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
165 static __inline__ int sum_neg(int is64, off_t offset, off_t reqcount)
167 if (is_neg(is64, offset +reqcount) )
172 /* -------------------------
174 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
176 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
179 /* -------------------------
181 static int getforkmode(struct adouble *adp, int eid, int what)
183 return ad_testlock(adp, eid, what);
186 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
194 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
195 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
198 if ((access & (OPENACC_RD | OPENACC_DRD))) {
199 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
201 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
204 if ((access & OPENACC_RD) && denyreadset) {
208 if ((access & OPENACC_DRD) && readset) {
212 /* boolean logic is not enough, because getforkmode is not always telling the
215 if ((access & OPENACC_RD)) {
216 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
220 if ((access & OPENACC_DRD)) {
221 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
226 /* ------------same for writing -------------- */
227 if ((access & (OPENACC_WR | OPENACC_DWR))) {
228 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
230 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
233 if ((access & OPENACC_WR) && denywriteset) {
237 if ((access & OPENACC_DWR) && writeset) {
241 if ((access & OPENACC_WR)) {
242 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
246 if ((access & OPENACC_DWR)) {
247 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
252 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
253 return ad_excl_lock(adp, eid);
258 /* ----------------------- */
259 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
262 int ibuflen, *rbuflen;
266 struct ofork *ofork, *opened;
267 struct adouble *adsame = NULL;
268 int buflen, ret, adflags, eid;
270 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
271 char fork, *path, *upath;
278 memcpy(&vid, ibuf, sizeof( vid ));
282 if (NULL == ( vol = getvolbyvid( vid ))) {
283 return( AFPERR_PARAM );
286 memcpy(&did, ibuf, sizeof( did ));
287 ibuf += sizeof( int );
289 if (NULL == ( dir = dirlookup( vol, did ))) {
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 );
300 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
304 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
305 return get_afp_errno(AFPERR_PARAM);
308 if (*s_path->m_name == '\0') {
310 return AFPERR_BADTYPE;
313 /* stat() data fork st is set because it's not a dir */
314 switch ( s_path->st_errno ) {
320 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
322 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
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;
333 if (file_access(s_path, access ) < 0) {
334 return AFPERR_ACCESS;
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?
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);
350 adsame = opened->of_ad;
353 if ( fork == OPENFORK_DATA ) {
355 adflags = ADFLAGS_DF|ADFLAGS_HF;
358 adflags = ADFLAGS_HF;
361 path = s_path->m_name;
362 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
363 adsame, st)) == NULL ) {
364 return( AFPERR_NFILE );
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) {
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) {
383 adflags = ADFLAGS_DF;
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)
390 ofork->of_flags |= AFPFORK_OPEN;
399 ret = AFPERR_BADTYPE;
403 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
410 /* the ressource fork is open too */
411 ofork->of_flags |= AFPFORK_OPEN;
414 /* try opening in read-only mode */
416 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
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) {
429 adflags = ADFLAGS_DF;
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
446 ret = AFPERR_BADTYPE;
450 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
456 /* the ressource fork is open too */
457 ofork->of_flags |= AFPFORK_OPEN;
461 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
462 if (ad_getentryoff(ofork->of_ad, ADEID_NAME)) {
463 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
464 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
465 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
466 ad_flush( ofork->of_ad, adflags );
470 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
471 &buflen, attrbits )) != AFP_OK ) {
472 ad_close( ofork->of_ad, adflags );
476 *rbuflen = buflen + 2 * sizeof( u_int16_t );
477 bitmap = htons( bitmap );
478 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
479 rbuf += sizeof( u_int16_t );
481 /* check WriteInhibit bit if we have a ressource fork
482 * the test is done here, after some Mac trafic capture
484 if (ad_hfileno(ofork->of_ad) != -1) {
485 ad_getattr(ofork->of_ad, &bshort);
486 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
487 ad_close( ofork->of_ad, adflags );
490 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
491 return(AFPERR_OLOCK);
496 * synchronization locks:
499 /* don't try to lock non-existent rforks. */
500 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
502 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
503 /* can we access the fork? */
506 ad_close( ofork->of_ad, adflags );
509 case EAGAIN: /* return data anyway */
513 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
514 return( AFPERR_DENYCONF );
518 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(ret) );
519 return( AFPERR_PARAM );
522 if ((access & OPENACC_WR))
523 ofork->of_flags |= AFPFORK_ACCWR;
525 /* the file may be open read only without ressource fork */
526 if ((access & OPENACC_RD))
527 ofork->of_flags |= AFPFORK_ACCRD;
529 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
535 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
539 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
542 int ibuflen, *rbuflen;
546 u_int16_t ofrefnum, bitmap;
554 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
555 ibuf += sizeof( ofrefnum );
557 memcpy(&bitmap, ibuf, sizeof(bitmap));
558 bitmap = ntohs(bitmap);
559 ibuf += sizeof( bitmap );
562 if (NULL == ( ofork = of_find( ofrefnum )) ) {
563 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
564 return( AFPERR_PARAM );
567 if (ofork->of_vol->v_flags & AFPVOL_RO)
570 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
571 return AFPERR_ACCESS;
573 if ( ofork->of_flags & AFPFORK_DATA) {
575 } else if (ofork->of_flags & AFPFORK_RSRC) {
580 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
581 && eid == ADEID_RFORK
583 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
584 && eid == ADEID_DFORK)) {
585 return AFPERR_BITMAP;
589 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
590 if (afp_version >= 30) {
594 return AFPERR_BITMAP;
597 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
598 return AFPERR_PARAM ;
600 size = get_off_t(&ibuf, is64);
603 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
606 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
607 st_size = ad_size(ofork->of_ad, eid);
609 if (st_size > size &&
610 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
611 goto afp_setfork_err;
613 err = ad_dtruncate( ofork->of_ad, size );
615 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
617 goto afp_setfork_err;
618 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
619 ad_refresh( ofork->of_ad );
621 st_size = ad_size(ofork->of_ad, eid);
623 if (st_size > size &&
624 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
625 goto afp_setfork_err;
627 err = ad_rtruncate(ofork->of_ad, size);
629 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
631 goto afp_setfork_err;
633 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
634 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
638 return AFPERR_BITMAP;
641 if ( flushfork( ofork ) < 0 ) {
642 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
657 return AFPERR_ACCESS;
668 /* for this to work correctly, we need to check for locks before each
669 * read and write. that's most easily handled by always doing an
670 * appropriate check before each ad_read/ad_write. other things
671 * that can change files like truncate are handled internally to those
674 #define ENDBIT(a) ((a) & 0x80)
675 #define UNLOCKBIT(a) ((a) & 0x01)
678 /* ---------------------- */
679 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
682 int ibuflen, *rbuflen;
686 off_t offset, length;
694 /* figure out parameters */
696 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
698 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
699 ibuf += sizeof(ofrefnum);
701 if (NULL == ( ofork = of_find( ofrefnum )) ) {
702 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
703 return( AFPERR_PARAM );
706 if ( ofork->of_flags & AFPFORK_DATA) {
708 } else if (ofork->of_flags & AFPFORK_RSRC) {
713 offset = get_off_t(&ibuf, is64);
714 length = get_off_t(&ibuf, is64);
716 /* FIXME AD_FILELOCK test is surely wrong */
718 length = BYTELOCK_MAX;
719 else if (!length || is_neg(is64, length)) {
721 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
726 offset += ad_size(ofork->of_ad, eid);
727 /* FIXME what do we do if file size > 2 GB and
728 it's not byte_lock_ext?
731 if (offset < 0) /* error if we have a negative offset */
734 /* if the file is a read-only file, we use read locks instead of
735 * write locks. that way, we can prevent anyone from initiating
737 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
738 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
739 ofork->of_refnum) < 0) {
743 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
749 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
757 *rbuflen = set_off_t (offset, rbuf, is64);
761 /* --------------------------- */
762 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
765 int ibuflen, *rbuflen;
767 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
770 /* --------------------------- */
771 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
774 int ibuflen, *rbuflen;
776 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
781 /* --------------------------- */
782 static __inline__ int crlf( of )
787 if ( ad_hfileno( of->of_ad ) == -1 ||
788 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
790 if (NULL == ( em = getextmap( of->of_name )) ||
791 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
797 if ( memcmp( ufinderi,
798 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
807 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
808 off_t offset, u_char nlmask,
809 u_char nlchar, char *rbuf,
810 int *rbuflen, const int xlate)
816 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
818 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
820 return( AFPERR_PARAM );
822 if ( cc < *rbuflen ) {
830 for ( p = rbuf, q = p + cc; p < q; ) {
831 if (( *p++ & nlmask ) == nlchar ) {
842 * If this file is of type TEXT, then swap \012 to \015.
845 for ( p = rbuf, q = p + cc; p < q; p++ ) {
846 if ( *p == '\012' ) {
848 } else if ( *p == '\015' ) {
857 return( AFPERR_EOF );
862 /* -----------------------------
863 * with ddp, afp_read can return fewer bytes than in reqcount
864 * so return EOF only if read actually past end of file not
865 * if offset +reqcount > size of file
867 * getfork size ==> 10430
868 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
869 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
870 * read fork offset 9248 size 1508 ==> 1182 (EOF)
871 * 10752 is a bug in Mac 7.5.x finder
873 * with dsi, should we check that reqcount < server quantum?
875 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
878 int ibuflen, *rbuflen;
883 off_t offset, saveoff, reqcount, savereqcount;
884 int cc, err, eid, xlate = 0;
886 u_char nlmask, nlchar;
887 int non_blocking = 0;
890 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
891 ibuf += sizeof( u_short );
893 if (NULL == ( ofork = of_find( ofrefnum )) ) {
894 LOG(log_error, logtype_afpd, "afp_read: of_find");
899 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
903 offset = get_off_t(&ibuf, is64);
904 reqcount = get_off_t(&ibuf, is64);
913 /* if we wanted to be picky, we could add in the following
914 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
916 if (reqcount < 0 || offset < 0) {
921 if ( ofork->of_flags & AFPFORK_DATA) {
923 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
924 } else if (ofork->of_flags & AFPFORK_RSRC) {
926 } else { /* fork wasn't opened. this should never really happen. */
931 /* zero request count */
937 /* reqcount isn't always truthful. we need to deal with that. */
938 size = ad_size(ofork->of_ad, eid);
940 if (offset >= size) {
945 savereqcount = reqcount;
947 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
952 #define min(a,b) ((a)<(b)?(a):(b))
953 *rbuflen = min( reqcount, *rbuflen );
954 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
958 /* dsi can stream requests. we can only do this if we're not checking
959 * for an end-of-line character. oh well. */
960 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
961 DSI *dsi = obj->handle;
964 if (obj->options.flags & OPTION_DEBUG) {
965 printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID);
966 bprint(rbuf, *rbuflen);
969 /* subtract off the offset */
971 if (reqcount > size) {
978 /* dsi_readinit() returns size of next read buffer. by this point,
979 * we know that we're sending some data. if we fail, something
980 * horrible happened. */
981 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
984 /* due to the nature of afp packets, we have to exit if we get
985 an error. we can't do this with translation on. */
986 #if 0 /* idef WITH_SENDFILE */
987 /* FIXME with OS X deadlock partial workaround we can't use sendfile */
988 if (!(xlate || Debug(obj) )) {
989 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize) < 0) {
990 if (errno == EINVAL || errno == ENOSYS)
993 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
1005 /* fill up our buffer. */
1007 /* set to non blocking mode */
1011 /* fill up our buffer. */
1012 while (*rbuflen > 0) {
1013 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
1019 if (obj->options.flags & OPTION_DEBUG) {
1020 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1021 bprint(rbuf, *rbuflen);
1024 /* dsi_read() also returns buffer size of next allocation */
1025 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1034 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1036 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1042 DSI *dsi = obj->handle;
1043 /* set back to blocking mode */
1046 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1054 /* ---------------------- */
1055 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1058 int ibuflen, *rbuflen;
1060 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1063 /* ---------------------- */
1064 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1067 int ibuflen, *rbuflen;
1069 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1072 /* ---------------------- */
1073 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1076 int ibuflen, *rbuflen;
1084 memcpy(&vid, ibuf, sizeof(vid));
1085 if (NULL == ( vol = getvolbyvid( vid )) ) {
1086 return( AFPERR_PARAM );
1093 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1096 int ibuflen, *rbuflen;
1098 struct ofork *ofork;
1103 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1105 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1106 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1107 return( AFPERR_PARAM );
1110 if ( flushfork( ofork ) < 0 ) {
1111 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1117 /* this is very similar to closefork */
1118 int flushfork( ofork )
1119 struct ofork *ofork;
1123 int err = 0, doflush = 0;
1125 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1126 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1127 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1128 ad_dfileno(ofork->of_ad), strerror(errno) );
1132 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1133 (ofork->of_flags & AFPFORK_RSRC)) {
1135 /* read in the rfork length */
1136 ad_refresh(ofork->of_ad);
1138 /* set the date if we're dirty */
1139 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1140 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1141 ofork->of_flags &= ~AFPFORK_DIRTY;
1145 /* flush the header */
1146 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1149 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1153 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1154 ad_hfileno(ofork->of_ad), strerror(errno) );
1160 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1163 int ibuflen, *rbuflen;
1165 struct ofork *ofork;
1167 int adflags, doflush = 0;
1172 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1174 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1175 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1176 return( AFPERR_PARAM );
1180 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1181 adflags |= ADFLAGS_DF;
1183 if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
1184 adflags |= ADFLAGS_HF;
1186 * Only set the rfork's length if we're closing the rfork.
1188 if ((ofork->of_flags & AFPFORK_RSRC)) {
1189 ad_refresh( ofork->of_ad );
1190 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1191 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1195 ad_flush( ofork->of_ad, adflags );
1200 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1201 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1202 return( AFPERR_PARAM );
1205 of_dealloc( ofork );
1210 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1211 off_t offset, char *rbuf,
1212 size_t rbuflen, const int xlate)
1218 * If this file is of type TEXT, swap \015 to \012.
1221 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1222 if ( *p == '\015' ) {
1224 } else if ( *p == '\012' ) {
1230 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1231 rbuf, rbuflen)) < 0 ) {
1236 return( AFPERR_DFULL );
1238 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1239 return( AFPERR_PARAM );
1247 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1248 * the client may have sent us a bunch of data that's not reflected
1249 * in reqcount et al. */
1250 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1253 int ibuflen, *rbuflen;
1256 struct ofork *ofork;
1257 off_t offset, saveoff, reqcount;
1258 int endflag, eid, xlate = 0, err = AFP_OK;
1262 /* figure out parameters */
1264 endflag = ENDBIT(*ibuf);
1266 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1267 ibuf += sizeof( ofrefnum );
1269 offset = get_off_t(&ibuf, is64);
1270 reqcount = get_off_t(&ibuf, is64);
1272 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1273 LOG(log_error, logtype_afpd, "afp_write: of_find");
1278 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1279 err = AFPERR_ACCESS;
1284 writtenfork = ofork;
1287 if ( ofork->of_flags & AFPFORK_DATA) {
1289 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1290 } else if (ofork->of_flags & AFPFORK_RSRC) {
1293 err = AFPERR_ACCESS; /* should never happen */
1298 offset += ad_size(ofork->of_ad, eid);
1300 /* handle bogus parameters */
1301 if (reqcount < 0 || offset < 0) {
1306 /* offset can overflow on 64-bit capable filesystems.
1307 * report disk full if that's going to happen. */
1308 if (sum_neg(is64, offset, reqcount)) {
1313 if (!reqcount) { /* handle request counts of 0 */
1315 *rbuflen = set_off_t (offset, rbuf, is64);
1320 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1321 reqcount, ofork->of_refnum) < 0) {
1326 /* this is yucky, but dsi can stream i/o and asp can't */
1327 switch (obj->proto) {
1330 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1332 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1333 return( AFPERR_PARAM );
1337 if (obj->options.flags & OPTION_DEBUG) {
1338 printf("(write) len: %d\n", *rbuflen);
1339 bprint(rbuf, *rbuflen);
1342 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1345 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1350 #endif /* no afp/asp */
1354 DSI *dsi = obj->handle;
1356 /* find out what we have already and write it out. */
1357 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1358 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1359 dsi_writeflush(dsi);
1361 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1366 #if 0 /*def HAVE_SENDFILE_WRITE*/
1367 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1368 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1369 offset, dsi->datasize)) < 0) {
1377 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1378 goto afp_write_loop;
1380 dsi_writeflush(dsi);
1382 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1383 reqcount, ofork->of_refnum);
1388 goto afp_write_done;
1390 #endif /* 0, was HAVE_SENDFILE_WRITE */
1392 /* loop until everything gets written. currently
1393 * dsi_write handles the end case by itself. */
1394 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1396 if ( obj->options.flags & OPTION_DEBUG ) {
1397 printf("(write) command cont'd: %d\n", cc);
1401 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1402 dsi_writeflush(dsi);
1404 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1405 reqcount, ofork->of_refnum);
1414 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1415 if ( ad_hfileno( ofork->of_ad ) != -1 )
1416 ofork->of_flags |= AFPFORK_DIRTY;
1418 *rbuflen = set_off_t (offset, rbuf, is64);
1422 if (obj->proto == AFPPROTO_DSI) {
1423 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1424 dsi_writeflush(obj->handle);
1426 if (err != AFP_OK) {
1432 /* ---------------------------- */
1433 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1436 int ibuflen, *rbuflen;
1438 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1441 /* ----------------------------
1442 * FIXME need to deal with SIGXFSZ signal
1444 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1447 int ibuflen, *rbuflen;
1449 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1452 /* ---------------------------- */
1453 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1456 int ibuflen, *rbuflen;
1458 struct ofork *ofork;
1460 u_int16_t ofrefnum, bitmap;
1461 u_int16_t attrbits = 0;
1464 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1465 ibuf += sizeof( ofrefnum );
1466 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1467 bitmap = ntohs( bitmap );
1468 ibuf += sizeof( bitmap );
1471 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1472 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1473 return( AFPERR_PARAM );
1475 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1476 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1478 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1479 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1480 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1481 return( AFPERR_PARAM );
1485 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1486 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1490 *rbuflen = buflen + sizeof( u_short );
1491 bitmap = htons( bitmap );
1492 memcpy(rbuf, &bitmap, sizeof( bitmap ));