2 * $Id: fork.c,v 1.49 2003-02-16 12:35:04 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>
40 #include <atalk/cnid.h>
46 #include "directory.h"
50 struct ofork *writtenfork;
51 extern int getmetadata(struct vol *vol,
53 struct path *path, struct dir *dir, char *buf,
54 int *buflen, struct adouble *adp, int attrbits );
56 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
61 const u_int16_t attrbits;
71 /* can only get the length of the opened fork */
72 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
73 && (ofork->of_flags & AFPFORK_RSRC))
75 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
76 && (ofork->of_flags & AFPFORK_DATA))) {
77 return( AFPERR_BITMAP );
80 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
89 path.u_name = mtoupath(vol, ofork->of_name);
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 ))) {
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 (check_access(upath, access ) < 0) {
331 return AFPERR_ACCESS;
335 /* XXX: this probably isn't the best way to do this. the already
336 open bits should really be set if the fork is opened by any
337 program, not just this one. however, that's problematic to do
338 if we can't write lock files somewhere. opened is also passed to
339 ad_open so that we can keep file locks together.
340 FIXME: add the fork we are opening?
342 if ((opened = of_findname(s_path))) {
343 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
344 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
346 adsame = opened->of_ad;
349 if ( fork == OPENFORK_DATA ) {
351 adflags = ADFLAGS_DF|ADFLAGS_HF;
354 adflags = ADFLAGS_HF;
357 path = s_path->m_name;
358 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
359 adsame, st)) == NULL ) {
360 return( AFPERR_NFILE );
364 if (access & OPENACC_WR) {
365 /* try opening in read-write mode */
366 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
374 if (fork == OPENFORK_DATA) {
375 /* try to open only the data fork */
376 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
379 adflags = ADFLAGS_DF;
382 /* here's the deal. we only try to create the resource
383 * fork if the user wants to open it for write acess. */
384 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
386 ofork->of_flags |= AFPFORK_OPEN;
395 ret = AFPERR_BADTYPE;
399 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
406 /* the ressource fork is open too */
407 ofork->of_flags |= AFPFORK_OPEN;
410 /* try opening in read-only mode */
412 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
420 /* see if client asked for a read only data fork */
421 if (fork == OPENFORK_DATA) {
422 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
425 adflags = ADFLAGS_DF;
427 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
428 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
429 * then create in open read-write.
438 ret = AFPERR_BADTYPE;
442 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
448 /* the ressource fork is open too */
449 ofork->of_flags |= AFPFORK_OPEN;
453 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
454 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
455 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
456 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
457 ad_flush( ofork->of_ad, adflags );
460 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
461 &buflen, attrbits )) != AFP_OK ) {
462 ad_close( ofork->of_ad, adflags );
466 *rbuflen = buflen + 2 * sizeof( u_int16_t );
467 bitmap = htons( bitmap );
468 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
469 rbuf += sizeof( u_int16_t );
471 /* check WriteInhibit bit if we have a ressource fork
472 * the test is done here, after some Mac trafic capture
474 if (ad_hfileno(ofork->of_ad) != -1) {
475 ad_getattr(ofork->of_ad, &bshort);
476 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
477 ad_close( ofork->of_ad, adflags );
480 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
481 return(AFPERR_OLOCK);
486 * synchronization locks:
489 /* don't try to lock non-existent rforks. */
490 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
492 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
493 /* can we access the fork? */
496 ad_close( ofork->of_ad, adflags );
499 case EAGAIN: /* return data anyway */
503 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
504 return( AFPERR_DENYCONF );
508 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(ret) );
509 return( AFPERR_PARAM );
512 if ((access & OPENACC_WR))
513 ofork->of_flags |= AFPFORK_ACCWR;
515 /* the file may be open read only without ressource fork */
516 if ((access & OPENACC_RD))
517 ofork->of_flags |= AFPFORK_ACCRD;
519 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
525 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
529 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
532 int ibuflen, *rbuflen;
536 u_int16_t ofrefnum, bitmap;
544 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
545 ibuf += sizeof( ofrefnum );
547 memcpy(&bitmap, ibuf, sizeof(bitmap));
548 bitmap = ntohs(bitmap);
549 ibuf += sizeof( bitmap );
552 if (NULL == ( ofork = of_find( ofrefnum )) ) {
553 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
554 return( AFPERR_PARAM );
557 if (ofork->of_vol->v_flags & AFPVOL_RO)
560 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
561 return AFPERR_ACCESS;
563 if ( ofork->of_flags & AFPFORK_DATA) {
565 } else if (ofork->of_flags & AFPFORK_RSRC) {
570 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
571 && eid == ADEID_RFORK
573 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
574 && eid == ADEID_DFORK)) {
575 return AFPERR_BITMAP;
579 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
580 if (afp_version >= 30) {
584 return AFPERR_BITMAP;
587 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
588 return AFPERR_PARAM ;
590 size = get_off_t(&ibuf, is64);
593 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
596 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
597 st_size = ad_size(ofork->of_ad, eid);
599 if (st_size > size &&
600 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
601 goto afp_setfork_err;
603 err = ad_dtruncate( ofork->of_ad, size );
605 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
607 goto afp_setfork_err;
608 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
609 ad_refresh( ofork->of_ad );
611 st_size = ad_size(ofork->of_ad, eid);
613 if (st_size > size &&
614 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
615 goto afp_setfork_err;
617 err = ad_rtruncate(ofork->of_ad, size);
619 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
621 goto afp_setfork_err;
623 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
624 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
628 return AFPERR_BITMAP;
631 if ( flushfork( ofork ) < 0 ) {
632 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
647 return AFPERR_ACCESS;
658 /* for this to work correctly, we need to check for locks before each
659 * read and write. that's most easily handled by always doing an
660 * appropriate check before each ad_read/ad_write. other things
661 * that can change files like truncate are handled internally to those
664 #define ENDBIT(a) ((a) & 0x80)
665 #define UNLOCKBIT(a) ((a) & 0x01)
668 /* ---------------------- */
669 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
672 int ibuflen, *rbuflen;
676 off_t offset, length;
684 /* figure out parameters */
686 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
688 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
689 ibuf += sizeof(ofrefnum);
691 if (NULL == ( ofork = of_find( ofrefnum )) ) {
692 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
693 return( AFPERR_PARAM );
696 if ( ofork->of_flags & AFPFORK_DATA) {
698 } else if (ofork->of_flags & AFPFORK_RSRC) {
703 offset = get_off_t(&ibuf, is64);
704 length = get_off_t(&ibuf, is64);
706 /* FIXME AD_FILELOCK test is surely wrong */
708 length = BYTELOCK_MAX;
709 else if (!length || is_neg(is64, length)) {
711 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
716 offset += ad_size(ofork->of_ad, eid);
717 /* FIXME what do we do if file size > 2 GB and
718 it's not byte_lock_ext?
721 if (offset < 0) /* error if we have a negative offset */
724 /* if the file is a read-only file, we use read locks instead of
725 * write locks. that way, we can prevent anyone from initiating
727 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
728 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
729 ofork->of_refnum) < 0) {
733 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
739 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
747 *rbuflen = set_off_t (offset, rbuf, is64);
751 /* --------------------------- */
752 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
755 int ibuflen, *rbuflen;
757 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
760 /* --------------------------- */
761 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
764 int ibuflen, *rbuflen;
766 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
771 /* --------------------------- */
772 static __inline__ int crlf( of )
777 if ( ad_hfileno( of->of_ad ) == -1 ||
778 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
780 if (NULL == ( em = getextmap( of->of_name )) ||
781 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
787 if ( memcmp( ufinderi,
788 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
797 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
798 off_t offset, u_char nlmask,
799 u_char nlchar, char *rbuf,
800 int *rbuflen, const int xlate)
806 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
808 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
810 return( AFPERR_PARAM );
812 if ( cc < *rbuflen ) {
820 for ( p = rbuf, q = p + cc; p < q; ) {
821 if (( *p++ & nlmask ) == nlchar ) {
832 * If this file is of type TEXT, then swap \012 to \015.
835 for ( p = rbuf, q = p + cc; p < q; p++ ) {
836 if ( *p == '\012' ) {
838 } else if ( *p == '\015' ) {
847 return( AFPERR_EOF );
852 /* -----------------------------
853 * with ddp, afp_read can return fewer bytes than in reqcount
854 * so return EOF only if read actually past end of file not
855 * if offset +reqcount > size of file
857 * getfork size ==> 10430
858 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
859 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
860 * read fork offset 9248 size 1508 ==> 1182 (EOF)
861 * 10752 is a bug in Mac 7.5.x finder
863 * with dsi, should we check that reqcount < server quantum?
865 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
868 int ibuflen, *rbuflen;
873 off_t offset, saveoff, reqcount, savereqcount;
874 int cc, err, eid, xlate = 0;
876 u_char nlmask, nlchar;
879 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
880 ibuf += sizeof( u_short );
882 if (NULL == ( ofork = of_find( ofrefnum )) ) {
883 LOG(log_error, logtype_afpd, "afp_read: of_find");
888 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
892 offset = get_off_t(&ibuf, is64);
893 reqcount = get_off_t(&ibuf, is64);
902 /* if we wanted to be picky, we could add in the following
903 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
905 if (reqcount < 0 || offset < 0) {
910 if ( ofork->of_flags & AFPFORK_DATA) {
912 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
913 } else if (ofork->of_flags & AFPFORK_RSRC) {
915 } else { /* fork wasn't opened. this should never really happen. */
920 /* zero request count */
926 /* reqcount isn't always truthful. we need to deal with that. */
927 size = ad_size(ofork->of_ad, eid);
929 if (offset >= size) {
934 savereqcount = reqcount;
936 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
941 #define min(a,b) ((a)<(b)?(a):(b))
942 *rbuflen = min( reqcount, *rbuflen );
943 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
948 /* dsi can stream requests. we can only do this if we're not checking
949 * for an end-of-line character. oh well. */
950 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
951 DSI *dsi = obj->handle;
953 if (obj->options.flags & OPTION_DEBUG) {
954 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
955 (int) reqcount, dsi->clientID);
956 bprint(rbuf, *rbuflen);
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 #ifdef HAVE_SENDFILE_READ
976 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
977 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
978 dsi->datasize) < 0) {
982 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
992 #endif /* HAVE_SENDFILE_READ */
994 /* fill up our buffer. */
995 while (*rbuflen > 0) {
996 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
1002 if (obj->options.flags & OPTION_DEBUG) {
1003 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1004 bprint(rbuf, *rbuflen);
1007 /* dsi_read() also returns buffer size of next allocation */
1008 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1017 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1019 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1024 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1032 /* ---------------------- */
1033 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1036 int ibuflen, *rbuflen;
1038 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1041 /* ---------------------- */
1042 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1045 int ibuflen, *rbuflen;
1047 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1050 /* ---------------------- */
1051 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1054 int ibuflen, *rbuflen;
1062 memcpy(&vid, ibuf, sizeof(vid));
1063 if (NULL == ( vol = getvolbyvid( vid )) ) {
1064 return( AFPERR_PARAM );
1071 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1074 int ibuflen, *rbuflen;
1076 struct ofork *ofork;
1081 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1083 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1084 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1085 return( AFPERR_PARAM );
1088 if ( flushfork( ofork ) < 0 ) {
1089 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1095 /* this is very similar to closefork */
1096 int flushfork( ofork )
1097 struct ofork *ofork;
1101 int err = 0, doflush = 0;
1103 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1104 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1105 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1106 ad_dfileno(ofork->of_ad), strerror(errno) );
1110 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1111 (ofork->of_flags & AFPFORK_RSRC)) {
1113 /* read in the rfork length */
1114 ad_refresh(ofork->of_ad);
1116 /* set the date if we're dirty */
1117 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1118 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1119 ofork->of_flags &= ~AFPFORK_DIRTY;
1123 /* flush the header */
1124 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1127 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1131 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1132 ad_hfileno(ofork->of_ad), strerror(errno) );
1138 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1141 int ibuflen, *rbuflen;
1143 struct ofork *ofork;
1145 int adflags, doflush = 0;
1150 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1152 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1153 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1154 return( AFPERR_PARAM );
1158 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1159 adflags |= ADFLAGS_DF;
1161 if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
1162 adflags |= ADFLAGS_HF;
1164 * Only set the rfork's length if we're closing the rfork.
1166 if ((ofork->of_flags & AFPFORK_RSRC)) {
1167 ad_refresh( ofork->of_ad );
1168 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1169 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1173 ad_flush( ofork->of_ad, adflags );
1178 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1179 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1180 return( AFPERR_PARAM );
1183 of_dealloc( ofork );
1188 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1189 off_t offset, char *rbuf,
1190 size_t rbuflen, const int xlate)
1196 * If this file is of type TEXT, swap \015 to \012.
1199 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1200 if ( *p == '\015' ) {
1202 } else if ( *p == '\012' ) {
1208 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1209 rbuf, rbuflen)) < 0 ) {
1214 return( AFPERR_DFULL );
1216 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1217 return( AFPERR_PARAM );
1225 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1226 * the client may have sent us a bunch of data that's not reflected
1227 * in reqcount et al. */
1228 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1231 int ibuflen, *rbuflen;
1234 struct ofork *ofork;
1235 off_t offset, saveoff, reqcount;
1236 int endflag, eid, xlate = 0, err = AFP_OK;
1240 /* figure out parameters */
1242 endflag = ENDBIT(*ibuf);
1244 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1245 ibuf += sizeof( ofrefnum );
1247 offset = get_off_t(&ibuf, is64);
1248 reqcount = get_off_t(&ibuf, is64);
1250 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1251 LOG(log_error, logtype_afpd, "afp_write: of_find");
1256 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1257 err = AFPERR_ACCESS;
1262 writtenfork = ofork;
1265 if ( ofork->of_flags & AFPFORK_DATA) {
1267 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1268 } else if (ofork->of_flags & AFPFORK_RSRC) {
1271 err = AFPERR_ACCESS; /* should never happen */
1276 offset += ad_size(ofork->of_ad, eid);
1278 /* handle bogus parameters */
1279 if (reqcount < 0 || offset < 0) {
1284 /* offset can overflow on 64-bit capable filesystems.
1285 * report disk full if that's going to happen. */
1286 if (sum_neg(is64, offset, reqcount)) {
1291 if (!reqcount) { /* handle request counts of 0 */
1293 *rbuflen = set_off_t (offset, rbuf, is64);
1298 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1299 reqcount, ofork->of_refnum) < 0) {
1304 /* this is yucky, but dsi can stream i/o and asp can't */
1305 switch (obj->proto) {
1308 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1310 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1311 return( AFPERR_PARAM );
1314 if (obj->options.flags & OPTION_DEBUG) {
1315 printf("(write) len: %d\n", *rbuflen);
1316 bprint(rbuf, *rbuflen);
1319 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1322 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1327 #endif /* no afp/asp */
1331 DSI *dsi = obj->handle;
1333 /* find out what we have already and write it out. */
1334 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1336 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1337 dsi_writeflush(dsi);
1339 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1344 #if 0 /*def HAVE_SENDFILE_WRITE*/
1345 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1346 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1347 offset, dsi->datasize)) < 0) {
1355 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1356 goto afp_write_loop;
1358 dsi_writeflush(dsi);
1360 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1361 reqcount, ofork->of_refnum);
1366 goto afp_write_done;
1368 #endif /* 0, was HAVE_SENDFILE_WRITE */
1370 /* loop until everything gets written. currently
1371 * dsi_write handles the end case by itself. */
1372 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1373 if ( obj->options.flags & OPTION_DEBUG ) {
1374 printf("(write) command cont'd: %d\n", cc);
1378 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1379 dsi_writeflush(dsi);
1381 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1382 reqcount, ofork->of_refnum);
1391 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1392 if ( ad_hfileno( ofork->of_ad ) != -1 )
1393 ofork->of_flags |= AFPFORK_DIRTY;
1395 *rbuflen = set_off_t (offset, rbuf, is64);
1399 if (obj->proto == AFPPROTO_DSI) {
1400 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1401 dsi_writeflush(obj->handle);
1404 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1408 /* ---------------------------- */
1409 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1412 int ibuflen, *rbuflen;
1414 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1417 /* ----------------------------
1418 * FIXME need to deal with SIGXFSZ signal
1420 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1423 int ibuflen, *rbuflen;
1425 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1428 /* ---------------------------- */
1429 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1432 int ibuflen, *rbuflen;
1434 struct ofork *ofork;
1436 u_int16_t ofrefnum, bitmap;
1437 u_int16_t attrbits = 0;
1440 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1441 ibuf += sizeof( ofrefnum );
1442 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1443 bitmap = ntohs( bitmap );
1444 ibuf += sizeof( bitmap );
1447 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1448 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1449 return( AFPERR_PARAM );
1451 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1452 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1454 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1455 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1456 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1457 return( AFPERR_PARAM );
1461 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1462 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1466 *rbuflen = buflen + sizeof( u_short );
1467 bitmap = htons( bitmap );
1468 memcpy(rbuf, &bitmap, sizeof( bitmap ));