2 * $Id: fork.c,v 1.51.2.2.2.1 2003-09-09 16:42:20 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
15 #endif /* HAVE_UNISTD_H */
18 #endif /* HAVE_FCNTL_H */
22 #include <atalk/logger.h>
24 #include <sys/param.h>
26 #include <sys/types.h>
28 #include <sys/socket.h>
30 #include <netatalk/endian.h>
31 #include <netatalk/at.h>
33 #include <atalk/dsi.h>
34 #include <atalk/atp.h>
35 #include <atalk/asp.h>
36 #include <atalk/afp.h>
37 #include <atalk/adouble.h>
38 #include <atalk/util.h>
39 #include <atalk/cnid.h>
44 #include "directory.h"
48 struct ofork *writtenfork;
49 extern int getmetadata(struct vol *vol,
51 struct path *path, struct dir *dir, char *buf,
52 int *buflen, struct adouble *adp, int attrbits );
54 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
59 const u_int16_t attrbits;
69 /* can only get the length of the opened fork */
70 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
71 && (ofork->of_flags & AFPFORK_RSRC))
73 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
74 && (ofork->of_flags & AFPFORK_DATA))) {
75 return( AFPERR_BITMAP );
78 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
87 if (NULL == (path.u_name = mtoupath(vol, ofork->of_name, utf8_encoding()))) {
88 return( AFPERR_MISC );
90 path.m_name = ofork->of_name;
92 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
93 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
94 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
95 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
96 if (movecwd(vol, dir) < 0)
97 return( AFPERR_NOOBJ );
98 if ( stat( path.u_name, st ) < 0 )
99 return( AFPERR_NOOBJ );
101 if ( fstat( ad_dfileno( ofork->of_ad ), st ) < 0 ) {
102 return( AFPERR_BITMAP );
106 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp, attrbits );
109 /* ---------------------------- */
110 static off_t get_off_t(ibuf, is64)
118 memcpy(&temp, *ibuf, sizeof( temp ));
119 ret = ntohl(temp); /* ntohl is unsigned */
120 *ibuf += sizeof(temp);
123 memcpy(&temp, *ibuf, sizeof( temp ));
124 *ibuf += sizeof(temp);
125 ret = ntohl(temp)| (ret << 32);
128 ret = (int)ret; /* sign extend */
133 /* ---------------------- */
134 static int set_off_t(offset, rbuf, is64)
144 temp = htonl(offset >> 32);
145 memcpy(rbuf, &temp, sizeof( temp ));
146 rbuf += sizeof(temp);
147 ret = sizeof( temp );
148 offset &= 0xffffffff;
150 temp = htonl(offset);
151 memcpy(rbuf, &temp, sizeof( temp ));
152 ret += sizeof( temp );
157 /* ------------------------
159 static int is_neg(int is64, off_t val)
161 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
166 static __inline__ int sum_neg(int is64, off_t offset, off_t reqcount)
168 if (is_neg(is64, offset +reqcount) )
173 /* -------------------------
175 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
177 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
180 /* -------------------------
182 static int getforkmode(struct adouble *adp, int eid, int what)
184 return ad_testlock(adp, eid, what);
187 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
195 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
196 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
199 if ((access & (OPENACC_RD | OPENACC_DRD))) {
200 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
202 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
205 if ((access & OPENACC_RD) && denyreadset) {
209 if ((access & OPENACC_DRD) && readset) {
213 /* boolean logic is not enough, because getforkmode is not always telling the
216 if ((access & OPENACC_RD)) {
217 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
221 if ((access & OPENACC_DRD)) {
222 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
227 /* ------------same for writing -------------- */
228 if ((access & (OPENACC_WR | OPENACC_DWR))) {
229 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
231 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
234 if ((access & OPENACC_WR) && denywriteset) {
238 if ((access & OPENACC_DWR) && writeset) {
242 if ((access & OPENACC_WR)) {
243 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
247 if ((access & OPENACC_DWR)) {
248 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);
261 /* ----------------------- */
262 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
265 int ibuflen, *rbuflen;
269 struct ofork *ofork, *opened;
270 struct adouble *adsame = NULL;
271 int buflen, ret, adflags, eid;
273 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
274 char fork, *path, *upath;
281 memcpy(&vid, ibuf, sizeof( vid ));
285 if (NULL == ( vol = getvolbyvid( vid ))) {
286 return( AFPERR_PARAM );
289 memcpy(&did, ibuf, sizeof( did ));
290 ibuf += sizeof( int );
292 if (NULL == ( dir = dirlookup( vol, did ))) {
296 memcpy(&bitmap, ibuf, sizeof( bitmap ));
297 bitmap = ntohs( bitmap );
298 ibuf += sizeof( bitmap );
299 memcpy(&access, ibuf, sizeof( access ));
300 access = ntohs( access );
301 ibuf += sizeof( access );
303 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
307 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
308 return get_afp_errno(AFPERR_PARAM);
311 if (*s_path->m_name == '\0') {
313 return AFPERR_BADTYPE;
316 /* stat() data fork st is set because it's not a dir */
317 switch ( s_path->st_errno ) {
323 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
325 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
328 /* FIXME should we check it first ? */
329 upath = s_path->u_name;
330 if (!vol_unix_priv(vol)) {
331 if (check_access(upath, access ) < 0) {
332 return AFPERR_ACCESS;
336 if (file_access(s_path, access ) < 0) {
337 return AFPERR_ACCESS;
342 /* XXX: this probably isn't the best way to do this. the already
343 open bits should really be set if the fork is opened by any
344 program, not just this one. however, that's problematic to do
345 if we can't write lock files somewhere. opened is also passed to
346 ad_open so that we can keep file locks together.
347 FIXME: add the fork we are opening?
349 if ((opened = of_findname(s_path))) {
350 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
351 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
353 adsame = opened->of_ad;
356 if ( fork == OPENFORK_DATA ) {
358 adflags = ADFLAGS_DF|ADFLAGS_HF;
361 adflags = ADFLAGS_HF;
364 path = s_path->m_name;
365 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
366 adsame, st)) == NULL ) {
367 return( AFPERR_NFILE );
371 if (access & OPENACC_WR) {
372 /* try opening in read-write mode */
373 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
381 if (fork == OPENFORK_DATA) {
382 /* try to open only the data fork */
383 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
386 adflags = ADFLAGS_DF;
389 /* here's the deal. we only try to create the resource
390 * fork if the user wants to open it for write acess. */
391 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
393 ofork->of_flags |= AFPFORK_OPEN;
402 ret = AFPERR_BADTYPE;
406 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
413 /* the ressource fork is open too */
414 ofork->of_flags |= AFPFORK_OPEN;
417 /* try opening in read-only mode */
419 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
427 /* see if client asked for a read only data fork */
428 if (fork == OPENFORK_DATA) {
429 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
432 adflags = ADFLAGS_DF;
434 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
435 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
436 * then create in open read-write.
437 * FIXME , it doesn't play well with byte locking example:
438 * ressource fork open read only
439 * locking set on it (no effect, there's no file!)
440 * ressource fork open read write now
449 ret = AFPERR_BADTYPE;
453 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
459 /* the ressource fork is open too */
460 ofork->of_flags |= AFPFORK_OPEN;
464 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
465 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
466 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
467 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
468 ad_flush( ofork->of_ad, adflags );
471 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
472 &buflen, attrbits )) != AFP_OK ) {
473 ad_close( ofork->of_ad, adflags );
477 *rbuflen = buflen + 2 * sizeof( u_int16_t );
478 bitmap = htons( bitmap );
479 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
480 rbuf += sizeof( u_int16_t );
482 /* check WriteInhibit bit if we have a ressource fork
483 * the test is done here, after some Mac trafic capture
485 if (ad_hfileno(ofork->of_ad) != -1) {
486 ad_getattr(ofork->of_ad, &bshort);
487 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
488 ad_close( ofork->of_ad, adflags );
491 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
492 return(AFPERR_OLOCK);
497 * synchronization locks:
500 /* don't try to lock non-existent rforks. */
501 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
503 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
504 /* can we access the fork? */
507 ad_close( ofork->of_ad, adflags );
510 case EAGAIN: /* return data anyway */
514 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
515 return( AFPERR_DENYCONF );
519 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(ret) );
520 return( AFPERR_PARAM );
523 if ((access & OPENACC_WR))
524 ofork->of_flags |= AFPFORK_ACCWR;
526 /* the file may be open read only without ressource fork */
527 if ((access & OPENACC_RD))
528 ofork->of_flags |= AFPFORK_ACCRD;
530 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
536 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
540 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
543 int ibuflen, *rbuflen;
547 u_int16_t ofrefnum, bitmap;
555 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
556 ibuf += sizeof( ofrefnum );
558 memcpy(&bitmap, ibuf, sizeof(bitmap));
559 bitmap = ntohs(bitmap);
560 ibuf += sizeof( bitmap );
563 if (NULL == ( ofork = of_find( ofrefnum )) ) {
564 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
565 return( AFPERR_PARAM );
568 if (ofork->of_vol->v_flags & AFPVOL_RO)
571 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
572 return AFPERR_ACCESS;
574 if ( ofork->of_flags & AFPFORK_DATA) {
576 } else if (ofork->of_flags & AFPFORK_RSRC) {
581 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
582 && eid == ADEID_RFORK
584 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
585 && eid == ADEID_DFORK)) {
586 return AFPERR_BITMAP;
590 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
591 if (afp_version >= 30) {
595 return AFPERR_BITMAP;
598 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
599 return AFPERR_PARAM ;
601 size = get_off_t(&ibuf, is64);
604 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
607 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
608 st_size = ad_size(ofork->of_ad, eid);
610 if (st_size > size &&
611 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
612 goto afp_setfork_err;
614 err = ad_dtruncate( ofork->of_ad, size );
616 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
618 goto afp_setfork_err;
619 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
620 ad_refresh( ofork->of_ad );
622 st_size = ad_size(ofork->of_ad, eid);
624 if (st_size > size &&
625 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
626 goto afp_setfork_err;
628 err = ad_rtruncate(ofork->of_ad, size);
630 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
632 goto afp_setfork_err;
634 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
635 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
639 return AFPERR_BITMAP;
642 if ( flushfork( ofork ) < 0 ) {
643 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
658 return AFPERR_ACCESS;
669 /* for this to work correctly, we need to check for locks before each
670 * read and write. that's most easily handled by always doing an
671 * appropriate check before each ad_read/ad_write. other things
672 * that can change files like truncate are handled internally to those
675 #define ENDBIT(a) ((a) & 0x80)
676 #define UNLOCKBIT(a) ((a) & 0x01)
679 /* ---------------------- */
680 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
683 int ibuflen, *rbuflen;
687 off_t offset, length;
695 /* figure out parameters */
697 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
699 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
700 ibuf += sizeof(ofrefnum);
702 if (NULL == ( ofork = of_find( ofrefnum )) ) {
703 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
704 return( AFPERR_PARAM );
707 if ( ofork->of_flags & AFPFORK_DATA) {
709 } else if (ofork->of_flags & AFPFORK_RSRC) {
714 offset = get_off_t(&ibuf, is64);
715 length = get_off_t(&ibuf, is64);
717 /* FIXME AD_FILELOCK test is surely wrong */
719 length = BYTELOCK_MAX;
720 else if (!length || is_neg(is64, length)) {
722 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
727 offset += ad_size(ofork->of_ad, eid);
728 /* FIXME what do we do if file size > 2 GB and
729 it's not byte_lock_ext?
732 if (offset < 0) /* error if we have a negative offset */
735 /* if the file is a read-only file, we use read locks instead of
736 * write locks. that way, we can prevent anyone from initiating
738 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
739 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
740 ofork->of_refnum) < 0) {
744 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
750 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
758 *rbuflen = set_off_t (offset, rbuf, is64);
762 /* --------------------------- */
763 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
766 int ibuflen, *rbuflen;
768 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
771 /* --------------------------- */
772 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
775 int ibuflen, *rbuflen;
777 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
782 /* --------------------------- */
783 static __inline__ int crlf( of )
788 if ( ad_hfileno( of->of_ad ) == -1 ||
789 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
791 if (NULL == ( em = getextmap( of->of_name )) ||
792 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
798 if ( memcmp( ufinderi,
799 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
808 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
809 off_t offset, u_char nlmask,
810 u_char nlchar, char *rbuf,
811 int *rbuflen, const int xlate)
817 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
819 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
821 return( AFPERR_PARAM );
823 if ( cc < *rbuflen ) {
831 for ( p = rbuf, q = p + cc; p < q; ) {
832 if (( *p++ & nlmask ) == nlchar ) {
843 * If this file is of type TEXT, then swap \012 to \015.
846 for ( p = rbuf, q = p + cc; p < q; p++ ) {
847 if ( *p == '\012' ) {
849 } else if ( *p == '\015' ) {
858 return( AFPERR_EOF );
863 /* -----------------------------
864 * with ddp, afp_read can return fewer bytes than in reqcount
865 * so return EOF only if read actually past end of file not
866 * if offset +reqcount > size of file
868 * getfork size ==> 10430
869 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
870 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
871 * read fork offset 9248 size 1508 ==> 1182 (EOF)
872 * 10752 is a bug in Mac 7.5.x finder
874 * with dsi, should we check that reqcount < server quantum?
876 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
879 int ibuflen, *rbuflen;
884 off_t offset, saveoff, reqcount, savereqcount;
885 int cc, err, eid, xlate = 0;
887 u_char nlmask, nlchar;
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,
959 /* dsi can stream requests. we can only do this if we're not checking
960 * for an end-of-line character. oh well. */
961 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
962 DSI *dsi = obj->handle;
964 if (obj->options.flags & OPTION_DEBUG) {
965 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
966 (int) reqcount, dsi->clientID);
967 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 #ifdef HAVE_SENDFILE_READ
987 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
988 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
989 dsi->datasize) < 0) {
993 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
1003 #endif /* HAVE_SENDFILE_READ */
1005 /* fill up our buffer. */
1006 while (*rbuflen > 0) {
1007 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
1013 if (obj->options.flags & OPTION_DEBUG) {
1014 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1015 bprint(rbuf, *rbuflen);
1018 /* dsi_read() also returns buffer size of next allocation */
1019 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1028 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1030 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1035 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1043 /* ---------------------- */
1044 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1047 int ibuflen, *rbuflen;
1049 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1052 /* ---------------------- */
1053 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1056 int ibuflen, *rbuflen;
1058 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1061 /* ---------------------- */
1062 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1065 int ibuflen, *rbuflen;
1073 memcpy(&vid, ibuf, sizeof(vid));
1074 if (NULL == ( vol = getvolbyvid( vid )) ) {
1075 return( AFPERR_PARAM );
1082 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1085 int ibuflen, *rbuflen;
1087 struct ofork *ofork;
1092 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1094 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1095 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1096 return( AFPERR_PARAM );
1099 if ( flushfork( ofork ) < 0 ) {
1100 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1106 /* this is very similar to closefork */
1107 int flushfork( ofork )
1108 struct ofork *ofork;
1112 int err = 0, doflush = 0;
1114 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1115 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1116 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1117 ad_dfileno(ofork->of_ad), strerror(errno) );
1121 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1122 (ofork->of_flags & AFPFORK_RSRC)) {
1124 /* read in the rfork length */
1125 ad_refresh(ofork->of_ad);
1127 /* set the date if we're dirty */
1128 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1129 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1130 ofork->of_flags &= ~AFPFORK_DIRTY;
1134 /* flush the header */
1135 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1138 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1142 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1143 ad_hfileno(ofork->of_ad), strerror(errno) );
1149 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1152 int ibuflen, *rbuflen;
1154 struct ofork *ofork;
1156 int adflags, doflush = 0;
1161 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1163 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1164 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1165 return( AFPERR_PARAM );
1169 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1170 adflags |= ADFLAGS_DF;
1172 if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
1173 adflags |= ADFLAGS_HF;
1175 * Only set the rfork's length if we're closing the rfork.
1177 if ((ofork->of_flags & AFPFORK_RSRC)) {
1178 ad_refresh( ofork->of_ad );
1179 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1180 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1184 ad_flush( ofork->of_ad, adflags );
1189 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1190 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1191 return( AFPERR_PARAM );
1194 of_dealloc( ofork );
1199 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1200 off_t offset, char *rbuf,
1201 size_t rbuflen, const int xlate)
1207 * If this file is of type TEXT, swap \015 to \012.
1210 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1211 if ( *p == '\015' ) {
1213 } else if ( *p == '\012' ) {
1219 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1220 rbuf, rbuflen)) < 0 ) {
1225 return( AFPERR_DFULL );
1227 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1228 return( AFPERR_PARAM );
1236 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1237 * the client may have sent us a bunch of data that's not reflected
1238 * in reqcount et al. */
1239 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1242 int ibuflen, *rbuflen;
1245 struct ofork *ofork;
1246 off_t offset, saveoff, reqcount;
1247 int endflag, eid, xlate = 0, err = AFP_OK;
1251 /* figure out parameters */
1253 endflag = ENDBIT(*ibuf);
1255 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1256 ibuf += sizeof( ofrefnum );
1258 offset = get_off_t(&ibuf, is64);
1259 reqcount = get_off_t(&ibuf, is64);
1261 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1262 LOG(log_error, logtype_afpd, "afp_write: of_find");
1267 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1268 err = AFPERR_ACCESS;
1273 writtenfork = ofork;
1276 if ( ofork->of_flags & AFPFORK_DATA) {
1278 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1279 } else if (ofork->of_flags & AFPFORK_RSRC) {
1282 err = AFPERR_ACCESS; /* should never happen */
1287 offset += ad_size(ofork->of_ad, eid);
1289 /* handle bogus parameters */
1290 if (reqcount < 0 || offset < 0) {
1295 /* offset can overflow on 64-bit capable filesystems.
1296 * report disk full if that's going to happen. */
1297 if (sum_neg(is64, offset, reqcount)) {
1302 if (!reqcount) { /* handle request counts of 0 */
1304 *rbuflen = set_off_t (offset, rbuf, is64);
1309 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1310 reqcount, ofork->of_refnum) < 0) {
1315 /* this is yucky, but dsi can stream i/o and asp can't */
1316 switch (obj->proto) {
1319 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1321 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1322 return( AFPERR_PARAM );
1325 if (obj->options.flags & OPTION_DEBUG) {
1326 printf("(write) len: %d\n", *rbuflen);
1327 bprint(rbuf, *rbuflen);
1330 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1333 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1338 #endif /* no afp/asp */
1342 DSI *dsi = obj->handle;
1344 /* find out what we have already and write it out. */
1345 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1347 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1348 dsi_writeflush(dsi);
1350 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1355 #if 0 /*def HAVE_SENDFILE_WRITE*/
1356 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1357 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1358 offset, dsi->datasize)) < 0) {
1366 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1367 goto afp_write_loop;
1369 dsi_writeflush(dsi);
1371 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1372 reqcount, ofork->of_refnum);
1377 goto afp_write_done;
1379 #endif /* 0, was HAVE_SENDFILE_WRITE */
1381 /* loop until everything gets written. currently
1382 * dsi_write handles the end case by itself. */
1383 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1384 if ( obj->options.flags & OPTION_DEBUG ) {
1385 printf("(write) command cont'd: %d\n", cc);
1389 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1390 dsi_writeflush(dsi);
1392 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1393 reqcount, ofork->of_refnum);
1402 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1403 if ( ad_hfileno( ofork->of_ad ) != -1 )
1404 ofork->of_flags |= AFPFORK_DIRTY;
1406 *rbuflen = set_off_t (offset, rbuf, is64);
1410 if (obj->proto == AFPPROTO_DSI) {
1411 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1412 dsi_writeflush(obj->handle);
1414 if (err != AFP_OK) {
1420 /* ---------------------------- */
1421 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1424 int ibuflen, *rbuflen;
1426 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1429 /* ----------------------------
1430 * FIXME need to deal with SIGXFSZ signal
1432 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1435 int ibuflen, *rbuflen;
1437 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1440 /* ---------------------------- */
1441 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1444 int ibuflen, *rbuflen;
1446 struct ofork *ofork;
1448 u_int16_t ofrefnum, bitmap;
1449 u_int16_t attrbits = 0;
1452 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1453 ibuf += sizeof( ofrefnum );
1454 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1455 bitmap = ntohs( bitmap );
1456 ibuf += sizeof( bitmap );
1459 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1460 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1461 return( AFPERR_PARAM );
1463 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1464 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1466 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1467 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1468 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1469 return( AFPERR_PARAM );
1473 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1474 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1478 *rbuflen = buflen + sizeof( u_short );
1479 bitmap = htons( bitmap );
1480 memcpy(rbuf, &bitmap, sizeof( bitmap ));