2 * $Id: fork.c,v 1.51.2.2.2.10.2.6 2008-11-25 15:16:33 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, of_name(ofork), dir->d_did, utf8_encoding()))) {
87 return( AFPERR_MISC );
89 path.m_name = of_name(ofork);
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 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 int getforkmode(struct adouble *adp, int eid, int what)
183 return ad_testlock(adp, eid, what);
186 /* -------------------------
188 static int fork_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);
254 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
255 return ad_excl_lock(adp, eid);
260 /* ----------------------- */
261 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
264 int ibuflen _U_, *rbuflen;
268 struct ofork *ofork, *opened;
269 struct adouble *adsame = NULL;
270 int buflen, ret, adflags, eid;
272 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
273 char fork, *path, *upath;
280 memcpy(&vid, ibuf, sizeof( vid ));
284 if (NULL == ( vol = getvolbyvid( vid ))) {
285 return( AFPERR_PARAM );
288 memcpy(&did, ibuf, sizeof( did ));
289 ibuf += sizeof( int );
291 if (NULL == ( dir = dirlookup( vol, did ))) {
295 memcpy(&bitmap, ibuf, sizeof( bitmap ));
296 bitmap = ntohs( bitmap );
297 ibuf += sizeof( bitmap );
298 memcpy(&access, ibuf, sizeof( access ));
299 access = ntohs( access );
300 ibuf += sizeof( access );
302 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
306 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
307 return get_afp_errno(AFPERR_PARAM);
310 if (*s_path->m_name == '\0') {
312 return AFPERR_BADTYPE;
315 /* stat() data fork st is set because it's not a dir */
316 switch ( s_path->st_errno ) {
322 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
324 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
327 /* FIXME should we check it first ? */
328 upath = s_path->u_name;
329 if (!vol_unix_priv(vol)) {
330 if (check_access(upath, access ) < 0) {
331 return AFPERR_ACCESS;
335 if (file_access(s_path, access ) < 0) {
336 return AFPERR_ACCESS;
341 /* XXX: this probably isn't the best way to do this. the already
342 open bits should really be set if the fork is opened by any
343 program, not just this one. however, that's problematic to do
344 if we can't write lock files somewhere. opened is also passed to
345 ad_open so that we can keep file locks together.
346 FIXME: add the fork we are opening?
348 if ((opened = of_findname(s_path))) {
349 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
350 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
352 adsame = opened->of_ad;
355 if ( fork == OPENFORK_DATA ) {
357 adflags = ADFLAGS_DF|ADFLAGS_HF;
360 adflags = ADFLAGS_HF;
363 path = s_path->m_name;
364 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
365 adsame, st)) == NULL ) {
366 return( AFPERR_NFILE );
370 if (access & OPENACC_WR) {
371 /* try opening in read-write mode */
372 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
380 if (fork == OPENFORK_DATA) {
381 /* try to open only the data fork */
382 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
385 adflags = ADFLAGS_DF;
388 /* here's the deal. we only try to create the resource
389 * fork if the user wants to open it for write acess. */
390 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
392 ofork->of_flags |= AFPFORK_OPEN;
401 ret = AFPERR_BADTYPE;
405 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
412 /* the ressource fork is open too */
413 ofork->of_flags |= AFPFORK_OPEN;
416 /* try opening in read-only mode */
418 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
426 /* see if client asked for a read only data fork */
427 if (fork == OPENFORK_DATA) {
428 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
431 adflags = ADFLAGS_DF;
433 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
434 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
435 * then create in open read-write.
436 * FIXME , it doesn't play well with byte locking example:
437 * ressource fork open read only
438 * locking set on it (no effect, there's no file!)
439 * ressource fork open read write now
448 ret = AFPERR_BADTYPE;
452 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
458 /* the ressource fork is open too */
459 ofork->of_flags |= AFPFORK_OPEN;
463 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
464 if (ad_setname(ofork->of_ad, path)) {
465 ad_flush( ofork->of_ad, adflags );
469 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
470 &buflen, attrbits )) != AFP_OK ) {
471 ad_close( ofork->of_ad, adflags );
475 *rbuflen = buflen + 2 * sizeof( u_int16_t );
476 bitmap = htons( bitmap );
477 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
478 rbuf += sizeof( u_int16_t );
480 /* check WriteInhibit bit if we have a ressource fork
481 * the test is done here, after some Mac trafic capture
483 if (ad_hfileno(ofork->of_ad) != -1) {
484 ad_getattr(ofork->of_ad, &bshort);
485 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
486 ad_close( ofork->of_ad, adflags );
489 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
490 return(AFPERR_OLOCK);
495 * synchronization locks:
498 /* don't try to lock non-existent rforks. */
499 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
501 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
502 /* can we access the fork? */
505 ad_close( ofork->of_ad, adflags );
508 case EAGAIN: /* return data anyway */
512 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
513 return( AFPERR_DENYCONF );
517 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
518 return( AFPERR_PARAM );
521 if ((access & OPENACC_WR))
522 ofork->of_flags |= AFPFORK_ACCWR;
524 /* the file may be open read only without ressource fork */
525 if ((access & OPENACC_RD))
526 ofork->of_flags |= AFPFORK_ACCRD;
528 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
534 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
538 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
540 char *ibuf, *rbuf _U_;
541 int ibuflen, *rbuflen;
545 u_int16_t ofrefnum, bitmap;
553 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
554 ibuf += sizeof( ofrefnum );
556 memcpy(&bitmap, ibuf, sizeof(bitmap));
557 bitmap = ntohs(bitmap);
558 ibuf += sizeof( bitmap );
561 if (NULL == ( ofork = of_find( ofrefnum )) ) {
562 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
563 return( AFPERR_PARAM );
566 if (ofork->of_vol->v_flags & AFPVOL_RO)
569 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
570 return AFPERR_ACCESS;
572 if ( ofork->of_flags & AFPFORK_DATA) {
574 } else if (ofork->of_flags & AFPFORK_RSRC) {
579 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
580 && eid == ADEID_RFORK
582 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
583 && eid == ADEID_DFORK)) {
584 return AFPERR_BITMAP;
588 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
589 if (afp_version >= 30) {
593 return AFPERR_BITMAP;
596 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
597 return AFPERR_PARAM ;
599 size = get_off_t(&ibuf, is64);
602 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
605 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
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_dtruncate( 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;
617 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
618 ad_refresh( ofork->of_ad );
620 st_size = ad_size(ofork->of_ad, eid);
622 if (st_size > size &&
623 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
624 goto afp_setfork_err;
626 err = ad_rtruncate(ofork->of_ad, size);
628 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
630 goto afp_setfork_err;
632 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
633 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
637 return AFPERR_BITMAP;
640 if ( flushfork( ofork ) < 0 ) {
641 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
656 return AFPERR_ACCESS;
667 /* for this to work correctly, we need to check for locks before each
668 * read and write. that's most easily handled by always doing an
669 * appropriate check before each ad_read/ad_write. other things
670 * that can change files like truncate are handled internally to those
673 #define ENDBIT(a) ((a) & 0x80)
674 #define UNLOCKBIT(a) ((a) & 0x01)
677 /* ---------------------- */
678 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
681 int ibuflen _U_, *rbuflen;
685 off_t offset, length;
693 /* figure out parameters */
695 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
697 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
698 ibuf += sizeof(ofrefnum);
700 if (NULL == ( ofork = of_find( ofrefnum )) ) {
701 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
702 return( AFPERR_PARAM );
705 if ( ofork->of_flags & AFPFORK_DATA) {
707 } else if (ofork->of_flags & AFPFORK_RSRC) {
712 offset = get_off_t(&ibuf, is64);
713 length = get_off_t(&ibuf, is64);
715 /* FIXME AD_FILELOCK test is surely wrong */
717 length = BYTELOCK_MAX;
718 else if (!length || is_neg(is64, length)) {
720 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
725 offset += ad_size(ofork->of_ad, eid);
726 /* FIXME what do we do if file size > 2 GB and
727 it's not byte_lock_ext?
730 if (offset < 0) /* error if we have a negative offset */
733 /* if the file is a read-only file, we use read locks instead of
734 * write locks. that way, we can prevent anyone from initiating
736 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
737 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
738 ofork->of_refnum) < 0) {
742 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
748 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
756 *rbuflen = set_off_t (offset, rbuf, is64);
760 /* --------------------------- */
761 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
764 int ibuflen, *rbuflen;
766 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
769 /* --------------------------- */
770 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
773 int ibuflen, *rbuflen;
775 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
780 /* --------------------------- */
781 static int crlf( of )
786 if ( ad_hfileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) {
787 /* no resource fork or no finderinfo, use our files extension mapping */
788 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
791 /* file type is TEXT */
794 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
801 static ssize_t read_file(struct ofork *ofork, int eid,
802 off_t offset, u_char nlmask,
803 u_char nlchar, char *rbuf,
804 int *rbuflen, const int xlate)
810 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
812 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
814 return( AFPERR_PARAM );
816 if ( cc < *rbuflen ) {
824 for ( p = rbuf, q = p + cc; p < q; ) {
825 if (( *p++ & nlmask ) == nlchar ) {
836 * If this file is of type TEXT, then swap \012 to \015.
839 for ( p = rbuf, q = p + cc; p < q; p++ ) {
840 if ( *p == '\012' ) {
842 } else if ( *p == '\015' ) {
851 return( AFPERR_EOF );
856 /* -----------------------------
857 * with ddp, afp_read can return fewer bytes than in reqcount
858 * so return EOF only if read actually past end of file not
859 * if offset +reqcount > size of file
861 * getfork size ==> 10430
862 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
863 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
864 * read fork offset 9248 size 1508 ==> 1182 (EOF)
865 * 10752 is a bug in Mac 7.5.x finder
867 * with dsi, should we check that reqcount < server quantum?
869 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
872 int ibuflen _U_, *rbuflen;
876 off_t offset, saveoff, reqcount, savereqcount;
877 int cc, err, eid, xlate = 0;
879 u_char nlmask, nlchar;
882 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
883 ibuf += sizeof( u_short );
885 if (NULL == ( ofork = of_find( ofrefnum )) ) {
886 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
891 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
895 offset = get_off_t(&ibuf, is64);
896 reqcount = get_off_t(&ibuf, is64);
905 /* if we wanted to be picky, we could add in the following
906 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
908 if (reqcount < 0 || offset < 0) {
913 if ( ofork->of_flags & AFPFORK_DATA) {
915 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
916 } else if (ofork->of_flags & AFPFORK_RSRC) {
918 } else { /* fork wasn't opened. this should never really happen. */
923 /* zero request count */
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, xlate);
942 /* dsi can stream requests. we can only do this if we're not checking
943 * for an end-of-line character. oh well. */
944 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
945 DSI *dsi = obj->handle;
947 int non_blocking = 0;
950 if (obj->options.flags & OPTION_DEBUG) {
951 printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID);
952 bprint(rbuf, *rbuflen);
955 /* reqcount isn't always truthful. we need to deal with that. */
956 size = ad_size(ofork->of_ad, eid);
958 /* subtract off the offset */
960 if (reqcount > size) {
967 /* dsi_readinit() returns size of next read buffer. by this point,
968 * we know that we're sending some data. if we fail, something
969 * horrible happened. */
970 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
973 /* due to the nature of afp packets, we have to exit if we get
974 an error. we can't do this with translation on. */
975 #if 0 /* ifdef WITH_SENDFILE */
976 /* FIXME with OS X deadlock partial workaround we can't use sendfile */
977 if (!(xlate || Debug(obj) )) {
978 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize) < 0) {
979 if (errno == EINVAL || errno == ENOSYS)
982 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
994 /* fill up our buffer. */
996 /* set to non blocking mode */
1000 /* fill up our buffer. */
1001 while (*rbuflen > 0) {
1002 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
1008 if (obj->options.flags & OPTION_DEBUG) {
1009 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1010 bprint(rbuf, *rbuflen);
1013 /* dsi_read() also returns buffer size of next allocation */
1014 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1020 /* set back to blocking mode */
1027 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
1029 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1030 obj->exit(EXITERR_CLNT);
1034 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1042 /* ---------------------- */
1043 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1046 int ibuflen, *rbuflen;
1048 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1051 /* ---------------------- */
1052 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1055 int ibuflen, *rbuflen;
1057 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1060 /* ---------------------- */
1061 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1063 char *ibuf, *rbuf _U_;
1064 int ibuflen _U_, *rbuflen;
1072 memcpy(&vid, ibuf, sizeof(vid));
1073 if (NULL == ( vol = getvolbyvid( vid )) ) {
1074 return( AFPERR_PARAM );
1081 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1083 char *ibuf, *rbuf _U_;
1084 int ibuflen _U_, *rbuflen;
1086 struct ofork *ofork;
1091 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1093 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1094 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1095 return( AFPERR_PARAM );
1098 if ( flushfork( ofork ) < 0 ) {
1099 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1105 /* this is very similar to closefork */
1106 int flushfork( ofork )
1107 struct ofork *ofork;
1111 int err = 0, doflush = 0;
1113 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1114 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1115 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1116 of_name(ofork), ad_dfileno(ofork->of_ad), strerror(errno) );
1120 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1121 (ofork->of_flags & AFPFORK_RSRC)) {
1123 /* read in the rfork length */
1124 ad_refresh(ofork->of_ad);
1126 /* set the date if we're dirty */
1127 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1128 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1129 ofork->of_flags &= ~AFPFORK_DIRTY;
1133 /* flush the header */
1134 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1137 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1141 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1142 of_name(ofork), ad_hfileno(ofork->of_ad), strerror(errno) );
1148 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1150 char *ibuf, *rbuf _U_;
1151 int ibuflen _U_, *rbuflen;
1153 struct ofork *ofork;
1155 int adflags, doflush = 0;
1162 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1164 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1165 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1166 return( AFPERR_PARAM );
1170 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1171 adflags |= ADFLAGS_DF;
1173 if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
1174 adflags |= ADFLAGS_HF;
1176 * Only set the rfork's length if we're closing the rfork.
1178 if ((ofork->of_flags & AFPFORK_RSRC)) {
1179 ad_refresh( ofork->of_ad );
1180 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1181 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1185 ad_flush( ofork->of_ad, adflags );
1190 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1191 LOG(log_error, logtype_afpd, "afp_closefork(%s): ad_close: %s", of_name(ofork), strerror(errno) );
1195 of_dealloc( ofork );
1200 static ssize_t write_file(struct ofork *ofork, int eid,
1201 off_t offset, char *rbuf,
1202 size_t rbuflen, const int xlate)
1208 * If this file is of type TEXT, swap \015 to \012.
1211 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1212 if ( *p == '\015' ) {
1214 } else if ( *p == '\012' ) {
1220 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1221 rbuf, rbuflen)) < 0 ) {
1226 return( AFPERR_DFULL );
1228 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1229 return( AFPERR_PARAM );
1237 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1238 * the client may have sent us a bunch of data that's not reflected
1239 * in reqcount et al. */
1240 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1243 int ibuflen _U_, *rbuflen;
1246 struct ofork *ofork;
1247 off_t offset, saveoff, reqcount;
1248 int endflag, eid, xlate = 0, err = AFP_OK;
1252 /* figure out parameters */
1254 endflag = ENDBIT(*ibuf);
1256 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1257 ibuf += sizeof( ofrefnum );
1259 offset = get_off_t(&ibuf, is64);
1260 reqcount = get_off_t(&ibuf, is64);
1262 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1263 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1268 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1269 err = AFPERR_ACCESS;
1274 writtenfork = ofork;
1277 if ( ofork->of_flags & AFPFORK_DATA) {
1279 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1280 } else if (ofork->of_flags & AFPFORK_RSRC) {
1283 err = AFPERR_ACCESS; /* should never happen */
1288 offset += ad_size(ofork->of_ad, eid);
1290 /* handle bogus parameters */
1291 if (reqcount < 0 || offset < 0) {
1296 /* offset can overflow on 64-bit capable filesystems.
1297 * report disk full if that's going to happen. */
1298 if (sum_neg(is64, offset, reqcount)) {
1303 if (!reqcount) { /* handle request counts of 0 */
1305 *rbuflen = set_off_t (offset, rbuf, is64);
1310 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1311 reqcount, ofork->of_refnum) < 0) {
1316 /* this is yucky, but dsi can stream i/o and asp can't */
1317 switch (obj->proto) {
1320 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1322 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1323 return( AFPERR_PARAM );
1327 if (obj->options.flags & OPTION_DEBUG) {
1328 printf("(write) len: %d\n", *rbuflen);
1329 bprint(rbuf, *rbuflen);
1332 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1335 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1340 #endif /* no afp/asp */
1344 DSI *dsi = obj->handle;
1346 /* find out what we have already and write it out. */
1347 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1348 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1349 dsi_writeflush(dsi);
1351 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1356 #if 0 /*def HAVE_SENDFILE_WRITE*/
1357 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1358 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1359 offset, dsi->datasize)) < 0) {
1367 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1368 goto afp_write_loop;
1370 dsi_writeflush(dsi);
1372 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1373 reqcount, ofork->of_refnum);
1378 goto afp_write_done;
1380 #endif /* 0, was HAVE_SENDFILE_WRITE */
1382 /* loop until everything gets written. currently
1383 * dsi_write handles the end case by itself. */
1384 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1386 if ( obj->options.flags & OPTION_DEBUG ) {
1387 printf("(write) command cont'd: %d\n", cc);
1391 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1392 dsi_writeflush(dsi);
1394 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1395 reqcount, ofork->of_refnum);
1404 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1405 if ( ad_hfileno( ofork->of_ad ) != -1 )
1406 ofork->of_flags |= AFPFORK_DIRTY;
1408 *rbuflen = set_off_t (offset, rbuf, is64);
1412 if (obj->proto == AFPPROTO_DSI) {
1413 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1414 dsi_writeflush(obj->handle);
1416 if (err != AFP_OK) {
1422 /* ---------------------------- */
1423 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1426 int ibuflen, *rbuflen;
1428 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1431 /* ----------------------------
1432 * FIXME need to deal with SIGXFSZ signal
1434 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1437 int ibuflen, *rbuflen;
1439 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1442 /* ---------------------------- */
1443 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1446 int ibuflen _U_, *rbuflen;
1448 struct ofork *ofork;
1450 u_int16_t ofrefnum, bitmap;
1451 u_int16_t attrbits = 0;
1454 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1455 ibuf += sizeof( ofrefnum );
1456 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1457 bitmap = ntohs( bitmap );
1458 ibuf += sizeof( bitmap );
1461 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1462 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1463 return( AFPERR_PARAM );
1465 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1466 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1468 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1469 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1470 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1471 return( AFPERR_PARAM );
1475 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1476 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1480 *rbuflen = buflen + sizeof( u_short );
1481 bitmap = htons( bitmap );
1482 memcpy(rbuf, &bitmap, sizeof( bitmap ));