2 * $Id: fork.c,v 1.51.2.2 2003-08-24 14:00:43 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 if (NULL == (path.u_name = mtoupath(vol, ofork->of_name, utf8_encoding()))) {
90 return( AFPERR_MISC );
92 path.m_name = ofork->of_name;
94 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
95 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
96 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
97 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
98 if (movecwd(vol, dir) < 0)
99 return( AFPERR_NOOBJ );
100 if ( stat( path.u_name, st ) < 0 )
101 return( AFPERR_NOOBJ );
103 if ( fstat( ad_dfileno( ofork->of_ad ), st ) < 0 ) {
104 return( AFPERR_BITMAP );
108 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp, attrbits );
111 /* ---------------------------- */
112 static off_t get_off_t(ibuf, is64)
120 memcpy(&temp, *ibuf, sizeof( temp ));
121 ret = ntohl(temp); /* ntohl is unsigned */
122 *ibuf += sizeof(temp);
125 memcpy(&temp, *ibuf, sizeof( temp ));
126 *ibuf += sizeof(temp);
127 ret = ntohl(temp)| (ret << 32);
130 ret = (int)ret; /* sign extend */
135 /* ---------------------- */
136 static int set_off_t(offset, rbuf, is64)
146 temp = htonl(offset >> 32);
147 memcpy(rbuf, &temp, sizeof( temp ));
148 rbuf += sizeof(temp);
149 ret = sizeof( temp );
150 offset &= 0xffffffff;
152 temp = htonl(offset);
153 memcpy(rbuf, &temp, sizeof( temp ));
154 ret += sizeof( temp );
159 /* ------------------------
161 static int is_neg(int is64, off_t val)
163 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
168 static __inline__ int sum_neg(int is64, off_t offset, off_t reqcount)
170 if (is_neg(is64, offset +reqcount) )
175 /* -------------------------
177 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
179 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
182 /* -------------------------
184 static int getforkmode(struct adouble *adp, int eid, int what)
186 return ad_testlock(adp, eid, what);
189 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
197 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
198 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
201 if ((access & (OPENACC_RD | OPENACC_DRD))) {
202 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
204 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
207 if ((access & OPENACC_RD) && denyreadset) {
211 if ((access & OPENACC_DRD) && readset) {
215 /* boolean logic is not enough, because getforkmode is not always telling the
218 if ((access & OPENACC_RD)) {
219 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
223 if ((access & OPENACC_DRD)) {
224 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
229 /* ------------same for writing -------------- */
230 if ((access & (OPENACC_WR | OPENACC_DWR))) {
231 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
233 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
236 if ((access & OPENACC_WR) && denywriteset) {
240 if ((access & OPENACC_DWR) && writeset) {
244 if ((access & OPENACC_WR)) {
245 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
249 if ((access & OPENACC_DWR)) {
250 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
256 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
257 return ad_excl_lock(adp, eid);
263 /* ----------------------- */
264 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
267 int ibuflen, *rbuflen;
271 struct ofork *ofork, *opened;
272 struct adouble *adsame = NULL;
273 int buflen, ret, adflags, eid;
275 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
276 char fork, *path, *upath;
283 memcpy(&vid, ibuf, sizeof( vid ));
287 if (NULL == ( vol = getvolbyvid( vid ))) {
288 return( AFPERR_PARAM );
291 memcpy(&did, ibuf, sizeof( did ));
292 ibuf += sizeof( int );
294 if (NULL == ( dir = dirlookup( vol, did ))) {
298 memcpy(&bitmap, ibuf, sizeof( bitmap ));
299 bitmap = ntohs( bitmap );
300 ibuf += sizeof( bitmap );
301 memcpy(&access, ibuf, sizeof( access ));
302 access = ntohs( access );
303 ibuf += sizeof( access );
305 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
309 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
310 return get_afp_errno(AFPERR_PARAM);
313 if (*s_path->m_name == '\0') {
315 return AFPERR_BADTYPE;
318 /* stat() data fork st is set because it's not a dir */
319 switch ( s_path->st_errno ) {
325 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
327 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
330 /* FIXME should we check it first ? */
331 upath = s_path->u_name;
332 if (!vol_unix_priv(vol)) {
333 if (check_access(upath, access ) < 0) {
334 return AFPERR_ACCESS;
338 if (file_access(s_path, access ) < 0) {
339 return AFPERR_ACCESS;
344 /* XXX: this probably isn't the best way to do this. the already
345 open bits should really be set if the fork is opened by any
346 program, not just this one. however, that's problematic to do
347 if we can't write lock files somewhere. opened is also passed to
348 ad_open so that we can keep file locks together.
349 FIXME: add the fork we are opening?
351 if ((opened = of_findname(s_path))) {
352 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
353 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
355 adsame = opened->of_ad;
358 if ( fork == OPENFORK_DATA ) {
360 adflags = ADFLAGS_DF|ADFLAGS_HF;
363 adflags = ADFLAGS_HF;
366 path = s_path->m_name;
367 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
368 adsame, st)) == NULL ) {
369 return( AFPERR_NFILE );
373 if (access & OPENACC_WR) {
374 /* try opening in read-write mode */
375 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
383 if (fork == OPENFORK_DATA) {
384 /* try to open only the data fork */
385 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
388 adflags = ADFLAGS_DF;
391 /* here's the deal. we only try to create the resource
392 * fork if the user wants to open it for write acess. */
393 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
395 ofork->of_flags |= AFPFORK_OPEN;
404 ret = AFPERR_BADTYPE;
408 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
415 /* the ressource fork is open too */
416 ofork->of_flags |= AFPFORK_OPEN;
419 /* try opening in read-only mode */
421 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
429 /* see if client asked for a read only data fork */
430 if (fork == OPENFORK_DATA) {
431 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
434 adflags = ADFLAGS_DF;
436 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
437 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
438 * then create in open read-write.
439 * FIXME , it doesn't play well with byte locking example:
440 * ressource fork open read only
441 * locking set on it (no effect, there's no file!)
442 * ressource fork open read write now
451 ret = AFPERR_BADTYPE;
455 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
461 /* the ressource fork is open too */
462 ofork->of_flags |= AFPFORK_OPEN;
466 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
467 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
468 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
469 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
470 ad_flush( ofork->of_ad, adflags );
473 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
474 &buflen, attrbits )) != AFP_OK ) {
475 ad_close( ofork->of_ad, adflags );
479 *rbuflen = buflen + 2 * sizeof( u_int16_t );
480 bitmap = htons( bitmap );
481 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
482 rbuf += sizeof( u_int16_t );
484 /* check WriteInhibit bit if we have a ressource fork
485 * the test is done here, after some Mac trafic capture
487 if (ad_hfileno(ofork->of_ad) != -1) {
488 ad_getattr(ofork->of_ad, &bshort);
489 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
490 ad_close( ofork->of_ad, adflags );
493 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
494 return(AFPERR_OLOCK);
499 * synchronization locks:
502 /* don't try to lock non-existent rforks. */
503 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
505 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
506 /* can we access the fork? */
509 ad_close( ofork->of_ad, adflags );
512 case EAGAIN: /* return data anyway */
516 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
517 return( AFPERR_DENYCONF );
521 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(ret) );
522 return( AFPERR_PARAM );
525 if ((access & OPENACC_WR))
526 ofork->of_flags |= AFPFORK_ACCWR;
528 /* the file may be open read only without ressource fork */
529 if ((access & OPENACC_RD))
530 ofork->of_flags |= AFPFORK_ACCRD;
532 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
538 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
542 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
545 int ibuflen, *rbuflen;
549 u_int16_t ofrefnum, bitmap;
557 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
558 ibuf += sizeof( ofrefnum );
560 memcpy(&bitmap, ibuf, sizeof(bitmap));
561 bitmap = ntohs(bitmap);
562 ibuf += sizeof( bitmap );
565 if (NULL == ( ofork = of_find( ofrefnum )) ) {
566 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
567 return( AFPERR_PARAM );
570 if (ofork->of_vol->v_flags & AFPVOL_RO)
573 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
574 return AFPERR_ACCESS;
576 if ( ofork->of_flags & AFPFORK_DATA) {
578 } else if (ofork->of_flags & AFPFORK_RSRC) {
583 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
584 && eid == ADEID_RFORK
586 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
587 && eid == ADEID_DFORK)) {
588 return AFPERR_BITMAP;
592 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
593 if (afp_version >= 30) {
597 return AFPERR_BITMAP;
600 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
601 return AFPERR_PARAM ;
603 size = get_off_t(&ibuf, is64);
606 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
609 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
610 st_size = ad_size(ofork->of_ad, eid);
612 if (st_size > size &&
613 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
614 goto afp_setfork_err;
616 err = ad_dtruncate( ofork->of_ad, size );
618 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
620 goto afp_setfork_err;
621 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
622 ad_refresh( ofork->of_ad );
624 st_size = ad_size(ofork->of_ad, eid);
626 if (st_size > size &&
627 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
628 goto afp_setfork_err;
630 err = ad_rtruncate(ofork->of_ad, size);
632 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
634 goto afp_setfork_err;
636 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
637 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
641 return AFPERR_BITMAP;
644 if ( flushfork( ofork ) < 0 ) {
645 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
660 return AFPERR_ACCESS;
671 /* for this to work correctly, we need to check for locks before each
672 * read and write. that's most easily handled by always doing an
673 * appropriate check before each ad_read/ad_write. other things
674 * that can change files like truncate are handled internally to those
677 #define ENDBIT(a) ((a) & 0x80)
678 #define UNLOCKBIT(a) ((a) & 0x01)
681 /* ---------------------- */
682 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
685 int ibuflen, *rbuflen;
689 off_t offset, length;
697 /* figure out parameters */
699 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
701 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
702 ibuf += sizeof(ofrefnum);
704 if (NULL == ( ofork = of_find( ofrefnum )) ) {
705 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
706 return( AFPERR_PARAM );
709 if ( ofork->of_flags & AFPFORK_DATA) {
711 } else if (ofork->of_flags & AFPFORK_RSRC) {
716 offset = get_off_t(&ibuf, is64);
717 length = get_off_t(&ibuf, is64);
719 /* FIXME AD_FILELOCK test is surely wrong */
721 length = BYTELOCK_MAX;
722 else if (!length || is_neg(is64, length)) {
724 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
729 offset += ad_size(ofork->of_ad, eid);
730 /* FIXME what do we do if file size > 2 GB and
731 it's not byte_lock_ext?
734 if (offset < 0) /* error if we have a negative offset */
737 /* if the file is a read-only file, we use read locks instead of
738 * write locks. that way, we can prevent anyone from initiating
740 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
741 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
742 ofork->of_refnum) < 0) {
746 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
752 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
760 *rbuflen = set_off_t (offset, rbuf, is64);
764 /* --------------------------- */
765 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
768 int ibuflen, *rbuflen;
770 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
773 /* --------------------------- */
774 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
777 int ibuflen, *rbuflen;
779 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
784 /* --------------------------- */
785 static __inline__ int crlf( of )
790 if ( ad_hfileno( of->of_ad ) == -1 ||
791 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
793 if (NULL == ( em = getextmap( of->of_name )) ||
794 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
800 if ( memcmp( ufinderi,
801 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
810 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
811 off_t offset, u_char nlmask,
812 u_char nlchar, char *rbuf,
813 int *rbuflen, const int xlate)
819 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
821 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
823 return( AFPERR_PARAM );
825 if ( cc < *rbuflen ) {
833 for ( p = rbuf, q = p + cc; p < q; ) {
834 if (( *p++ & nlmask ) == nlchar ) {
845 * If this file is of type TEXT, then swap \012 to \015.
848 for ( p = rbuf, q = p + cc; p < q; p++ ) {
849 if ( *p == '\012' ) {
851 } else if ( *p == '\015' ) {
860 return( AFPERR_EOF );
865 /* -----------------------------
866 * with ddp, afp_read can return fewer bytes than in reqcount
867 * so return EOF only if read actually past end of file not
868 * if offset +reqcount > size of file
870 * getfork size ==> 10430
871 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
872 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
873 * read fork offset 9248 size 1508 ==> 1182 (EOF)
874 * 10752 is a bug in Mac 7.5.x finder
876 * with dsi, should we check that reqcount < server quantum?
878 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
881 int ibuflen, *rbuflen;
886 off_t offset, saveoff, reqcount, savereqcount;
887 int cc, err, eid, xlate = 0;
889 u_char nlmask, nlchar;
892 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
893 ibuf += sizeof( u_short );
895 if (NULL == ( ofork = of_find( ofrefnum )) ) {
896 LOG(log_error, logtype_afpd, "afp_read: of_find");
901 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
905 offset = get_off_t(&ibuf, is64);
906 reqcount = get_off_t(&ibuf, is64);
915 /* if we wanted to be picky, we could add in the following
916 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
918 if (reqcount < 0 || offset < 0) {
923 if ( ofork->of_flags & AFPFORK_DATA) {
925 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
926 } else if (ofork->of_flags & AFPFORK_RSRC) {
928 } else { /* fork wasn't opened. this should never really happen. */
933 /* zero request count */
939 /* reqcount isn't always truthful. we need to deal with that. */
940 size = ad_size(ofork->of_ad, eid);
942 if (offset >= size) {
947 savereqcount = reqcount;
949 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
954 #define min(a,b) ((a)<(b)?(a):(b))
955 *rbuflen = min( reqcount, *rbuflen );
956 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
961 /* dsi can stream requests. we can only do this if we're not checking
962 * for an end-of-line character. oh well. */
963 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
964 DSI *dsi = obj->handle;
966 if (obj->options.flags & OPTION_DEBUG) {
967 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
968 (int) reqcount, dsi->clientID);
969 bprint(rbuf, *rbuflen);
971 /* subtract off the offset */
973 if (reqcount > size) {
980 /* dsi_readinit() returns size of next read buffer. by this point,
981 * we know that we're sending some data. if we fail, something
982 * horrible happened. */
983 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
986 /* due to the nature of afp packets, we have to exit if we get
987 an error. we can't do this with translation on. */
988 #ifdef HAVE_SENDFILE_READ
989 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
990 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
991 dsi->datasize) < 0) {
995 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
1005 #endif /* HAVE_SENDFILE_READ */
1007 /* fill up our buffer. */
1008 while (*rbuflen > 0) {
1009 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
1015 if (obj->options.flags & OPTION_DEBUG) {
1016 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1017 bprint(rbuf, *rbuflen);
1020 /* dsi_read() also returns buffer size of next allocation */
1021 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1030 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1032 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1037 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1045 /* ---------------------- */
1046 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1049 int ibuflen, *rbuflen;
1051 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1054 /* ---------------------- */
1055 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1058 int ibuflen, *rbuflen;
1060 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1063 /* ---------------------- */
1064 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1067 int ibuflen, *rbuflen;
1075 memcpy(&vid, ibuf, sizeof(vid));
1076 if (NULL == ( vol = getvolbyvid( vid )) ) {
1077 return( AFPERR_PARAM );
1084 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1087 int ibuflen, *rbuflen;
1089 struct ofork *ofork;
1094 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1096 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1097 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1098 return( AFPERR_PARAM );
1101 if ( flushfork( ofork ) < 0 ) {
1102 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1108 /* this is very similar to closefork */
1109 int flushfork( ofork )
1110 struct ofork *ofork;
1114 int err = 0, doflush = 0;
1116 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1117 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1118 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1119 ad_dfileno(ofork->of_ad), strerror(errno) );
1123 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1124 (ofork->of_flags & AFPFORK_RSRC)) {
1126 /* read in the rfork length */
1127 ad_refresh(ofork->of_ad);
1129 /* set the date if we're dirty */
1130 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1131 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1132 ofork->of_flags &= ~AFPFORK_DIRTY;
1136 /* flush the header */
1137 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1140 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1144 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1145 ad_hfileno(ofork->of_ad), strerror(errno) );
1151 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1154 int ibuflen, *rbuflen;
1156 struct ofork *ofork;
1158 int adflags, doflush = 0;
1163 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1165 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1166 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1167 return( AFPERR_PARAM );
1171 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1172 adflags |= ADFLAGS_DF;
1174 if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
1175 adflags |= ADFLAGS_HF;
1177 * Only set the rfork's length if we're closing the rfork.
1179 if ((ofork->of_flags & AFPFORK_RSRC)) {
1180 ad_refresh( ofork->of_ad );
1181 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1182 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1186 ad_flush( ofork->of_ad, adflags );
1191 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1192 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1193 return( AFPERR_PARAM );
1196 of_dealloc( ofork );
1201 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1202 off_t offset, char *rbuf,
1203 size_t rbuflen, const int xlate)
1209 * If this file is of type TEXT, swap \015 to \012.
1212 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1213 if ( *p == '\015' ) {
1215 } else if ( *p == '\012' ) {
1221 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1222 rbuf, rbuflen)) < 0 ) {
1227 return( AFPERR_DFULL );
1229 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1230 return( AFPERR_PARAM );
1238 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1239 * the client may have sent us a bunch of data that's not reflected
1240 * in reqcount et al. */
1241 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1244 int ibuflen, *rbuflen;
1247 struct ofork *ofork;
1248 off_t offset, saveoff, reqcount;
1249 int endflag, eid, xlate = 0, err = AFP_OK;
1253 /* figure out parameters */
1255 endflag = ENDBIT(*ibuf);
1257 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1258 ibuf += sizeof( ofrefnum );
1260 offset = get_off_t(&ibuf, is64);
1261 reqcount = get_off_t(&ibuf, is64);
1263 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1264 LOG(log_error, logtype_afpd, "afp_write: of_find");
1269 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1270 err = AFPERR_ACCESS;
1275 writtenfork = ofork;
1278 if ( ofork->of_flags & AFPFORK_DATA) {
1280 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1281 } else if (ofork->of_flags & AFPFORK_RSRC) {
1284 err = AFPERR_ACCESS; /* should never happen */
1289 offset += ad_size(ofork->of_ad, eid);
1291 /* handle bogus parameters */
1292 if (reqcount < 0 || offset < 0) {
1297 /* offset can overflow on 64-bit capable filesystems.
1298 * report disk full if that's going to happen. */
1299 if (sum_neg(is64, offset, reqcount)) {
1304 if (!reqcount) { /* handle request counts of 0 */
1306 *rbuflen = set_off_t (offset, rbuf, is64);
1311 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1312 reqcount, ofork->of_refnum) < 0) {
1317 /* this is yucky, but dsi can stream i/o and asp can't */
1318 switch (obj->proto) {
1321 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1323 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1324 return( AFPERR_PARAM );
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);
1349 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1350 dsi_writeflush(dsi);
1352 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1357 #if 0 /*def HAVE_SENDFILE_WRITE*/
1358 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1359 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1360 offset, dsi->datasize)) < 0) {
1368 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1369 goto afp_write_loop;
1371 dsi_writeflush(dsi);
1373 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1374 reqcount, ofork->of_refnum);
1379 goto afp_write_done;
1381 #endif /* 0, was HAVE_SENDFILE_WRITE */
1383 /* loop until everything gets written. currently
1384 * dsi_write handles the end case by itself. */
1385 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
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, *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");
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: ad_refresh: %s", 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 ));