2 * $Id: fork.c,v 1.51.2.2.2.10 2004-05-04 15:38:25 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(%s): ad_open: %s", s_path->m_name, 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(%s): ad_open: %s", s_path->m_name, 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(%s): ad_open: %s", s_path->m_name, 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_setname(ofork->of_ad, path)) {
463 ad_flush( ofork->of_ad, adflags );
467 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
468 &buflen, attrbits )) != AFP_OK ) {
469 ad_close( ofork->of_ad, adflags );
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 );
478 /* check WriteInhibit bit if we have a ressource fork
479 * the test is done here, after some Mac trafic capture
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 );
487 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
488 return(AFPERR_OLOCK);
493 * synchronization locks:
496 /* don't try to lock non-existent rforks. */
497 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
499 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
500 /* can we access the fork? */
503 ad_close( ofork->of_ad, adflags );
506 case EAGAIN: /* return data anyway */
510 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
511 return( AFPERR_DENYCONF );
515 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
516 return( AFPERR_PARAM );
519 if ((access & OPENACC_WR))
520 ofork->of_flags |= AFPFORK_ACCWR;
522 /* the file may be open read only without ressource fork */
523 if ((access & OPENACC_RD))
524 ofork->of_flags |= AFPFORK_ACCRD;
526 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
532 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
536 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
539 int ibuflen, *rbuflen;
543 u_int16_t ofrefnum, bitmap;
551 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
552 ibuf += sizeof( ofrefnum );
554 memcpy(&bitmap, ibuf, sizeof(bitmap));
555 bitmap = ntohs(bitmap);
556 ibuf += sizeof( bitmap );
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 );
564 if (ofork->of_vol->v_flags & AFPVOL_RO)
567 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
568 return AFPERR_ACCESS;
570 if ( ofork->of_flags & AFPFORK_DATA) {
572 } else if (ofork->of_flags & AFPFORK_RSRC) {
577 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
578 && eid == ADEID_RFORK
580 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
581 && eid == ADEID_DFORK)) {
582 return AFPERR_BITMAP;
586 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
587 if (afp_version >= 30) {
591 return AFPERR_BITMAP;
594 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
595 return AFPERR_PARAM ;
597 size = get_off_t(&ibuf, is64);
600 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
603 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
604 st_size = ad_size(ofork->of_ad, eid);
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;
610 err = ad_dtruncate( ofork->of_ad, size );
612 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
614 goto afp_setfork_err;
615 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
616 ad_refresh( ofork->of_ad );
618 st_size = ad_size(ofork->of_ad, eid);
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;
624 err = ad_rtruncate(ofork->of_ad, size);
626 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
628 goto afp_setfork_err;
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) );
635 return AFPERR_BITMAP;
638 if ( flushfork( ofork ) < 0 ) {
639 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", ofork->of_name, strerror(errno) );
654 return AFPERR_ACCESS;
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
671 #define ENDBIT(a) ((a) & 0x80)
672 #define UNLOCKBIT(a) ((a) & 0x01)
675 /* ---------------------- */
676 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
679 int ibuflen, *rbuflen;
683 off_t offset, length;
691 /* figure out parameters */
693 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
695 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
696 ibuf += sizeof(ofrefnum);
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 );
703 if ( ofork->of_flags & AFPFORK_DATA) {
705 } else if (ofork->of_flags & AFPFORK_RSRC) {
710 offset = get_off_t(&ibuf, is64);
711 length = get_off_t(&ibuf, is64);
713 /* FIXME AD_FILELOCK test is surely wrong */
715 length = BYTELOCK_MAX;
716 else if (!length || is_neg(is64, length)) {
718 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
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?
728 if (offset < 0) /* error if we have a negative offset */
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
734 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
735 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
736 ofork->of_refnum) < 0) {
740 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
746 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
754 *rbuflen = set_off_t (offset, rbuf, is64);
758 /* --------------------------- */
759 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
762 int ibuflen, *rbuflen;
764 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
767 /* --------------------------- */
768 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
771 int ibuflen, *rbuflen;
773 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
778 /* --------------------------- */
779 static __inline__ int crlf( of )
784 if ( ad_hfileno( of->of_ad ) == -1 ||
785 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
787 if (NULL == ( em = getextmap( of->of_name )) ||
788 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
794 if ( memcmp( ufinderi,
795 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
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)
813 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
815 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", ofork->of_name, strerror(errno) );
817 return( AFPERR_PARAM );
819 if ( cc < *rbuflen ) {
827 for ( p = rbuf, q = p + cc; p < q; ) {
828 if (( *p++ & nlmask ) == nlchar ) {
839 * If this file is of type TEXT, then swap \012 to \015.
842 for ( p = rbuf, q = p + cc; p < q; p++ ) {
843 if ( *p == '\012' ) {
845 } else if ( *p == '\015' ) {
854 return( AFPERR_EOF );
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
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
870 * with dsi, should we check that reqcount < server quantum?
872 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
875 int ibuflen, *rbuflen;
879 off_t offset, saveoff, reqcount, savereqcount;
880 int cc, err, eid, xlate = 0;
882 u_char nlmask, nlchar;
885 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
886 ibuf += sizeof( u_short );
888 if (NULL == ( ofork = of_find( ofrefnum )) ) {
889 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
894 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
898 offset = get_off_t(&ibuf, is64);
899 reqcount = get_off_t(&ibuf, is64);
908 /* if we wanted to be picky, we could add in the following
909 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
911 if (reqcount < 0 || offset < 0) {
916 if ( ofork->of_flags & AFPFORK_DATA) {
918 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
919 } else if (ofork->of_flags & AFPFORK_RSRC) {
921 } else { /* fork wasn't opened. this should never really happen. */
926 /* zero request count */
932 savereqcount = reqcount;
934 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
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);
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;
950 int non_blocking = 0;
953 if (obj->options.flags & OPTION_DEBUG) {
954 printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID);
955 bprint(rbuf, *rbuflen);
958 /* reqcount isn't always truthful. we need to deal with that. */
959 size = ad_size(ofork->of_ad, eid);
961 /* subtract off the offset */
963 if (reqcount > size) {
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)
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)
985 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", ofork->of_name, strerror(errno));
997 /* fill up our buffer. */
999 /* set to non blocking mode */
1003 /* fill up our buffer. */
1004 while (*rbuflen > 0) {
1005 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
1011 if (obj->options.flags & OPTION_DEBUG) {
1012 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1013 bprint(rbuf, *rbuflen);
1016 /* dsi_read() also returns buffer size of next allocation */
1017 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1023 /* set back to blocking mode */
1030 LOG(log_error, logtype_afpd, "afp_read(%s): %s", ofork->of_name, strerror(errno));
1032 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1033 obj->exit(EXITERR_CLNT);
1037 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1045 /* ---------------------- */
1046 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1049 int ibuflen, *rbuflen;
1051 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1054 /* ---------------------- */
1055 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1058 int ibuflen, *rbuflen;
1060 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1063 /* ---------------------- */
1064 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1067 int ibuflen, *rbuflen;
1075 memcpy(&vid, ibuf, sizeof(vid));
1076 if (NULL == ( vol = getvolbyvid( vid )) ) {
1077 return( AFPERR_PARAM );
1084 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1087 int ibuflen, *rbuflen;
1089 struct ofork *ofork;
1094 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
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 );
1101 if ( flushfork( ofork ) < 0 ) {
1102 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", ofork->of_name, strerror(errno) );
1108 /* this is very similar to closefork */
1109 int flushfork( ofork )
1110 struct ofork *ofork;
1114 int err = 0, doflush = 0;
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) );
1123 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1124 (ofork->of_flags & AFPFORK_RSRC)) {
1126 /* read in the rfork length */
1127 ad_refresh(ofork->of_ad);
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;
1136 /* flush the header */
1137 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1140 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1144 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1145 ofork->of_name, ad_hfileno(ofork->of_ad), strerror(errno) );
1151 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1154 int ibuflen, *rbuflen;
1156 struct ofork *ofork;
1158 int adflags, doflush = 0;
1163 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
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 );
1171 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1172 adflags |= ADFLAGS_DF;
1174 if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
1175 adflags |= ADFLAGS_HF;
1177 * Only set the rfork's length if we're closing the rfork.
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);
1186 ad_flush( ofork->of_ad, adflags );
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 );
1196 of_dealloc( ofork );
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)
1209 * If this file is of type TEXT, swap \015 to \012.
1212 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1213 if ( *p == '\015' ) {
1215 } else if ( *p == '\012' ) {
1221 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1222 rbuf, rbuflen)) < 0 ) {
1227 return( AFPERR_DFULL );
1229 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", ofork->of_name, strerror(errno) );
1230 return( AFPERR_PARAM );
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)
1244 int ibuflen, *rbuflen;
1247 struct ofork *ofork;
1248 off_t offset, saveoff, reqcount;
1249 int endflag, eid, xlate = 0, err = AFP_OK;
1253 /* figure out parameters */
1255 endflag = ENDBIT(*ibuf);
1257 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1258 ibuf += sizeof( ofrefnum );
1260 offset = get_off_t(&ibuf, is64);
1261 reqcount = get_off_t(&ibuf, is64);
1263 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1264 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1269 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1270 err = AFPERR_ACCESS;
1275 writtenfork = ofork;
1278 if ( ofork->of_flags & AFPFORK_DATA) {
1280 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1281 } else if (ofork->of_flags & AFPFORK_RSRC) {
1284 err = AFPERR_ACCESS; /* should never happen */
1289 offset += ad_size(ofork->of_ad, eid);
1291 /* handle bogus parameters */
1292 if (reqcount < 0 || offset < 0) {
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)) {
1304 if (!reqcount) { /* handle request counts of 0 */
1306 *rbuflen = set_off_t (offset, rbuf, is64);
1311 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1312 reqcount, ofork->of_refnum) < 0) {
1317 /* this is yucky, but dsi can stream i/o and asp can't */
1318 switch (obj->proto) {
1321 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1323 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1324 return( AFPERR_PARAM );
1328 if (obj->options.flags & OPTION_DEBUG) {
1329 printf("(write) len: %d\n", *rbuflen);
1330 bprint(rbuf, *rbuflen);
1333 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1336 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1341 #endif /* no afp/asp */
1345 DSI *dsi = obj->handle;
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);
1352 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
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) {
1368 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1369 goto afp_write_loop;
1371 dsi_writeflush(dsi);
1373 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1374 reqcount, ofork->of_refnum);
1379 goto afp_write_done;
1381 #endif /* 0, was HAVE_SENDFILE_WRITE */
1383 /* loop until everything gets written. currently
1384 * dsi_write handles the end case by itself. */
1385 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1387 if ( obj->options.flags & OPTION_DEBUG ) {
1388 printf("(write) command cont'd: %d\n", cc);
1392 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1393 dsi_writeflush(dsi);
1395 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1396 reqcount, ofork->of_refnum);
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;
1409 *rbuflen = set_off_t (offset, rbuf, is64);
1413 if (obj->proto == AFPPROTO_DSI) {
1414 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1415 dsi_writeflush(obj->handle);
1417 if (err != AFP_OK) {
1423 /* ---------------------------- */
1424 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1427 int ibuflen, *rbuflen;
1429 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1432 /* ----------------------------
1433 * FIXME need to deal with SIGXFSZ signal
1435 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1438 int ibuflen, *rbuflen;
1440 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1443 /* ---------------------------- */
1444 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1447 int ibuflen, *rbuflen;
1449 struct ofork *ofork;
1451 u_int16_t ofrefnum, bitmap;
1452 u_int16_t attrbits = 0;
1455 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1456 ibuf += sizeof( ofrefnum );
1457 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1458 bitmap = ntohs( bitmap );
1459 ibuf += sizeof( bitmap );
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 );
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);
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 );
1476 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1477 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1481 *rbuflen = buflen + sizeof( u_short );
1482 bitmap = htons( bitmap );
1483 memcpy(rbuf, &bitmap, sizeof( bitmap ));