2 * $Id: fork.c,v 1.54 2005-04-28 20:49:43 bfernhomberg 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 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", ofork->of_name, strerror(errno) );
637 return AFPERR_BITMAP;
640 if ( flushfork( ofork ) < 0 ) {
641 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", ofork->of_name, 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 __inline__ 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->of_name )) || 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 __inline__ 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", ofork->of_name, 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", ofork->of_name, 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", ofork->of_name, 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", ofork->of_name, 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 ofork->of_name, 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 ofork->of_name, 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;
1158 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1160 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1161 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1162 return( AFPERR_PARAM );
1164 if ( of_closefork( ofork ) < 0 ) {
1165 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", ofork->of_name, strerror(errno) );
1166 return( AFPERR_PARAM );
1173 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1174 off_t offset, char *rbuf,
1175 size_t rbuflen, const int xlate)
1181 * If this file is of type TEXT, swap \015 to \012.
1184 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1185 if ( *p == '\015' ) {
1187 } else if ( *p == '\012' ) {
1193 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1194 rbuf, rbuflen)) < 0 ) {
1199 return( AFPERR_DFULL );
1201 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", ofork->of_name, strerror(errno) );
1202 return( AFPERR_PARAM );
1210 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1211 * the client may have sent us a bunch of data that's not reflected
1212 * in reqcount et al. */
1213 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1216 int ibuflen _U_, *rbuflen;
1219 struct ofork *ofork;
1220 off_t offset, saveoff, reqcount;
1221 int endflag, eid, xlate = 0, err = AFP_OK;
1225 /* figure out parameters */
1227 endflag = ENDBIT(*ibuf);
1229 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1230 ibuf += sizeof( ofrefnum );
1232 offset = get_off_t(&ibuf, is64);
1233 reqcount = get_off_t(&ibuf, is64);
1235 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1236 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1241 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1242 err = AFPERR_ACCESS;
1247 writtenfork = ofork;
1250 if ( ofork->of_flags & AFPFORK_DATA) {
1252 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1253 } else if (ofork->of_flags & AFPFORK_RSRC) {
1256 err = AFPERR_ACCESS; /* should never happen */
1261 offset += ad_size(ofork->of_ad, eid);
1263 /* handle bogus parameters */
1264 if (reqcount < 0 || offset < 0) {
1269 /* offset can overflow on 64-bit capable filesystems.
1270 * report disk full if that's going to happen. */
1271 if (sum_neg(is64, offset, reqcount)) {
1276 if (!reqcount) { /* handle request counts of 0 */
1278 *rbuflen = set_off_t (offset, rbuf, is64);
1283 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1284 reqcount, ofork->of_refnum) < 0) {
1289 /* this is yucky, but dsi can stream i/o and asp can't */
1290 switch (obj->proto) {
1293 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1295 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1296 return( AFPERR_PARAM );
1300 if (obj->options.flags & OPTION_DEBUG) {
1301 printf("(write) len: %d\n", *rbuflen);
1302 bprint(rbuf, *rbuflen);
1305 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1308 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1313 #endif /* no afp/asp */
1317 DSI *dsi = obj->handle;
1319 /* find out what we have already and write it out. */
1320 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1321 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1322 dsi_writeflush(dsi);
1324 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1329 #if 0 /*def HAVE_SENDFILE_WRITE*/
1330 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1331 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1332 offset, dsi->datasize)) < 0) {
1340 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1341 goto afp_write_loop;
1343 dsi_writeflush(dsi);
1345 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1346 reqcount, ofork->of_refnum);
1351 goto afp_write_done;
1353 #endif /* 0, was HAVE_SENDFILE_WRITE */
1355 /* loop until everything gets written. currently
1356 * dsi_write handles the end case by itself. */
1357 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1359 if ( obj->options.flags & OPTION_DEBUG ) {
1360 printf("(write) command cont'd: %d\n", cc);
1364 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1365 dsi_writeflush(dsi);
1367 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1368 reqcount, ofork->of_refnum);
1377 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1378 if ( ad_hfileno( ofork->of_ad ) != -1 )
1379 ofork->of_flags |= AFPFORK_DIRTY;
1381 *rbuflen = set_off_t (offset, rbuf, is64);
1385 if (obj->proto == AFPPROTO_DSI) {
1386 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1387 dsi_writeflush(obj->handle);
1389 if (err != AFP_OK) {
1395 /* ---------------------------- */
1396 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1399 int ibuflen, *rbuflen;
1401 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1404 /* ----------------------------
1405 * FIXME need to deal with SIGXFSZ signal
1407 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1410 int ibuflen, *rbuflen;
1412 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1415 /* ---------------------------- */
1416 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1419 int ibuflen _U_, *rbuflen;
1421 struct ofork *ofork;
1423 u_int16_t ofrefnum, bitmap;
1424 u_int16_t attrbits = 0;
1427 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1428 ibuf += sizeof( ofrefnum );
1429 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1430 bitmap = ntohs( bitmap );
1431 ibuf += sizeof( bitmap );
1434 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1435 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1436 return( AFPERR_PARAM );
1438 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1439 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1441 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1442 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1443 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", ofork->of_name, strerror(errno) );
1444 return( AFPERR_PARAM );
1448 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1449 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1453 *rbuflen = buflen + sizeof( u_short );
1454 bitmap = htons( bitmap );
1455 memcpy(rbuf, &bitmap, sizeof( bitmap ));