2 * $Id: fork.c,v 1.51 2003-03-15 01:34:35 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 (check_access(upath, access ) < 0) {
333 return AFPERR_ACCESS;
337 /* XXX: this probably isn't the best way to do this. the already
338 open bits should really be set if the fork is opened by any
339 program, not just this one. however, that's problematic to do
340 if we can't write lock files somewhere. opened is also passed to
341 ad_open so that we can keep file locks together.
342 FIXME: add the fork we are opening?
344 if ((opened = of_findname(s_path))) {
345 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
346 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
348 adsame = opened->of_ad;
351 if ( fork == OPENFORK_DATA ) {
353 adflags = ADFLAGS_DF|ADFLAGS_HF;
356 adflags = ADFLAGS_HF;
359 path = s_path->m_name;
360 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
361 adsame, st)) == NULL ) {
362 return( AFPERR_NFILE );
366 if (access & OPENACC_WR) {
367 /* try opening in read-write mode */
368 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
376 if (fork == OPENFORK_DATA) {
377 /* try to open only the data fork */
378 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
381 adflags = ADFLAGS_DF;
384 /* here's the deal. we only try to create the resource
385 * fork if the user wants to open it for write acess. */
386 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
388 ofork->of_flags |= AFPFORK_OPEN;
397 ret = AFPERR_BADTYPE;
401 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
408 /* the ressource fork is open too */
409 ofork->of_flags |= AFPFORK_OPEN;
412 /* try opening in read-only mode */
414 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
422 /* see if client asked for a read only data fork */
423 if (fork == OPENFORK_DATA) {
424 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
427 adflags = ADFLAGS_DF;
429 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
430 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
431 * then create in open read-write.
432 * FIXME , it doesn't play well with byte locking example:
433 * ressource fork open read only
434 * locking set on it (no effect, there's no file!)
435 * ressource fork open read write now
444 ret = AFPERR_BADTYPE;
448 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
454 /* the ressource fork is open too */
455 ofork->of_flags |= AFPFORK_OPEN;
459 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
460 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
461 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
462 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
463 ad_flush( ofork->of_ad, adflags );
466 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
467 &buflen, attrbits )) != AFP_OK ) {
468 ad_close( ofork->of_ad, adflags );
472 *rbuflen = buflen + 2 * sizeof( u_int16_t );
473 bitmap = htons( bitmap );
474 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
475 rbuf += sizeof( u_int16_t );
477 /* check WriteInhibit bit if we have a ressource fork
478 * the test is done here, after some Mac trafic capture
480 if (ad_hfileno(ofork->of_ad) != -1) {
481 ad_getattr(ofork->of_ad, &bshort);
482 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
483 ad_close( ofork->of_ad, adflags );
486 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
487 return(AFPERR_OLOCK);
492 * synchronization locks:
495 /* don't try to lock non-existent rforks. */
496 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
498 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
499 /* can we access the fork? */
502 ad_close( ofork->of_ad, adflags );
505 case EAGAIN: /* return data anyway */
509 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
510 return( AFPERR_DENYCONF );
514 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(ret) );
515 return( AFPERR_PARAM );
518 if ((access & OPENACC_WR))
519 ofork->of_flags |= AFPFORK_ACCWR;
521 /* the file may be open read only without ressource fork */
522 if ((access & OPENACC_RD))
523 ofork->of_flags |= AFPFORK_ACCRD;
525 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
531 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
535 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
538 int ibuflen, *rbuflen;
542 u_int16_t ofrefnum, bitmap;
550 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
551 ibuf += sizeof( ofrefnum );
553 memcpy(&bitmap, ibuf, sizeof(bitmap));
554 bitmap = ntohs(bitmap);
555 ibuf += sizeof( bitmap );
558 if (NULL == ( ofork = of_find( ofrefnum )) ) {
559 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
560 return( AFPERR_PARAM );
563 if (ofork->of_vol->v_flags & AFPVOL_RO)
566 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
567 return AFPERR_ACCESS;
569 if ( ofork->of_flags & AFPFORK_DATA) {
571 } else if (ofork->of_flags & AFPFORK_RSRC) {
576 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
577 && eid == ADEID_RFORK
579 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
580 && eid == ADEID_DFORK)) {
581 return AFPERR_BITMAP;
585 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
586 if (afp_version >= 30) {
590 return AFPERR_BITMAP;
593 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
594 return AFPERR_PARAM ;
596 size = get_off_t(&ibuf, is64);
599 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
602 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
603 st_size = ad_size(ofork->of_ad, eid);
605 if (st_size > size &&
606 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
607 goto afp_setfork_err;
609 err = ad_dtruncate( ofork->of_ad, size );
611 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
613 goto afp_setfork_err;
614 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
615 ad_refresh( ofork->of_ad );
617 st_size = ad_size(ofork->of_ad, eid);
619 if (st_size > size &&
620 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
621 goto afp_setfork_err;
623 err = ad_rtruncate(ofork->of_ad, size);
625 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
627 goto afp_setfork_err;
629 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
630 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
634 return AFPERR_BITMAP;
637 if ( flushfork( ofork ) < 0 ) {
638 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
653 return AFPERR_ACCESS;
664 /* for this to work correctly, we need to check for locks before each
665 * read and write. that's most easily handled by always doing an
666 * appropriate check before each ad_read/ad_write. other things
667 * that can change files like truncate are handled internally to those
670 #define ENDBIT(a) ((a) & 0x80)
671 #define UNLOCKBIT(a) ((a) & 0x01)
674 /* ---------------------- */
675 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
678 int ibuflen, *rbuflen;
682 off_t offset, length;
690 /* figure out parameters */
692 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
694 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
695 ibuf += sizeof(ofrefnum);
697 if (NULL == ( ofork = of_find( ofrefnum )) ) {
698 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
699 return( AFPERR_PARAM );
702 if ( ofork->of_flags & AFPFORK_DATA) {
704 } else if (ofork->of_flags & AFPFORK_RSRC) {
709 offset = get_off_t(&ibuf, is64);
710 length = get_off_t(&ibuf, is64);
712 /* FIXME AD_FILELOCK test is surely wrong */
714 length = BYTELOCK_MAX;
715 else if (!length || is_neg(is64, length)) {
717 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
722 offset += ad_size(ofork->of_ad, eid);
723 /* FIXME what do we do if file size > 2 GB and
724 it's not byte_lock_ext?
727 if (offset < 0) /* error if we have a negative offset */
730 /* if the file is a read-only file, we use read locks instead of
731 * write locks. that way, we can prevent anyone from initiating
733 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
734 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
735 ofork->of_refnum) < 0) {
739 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
745 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
753 *rbuflen = set_off_t (offset, rbuf, is64);
757 /* --------------------------- */
758 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
761 int ibuflen, *rbuflen;
763 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
766 /* --------------------------- */
767 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
770 int ibuflen, *rbuflen;
772 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
777 /* --------------------------- */
778 static __inline__ int crlf( of )
783 if ( ad_hfileno( of->of_ad ) == -1 ||
784 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
786 if (NULL == ( em = getextmap( of->of_name )) ||
787 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
793 if ( memcmp( ufinderi,
794 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
803 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
804 off_t offset, u_char nlmask,
805 u_char nlchar, char *rbuf,
806 int *rbuflen, const int xlate)
812 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
814 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
816 return( AFPERR_PARAM );
818 if ( cc < *rbuflen ) {
826 for ( p = rbuf, q = p + cc; p < q; ) {
827 if (( *p++ & nlmask ) == nlchar ) {
838 * If this file is of type TEXT, then swap \012 to \015.
841 for ( p = rbuf, q = p + cc; p < q; p++ ) {
842 if ( *p == '\012' ) {
844 } else if ( *p == '\015' ) {
853 return( AFPERR_EOF );
858 /* -----------------------------
859 * with ddp, afp_read can return fewer bytes than in reqcount
860 * so return EOF only if read actually past end of file not
861 * if offset +reqcount > size of file
863 * getfork size ==> 10430
864 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
865 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
866 * read fork offset 9248 size 1508 ==> 1182 (EOF)
867 * 10752 is a bug in Mac 7.5.x finder
869 * with dsi, should we check that reqcount < server quantum?
871 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
874 int ibuflen, *rbuflen;
879 off_t offset, saveoff, reqcount, savereqcount;
880 int cc, err, eid, xlate = 0;
882 u_char nlmask, nlchar;
885 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
886 ibuf += sizeof( u_short );
888 if (NULL == ( ofork = of_find( ofrefnum )) ) {
889 LOG(log_error, logtype_afpd, "afp_read: of_find");
894 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
898 offset = get_off_t(&ibuf, is64);
899 reqcount = get_off_t(&ibuf, is64);
908 /* if we wanted to be picky, we could add in the following
909 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
911 if (reqcount < 0 || offset < 0) {
916 if ( ofork->of_flags & AFPFORK_DATA) {
918 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
919 } else if (ofork->of_flags & AFPFORK_RSRC) {
921 } else { /* fork wasn't opened. this should never really happen. */
926 /* zero request count */
932 /* reqcount isn't always truthful. we need to deal with that. */
933 size = ad_size(ofork->of_ad, eid);
935 if (offset >= size) {
940 savereqcount = reqcount;
942 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
947 #define min(a,b) ((a)<(b)?(a):(b))
948 *rbuflen = min( reqcount, *rbuflen );
949 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
954 /* dsi can stream requests. we can only do this if we're not checking
955 * for an end-of-line character. oh well. */
956 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
957 DSI *dsi = obj->handle;
959 if (obj->options.flags & OPTION_DEBUG) {
960 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
961 (int) reqcount, dsi->clientID);
962 bprint(rbuf, *rbuflen);
964 /* subtract off the offset */
966 if (reqcount > size) {
973 /* dsi_readinit() returns size of next read buffer. by this point,
974 * we know that we're sending some data. if we fail, something
975 * horrible happened. */
976 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
979 /* due to the nature of afp packets, we have to exit if we get
980 an error. we can't do this with translation on. */
981 #ifdef HAVE_SENDFILE_READ
982 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
983 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
984 dsi->datasize) < 0) {
988 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
998 #endif /* HAVE_SENDFILE_READ */
1000 /* fill up our buffer. */
1001 while (*rbuflen > 0) {
1002 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
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 */
1023 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1025 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1030 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1038 /* ---------------------- */
1039 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1042 int ibuflen, *rbuflen;
1044 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1047 /* ---------------------- */
1048 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1051 int ibuflen, *rbuflen;
1053 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1056 /* ---------------------- */
1057 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1060 int ibuflen, *rbuflen;
1068 memcpy(&vid, ibuf, sizeof(vid));
1069 if (NULL == ( vol = getvolbyvid( vid )) ) {
1070 return( AFPERR_PARAM );
1077 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1080 int ibuflen, *rbuflen;
1082 struct ofork *ofork;
1087 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1089 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1090 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1091 return( AFPERR_PARAM );
1094 if ( flushfork( ofork ) < 0 ) {
1095 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1101 /* this is very similar to closefork */
1102 int flushfork( ofork )
1103 struct ofork *ofork;
1107 int err = 0, doflush = 0;
1109 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1110 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1111 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1112 ad_dfileno(ofork->of_ad), strerror(errno) );
1116 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1117 (ofork->of_flags & AFPFORK_RSRC)) {
1119 /* read in the rfork length */
1120 ad_refresh(ofork->of_ad);
1122 /* set the date if we're dirty */
1123 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1124 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1125 ofork->of_flags &= ~AFPFORK_DIRTY;
1129 /* flush the header */
1130 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1133 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1137 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1138 ad_hfileno(ofork->of_ad), strerror(errno) );
1144 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1147 int ibuflen, *rbuflen;
1149 struct ofork *ofork;
1151 int adflags, doflush = 0;
1156 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1158 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1159 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1160 return( AFPERR_PARAM );
1164 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1165 adflags |= ADFLAGS_DF;
1167 if ( (ofork->of_flags & AFPFORK_OPEN) && ad_hfileno( ofork->of_ad ) != -1 ) {
1168 adflags |= ADFLAGS_HF;
1170 * Only set the rfork's length if we're closing the rfork.
1172 if ((ofork->of_flags & AFPFORK_RSRC)) {
1173 ad_refresh( ofork->of_ad );
1174 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1175 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1179 ad_flush( ofork->of_ad, adflags );
1184 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1185 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1186 return( AFPERR_PARAM );
1189 of_dealloc( ofork );
1194 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1195 off_t offset, char *rbuf,
1196 size_t rbuflen, const int xlate)
1202 * If this file is of type TEXT, swap \015 to \012.
1205 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1206 if ( *p == '\015' ) {
1208 } else if ( *p == '\012' ) {
1214 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1215 rbuf, rbuflen)) < 0 ) {
1220 return( AFPERR_DFULL );
1222 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1223 return( AFPERR_PARAM );
1231 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1232 * the client may have sent us a bunch of data that's not reflected
1233 * in reqcount et al. */
1234 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1237 int ibuflen, *rbuflen;
1240 struct ofork *ofork;
1241 off_t offset, saveoff, reqcount;
1242 int endflag, eid, xlate = 0, err = AFP_OK;
1246 /* figure out parameters */
1248 endflag = ENDBIT(*ibuf);
1250 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1251 ibuf += sizeof( ofrefnum );
1253 offset = get_off_t(&ibuf, is64);
1254 reqcount = get_off_t(&ibuf, is64);
1256 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1257 LOG(log_error, logtype_afpd, "afp_write: of_find");
1262 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1263 err = AFPERR_ACCESS;
1268 writtenfork = ofork;
1271 if ( ofork->of_flags & AFPFORK_DATA) {
1273 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1274 } else if (ofork->of_flags & AFPFORK_RSRC) {
1277 err = AFPERR_ACCESS; /* should never happen */
1282 offset += ad_size(ofork->of_ad, eid);
1284 /* handle bogus parameters */
1285 if (reqcount < 0 || offset < 0) {
1290 /* offset can overflow on 64-bit capable filesystems.
1291 * report disk full if that's going to happen. */
1292 if (sum_neg(is64, offset, reqcount)) {
1297 if (!reqcount) { /* handle request counts of 0 */
1299 *rbuflen = set_off_t (offset, rbuf, is64);
1304 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1305 reqcount, ofork->of_refnum) < 0) {
1310 /* this is yucky, but dsi can stream i/o and asp can't */
1311 switch (obj->proto) {
1314 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1316 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1317 return( AFPERR_PARAM );
1320 if (obj->options.flags & OPTION_DEBUG) {
1321 printf("(write) len: %d\n", *rbuflen);
1322 bprint(rbuf, *rbuflen);
1325 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1328 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1333 #endif /* no afp/asp */
1337 DSI *dsi = obj->handle;
1339 /* find out what we have already and write it out. */
1340 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1342 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1343 dsi_writeflush(dsi);
1345 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1350 #if 0 /*def HAVE_SENDFILE_WRITE*/
1351 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1352 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1353 offset, dsi->datasize)) < 0) {
1361 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1362 goto afp_write_loop;
1364 dsi_writeflush(dsi);
1366 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1367 reqcount, ofork->of_refnum);
1372 goto afp_write_done;
1374 #endif /* 0, was HAVE_SENDFILE_WRITE */
1376 /* loop until everything gets written. currently
1377 * dsi_write handles the end case by itself. */
1378 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1379 if ( obj->options.flags & OPTION_DEBUG ) {
1380 printf("(write) command cont'd: %d\n", cc);
1384 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1385 dsi_writeflush(dsi);
1387 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1388 reqcount, ofork->of_refnum);
1397 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1398 if ( ad_hfileno( ofork->of_ad ) != -1 )
1399 ofork->of_flags |= AFPFORK_DIRTY;
1401 *rbuflen = set_off_t (offset, rbuf, is64);
1405 if (obj->proto == AFPPROTO_DSI) {
1406 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1407 dsi_writeflush(obj->handle);
1410 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1414 /* ---------------------------- */
1415 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1418 int ibuflen, *rbuflen;
1420 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1423 /* ----------------------------
1424 * FIXME need to deal with SIGXFSZ signal
1426 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1429 int ibuflen, *rbuflen;
1431 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1434 /* ---------------------------- */
1435 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1438 int ibuflen, *rbuflen;
1440 struct ofork *ofork;
1442 u_int16_t ofrefnum, bitmap;
1443 u_int16_t attrbits = 0;
1446 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1447 ibuf += sizeof( ofrefnum );
1448 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1449 bitmap = ntohs( bitmap );
1450 ibuf += sizeof( bitmap );
1453 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1454 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1455 return( AFPERR_PARAM );
1457 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1458 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1460 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1461 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1462 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1463 return( AFPERR_PARAM );
1467 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1468 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1472 *rbuflen = buflen + sizeof( u_short );
1473 bitmap = htons( bitmap );
1474 memcpy(rbuf, &bitmap, sizeof( bitmap ));