2 * $Id: fork.c,v 1.32 2002-08-21 05:21:38 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 #define BYTELOCK_MAX 0x7FFFFFFFU
52 struct ofork *writtenfork;
53 extern int getmetadata(struct vol *vol,
55 char *path, struct dir *dir, struct stat *st,
56 char *buf, int *buflen, struct adouble *adp, int attrbits );
58 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
63 const u_int16_t attrbits;
66 struct stat lst, *lstp;
67 #endif /* !USE_LASTDID */
76 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
79 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
80 if ( ad_refresh( ofork->of_ad ) < 0 ) {
81 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
82 return( AFPERR_PARAM );
84 /* See afp_closefork() for why this is bad */
85 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
89 /* can only get the length of the opened fork */
90 if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
91 ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
92 return( AFPERR_BITMAP );
95 if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
96 (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
97 (1 << FILPBIT_BDATE))) {
98 upath = mtoupath(ofork->of_vol, ofork->of_name);
99 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
100 if ( stat( upath, &st ) < 0 )
101 return( AFPERR_NOOBJ );
103 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
104 return( AFPERR_BITMAP );
110 return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
113 /* -------------------------
117 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
122 /* NOTE: we can't write lock a read-only file. on those, we just
123 * make sure that we have a read lock set. that way, we at least prevent
124 * someone else from really setting a deny read/write on the file.
126 lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
127 lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
129 return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
133 /* -------------------------
135 extern int ad_testlock(struct adouble *adp, int eid, int off);
137 static int getforkmode(struct adouble *adp, int eid, int what)
139 return ad_testlock(adp, eid, what);
142 /* --------------------------
143 a lot of races, some can be remove. but I try first to get the semantic right
145 #ifdef USE_FLOCK_LOCKS
146 #error sorry, for now configure --with-flock-locks is broken...
149 static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
158 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
159 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
162 if ((access & (OPENACC_RD | OPENACC_DRD))) {
163 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
165 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
168 if ((access & OPENACC_RD) && denyreadset) {
172 if ((access & OPENACC_DRD) && readset) {
176 /* boolean logic is not enough, because getforkmode is not always telling the
179 mode = ((access & OPENACC_DRD))?EXCL: SHARE;
180 if ((access & OPENACC_RD)) {
181 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
185 if ((access & OPENACC_DRD)) {
186 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
191 /* ------------same for writing -------------- */
192 if ((access & (OPENACC_WR | OPENACC_DWR))) {
193 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
195 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
198 if ((access & OPENACC_WR) && denywriteset) {
202 if ((access & OPENACC_DWR) && writeset) {
206 mode = ((access & OPENACC_DWR))?EXCL: SHARE;
207 if ((access & OPENACC_WR)) {
208 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
212 if ((access & OPENACC_DWR)) {
213 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
221 /* ----------------------- */
222 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
225 int ibuflen, *rbuflen;
229 struct ofork *ofork, *opened;
230 struct adouble *adsame = NULL;
231 int buflen, ret, adflags, eid, lockop;
233 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
234 char fork, *path, *upath;
239 memcpy(&vid, ibuf, sizeof( vid ));
243 if (( vol = getvolbyvid( vid )) == NULL ) {
244 return( AFPERR_PARAM );
247 memcpy(&did, ibuf, sizeof( did ));
248 ibuf += sizeof( int );
250 if (( dir = dirsearch( vol, did )) == NULL ) {
251 return( AFPERR_NOOBJ );
254 memcpy(&bitmap, ibuf, sizeof( bitmap ));
255 bitmap = ntohs( bitmap );
256 ibuf += sizeof( bitmap );
257 memcpy(&access, ibuf, sizeof( access ));
258 access = ntohs( access );
259 ibuf += sizeof( access );
261 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
265 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
266 return( AFPERR_NOOBJ );
269 if ( fork == OPENFORK_DATA ) {
271 adflags = ADFLAGS_DF|ADFLAGS_HF;
274 adflags = ADFLAGS_HF;
277 /* XXX: this probably isn't the best way to do this. the already
278 open bits should really be set if the fork is opened by any
279 program, not just this one. however, that's problematic to do
280 if we can't write lock files somewhere. opened is also passed to
281 ad_open so that we can keep file locks together.
282 FIXME: add the fork we are opening?
284 if ((opened = of_findname(vol, curdir, path))) {
285 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
286 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
288 adsame = opened->of_ad;
291 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
293 return( AFPERR_NFILE );
295 if (access & OPENACC_WR) {
296 /* try opening in read-write mode */
297 upath = mtoupath(vol, path);
299 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
311 /* see if client asked for the data fork */
312 if (fork == OPENFORK_DATA) {
313 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
316 adflags = ADFLAGS_DF;
318 } else if (stat(upath, &st) == 0) {
319 /* here's the deal. we only try to create the resource
320 * fork if the user wants to open it for write acess. */
321 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
333 ret = AFPERR_BADTYPE;
337 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
344 /* try opening in read-only mode */
345 upath = mtoupath(vol, path);
347 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
352 /* check for a read-only data fork */
353 if ((adflags != ADFLAGS_HF) &&
354 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
357 adflags = ADFLAGS_DF;
363 /* see if client asked for the data fork */
364 if (fork == OPENFORK_DATA) {
365 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
368 adflags = ADFLAGS_DF;
370 } else if (stat(upath, &st) != 0) {
381 ret = AFPERR_BADTYPE;
385 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
392 if ((adflags & ADFLAGS_HF) &&
393 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
394 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
395 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
396 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
397 ad_flush( ofork->of_ad, adflags );
400 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
401 &buflen, attrbits )) != AFP_OK ) {
402 ad_close( ofork->of_ad, adflags );
406 *rbuflen = buflen + 2 * sizeof( u_int16_t );
407 bitmap = htons( bitmap );
408 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
409 rbuf += sizeof( u_int16_t );
411 /* check WriteInhibit bit, the test is done here, after some Mac trafic capture */
412 ad_getattr(ofork->of_ad, &bshort);
413 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
414 ad_close( ofork->of_ad, adflags );
417 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
418 return(AFPERR_OLOCK);
422 * synchronization locks:
425 /* don't try to lock non-existent rforks. */
426 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
428 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
429 /* can we access the fork? */
432 ad_close( ofork->of_ad, adflags );
435 case EAGAIN: /* return data anyway */
439 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
440 return( AFPERR_DENYCONF );
444 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
445 return( AFPERR_PARAM );
448 if ((access & OPENACC_WR))
449 ofork->of_flags |= AFPFORK_ACCWR;
450 if ((access & OPENACC_RD))
451 ofork->of_flags |= AFPFORK_ACCRD;
454 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
460 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
464 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
467 int ibuflen, *rbuflen;
471 u_int16_t ofrefnum, bitmap;
475 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
476 ibuf += sizeof( ofrefnum );
477 memcpy(&bitmap, ibuf, sizeof(bitmap));
478 bitmap = ntohs(bitmap);
479 ibuf += sizeof( bitmap );
480 memcpy(&size, ibuf, sizeof( size ));
481 size = ntohl( size );
484 if (( ofork = of_find( ofrefnum )) == NULL ) {
485 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
486 return( AFPERR_PARAM );
489 if (ofork->of_vol->v_flags & AFPVOL_RO)
492 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
493 return AFPERR_ACCESS;
498 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
499 err = ad_dtruncate( ofork->of_ad, size );
501 goto afp_setfork_err;
502 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
503 (ofork->of_flags & AFPFORK_RSRC)) {
504 ad_refresh( ofork->of_ad );
505 err = ad_rtruncate(ofork->of_ad, size);
507 goto afp_setfork_err;
509 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
510 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
512 return( AFPERR_PARAM );
515 return AFPERR_BITMAP;
518 if ( flushfork( ofork ) < 0 ) {
519 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
534 return AFPERR_ACCESS;
545 /* for this to work correctly, we need to check for locks before each
546 * read and write. that's most easily handled by always doing an
547 * appropriate check before each ad_read/ad_write. other things
548 * that can change files like truncate are handled internally to those
551 #define ENDBIT(a) ((a) & 0x80)
552 #define UNLOCKBIT(a) ((a) & 0x01)
553 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
556 int ibuflen, *rbuflen;
559 int32_t offset, length;
566 /* figure out parameters */
568 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
570 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
571 ibuf += sizeof(ofrefnum);
573 if (( ofork = of_find( ofrefnum )) == NULL ) {
574 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
575 return( AFPERR_PARAM );
578 if ( ofork->of_flags & AFPFORK_DATA) {
580 } else if (ofork->of_flags & AFPFORK_RSRC) {
585 memcpy(&offset, ibuf, sizeof( offset ));
586 offset = ntohl(offset);
587 ibuf += sizeof(offset);
589 memcpy(&length, ibuf, sizeof( length ));
590 length = ntohl(length);
591 if (length == 0xFFFFFFFF)
592 length = BYTELOCK_MAX;
593 else if (length <= 0) {
595 } else if ((length >= AD_FILELOCK_BASE) &&
596 (ad_hfileno(ofork->of_ad) == -1))
600 offset += ad_size(ofork->of_ad, eid);
602 if (offset < 0) /* error if we have a negative offset */
605 /* if the file is a read-only file, we use read locks instead of
606 * write locks. that way, we can prevent anyone from initiating
608 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
609 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
610 ADLOCK_WR : ADLOCK_RD), offset, length,
611 ofork->of_refnum) < 0) {
615 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
621 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
630 offset = htonl(offset);
631 memcpy(rbuf, &offset, sizeof( offset ));
632 *rbuflen = sizeof( offset );
638 static __inline__ int crlf( of )
643 if ( ad_hfileno( of->of_ad ) == -1 ||
644 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
646 if (( em = getextmap( of->of_name )) == NULL ||
647 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
653 if ( memcmp( ufinderi,
654 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
663 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
664 int offset, u_char nlmask,
665 u_char nlchar, char *rbuf,
666 int *rbuflen, const int xlate)
672 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
674 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
676 return( AFPERR_PARAM );
678 if ( cc < *rbuflen ) {
686 for ( p = rbuf, q = p + cc; p < q; ) {
687 if (( *p++ & nlmask ) == nlchar ) {
698 * If this file is of type TEXT, then swap \012 to \015.
701 for ( p = rbuf, q = p + cc; p < q; p++ ) {
702 if ( *p == '\012' ) {
704 } else if ( *p == '\015' ) {
713 return( AFPERR_EOF );
718 /* -----------------------------
719 * with ddp, afp_read can return fewer bytes than in reqcount
720 * so return EOF only if read actually past end of file not
721 * if offset +reqcount > size of file
723 * getfork size ==> 10430
724 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
725 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
726 * read fork offset 9248 size 1508 ==> 1182 (EOF)
727 * 10752 is a bug in Mac 7.5.x finder
729 * with dsi, should we check that reqcount < server quantum?
731 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
734 int ibuflen, *rbuflen;
738 int32_t offset, saveoff, reqcount, savereqcount;
739 int cc, err, eid, xlate = 0;
741 u_char nlmask, nlchar;
744 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
745 ibuf += sizeof( u_short );
747 if (( ofork = of_find( ofrefnum )) == NULL ) {
748 LOG(log_error, logtype_afpd, "afp_read: of_find");
753 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
758 memcpy(&offset, ibuf, sizeof( offset ));
759 offset = ntohl( offset );
760 ibuf += sizeof( offset );
761 memcpy(&reqcount, ibuf, sizeof( reqcount ));
762 reqcount = ntohl( reqcount );
763 ibuf += sizeof( reqcount );
768 /* if we wanted to be picky, we could add in the following
769 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
771 if (reqcount < 0 || offset < 0) {
776 if ( ofork->of_flags & AFPFORK_DATA) {
778 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
779 } else if (ofork->of_flags & AFPFORK_RSRC) {
781 } else { /* fork wasn't opened. this should never really happen. */
786 /* zero request count */
792 /* reqcount isn't always truthful. we need to deal with that. */
793 size = ad_size(ofork->of_ad, eid);
795 if (offset >= size) {
800 savereqcount = reqcount;
802 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
807 #define min(a,b) ((a)<(b)?(a):(b))
808 *rbuflen = min( reqcount, *rbuflen );
809 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
814 /* dsi can stream requests. we can only do this if we're not checking
815 * for an end-of-line character. oh well. */
816 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
817 DSI *dsi = obj->handle;
819 if (obj->options.flags & OPTION_DEBUG) {
820 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
821 reqcount, dsi->clientID);
822 bprint(rbuf, *rbuflen);
824 /* subtract off the offset */
826 if (reqcount > size) {
833 /* dsi_readinit() returns size of next read buffer. by this point,
834 * we know that we're sending some data. if we fail, something
835 * horrible happened. */
836 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
839 /* due to the nature of afp packets, we have to exit if we get
840 an error. we can't do this with translation on. */
841 #ifdef HAVE_SENDFILE_READ
842 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
843 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
844 dsi->datasize) < 0) {
848 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
858 #endif /* HAVE_SENDFILE_READ */
860 /* fill up our buffer. */
861 while (*rbuflen > 0) {
862 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
868 if (obj->options.flags & OPTION_DEBUG) {
869 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
870 bprint(rbuf, *rbuflen);
873 /* dsi_read() also returns buffer size of next allocation */
874 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
883 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
885 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
890 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
898 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
901 int ibuflen, *rbuflen;
909 memcpy(&vid, ibuf, sizeof(vid));
910 if (( vol = getvolbyvid( vid )) == NULL ) {
911 return( AFPERR_PARAM );
918 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
921 int ibuflen, *rbuflen;
928 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
930 if (( ofork = of_find( ofrefnum )) == NULL ) {
931 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
932 return( AFPERR_PARAM );
935 if ( flushfork( ofork ) < 0 ) {
936 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
942 /* this is very similar to closefork */
943 int flushfork( ofork )
947 int len, err = 0, doflush = 0;
949 if ( ad_dfileno( ofork->of_ad ) != -1 &&
950 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
951 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
952 ad_dfileno(ofork->of_ad), strerror(errno) );
956 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
958 /* read in the rfork length */
959 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
960 ad_refresh(ofork->of_ad);
962 /* set the date if we're dirty */
963 if ((ofork->of_flags & AFPFORK_DIRTY) &&
964 (gettimeofday(&tv, NULL) == 0)) {
965 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
966 ofork->of_flags &= ~AFPFORK_DIRTY;
970 /* if we're actually flushing this fork, make sure to set the
971 * length. otherwise, just use the stored length */
972 if ((ofork->of_flags & AFPFORK_RSRC) &&
973 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
974 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
979 /* flush the header (if it is a resource fork) */
980 if (ofork->of_flags & AFPFORK_RSRC)
981 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
984 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
988 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
989 ad_hfileno(ofork->of_ad), strerror(errno) );
995 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
998 int ibuflen, *rbuflen;
1000 struct ofork *ofork;
1002 int adflags, aint, doflush = 0;
1007 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1009 if (( ofork = of_find( ofrefnum )) == NULL ) {
1010 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1011 return( AFPERR_PARAM );
1015 if ((ofork->of_flags & AFPFORK_DATA) &&
1016 (ad_dfileno( ofork->of_ad ) != -1)) {
1017 adflags |= ADFLAGS_DF;
1020 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1021 adflags |= ADFLAGS_HF;
1023 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1024 ad_refresh( ofork->of_ad );
1025 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1026 (gettimeofday(&tv, NULL) == 0)) {
1027 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1033 * Only set the rfork's length if we're closing the rfork.
1035 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1036 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1037 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1041 ad_flush( ofork->of_ad, adflags );
1045 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1046 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1047 return( AFPERR_PARAM );
1050 of_dealloc( ofork );
1055 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1056 off_t offset, char *rbuf,
1057 size_t rbuflen, const int xlate)
1063 * If this file is of type TEXT, swap \015 to \012.
1066 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1067 if ( *p == '\015' ) {
1069 } else if ( *p == '\012' ) {
1075 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1076 rbuf, rbuflen)) < 0 ) {
1081 return( AFPERR_DFULL );
1083 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1084 return( AFPERR_PARAM );
1091 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1092 * the client may have sent us a bunch of data that's not reflected
1093 * in reqcount et al. */
1094 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1097 int ibuflen, *rbuflen;
1099 struct ofork *ofork;
1100 int32_t offset, saveoff, reqcount;
1101 int endflag, eid, xlate = 0, err = AFP_OK;
1105 /* figure out parameters */
1107 endflag = ENDBIT(*ibuf);
1109 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1110 ibuf += sizeof( ofrefnum );
1111 memcpy(&offset, ibuf, sizeof( offset ));
1112 offset = ntohl( offset );
1113 ibuf += sizeof( offset );
1114 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1115 reqcount = ntohl( reqcount );
1116 ibuf += sizeof( reqcount );
1118 if (( ofork = of_find( ofrefnum )) == NULL ) {
1119 LOG(log_error, logtype_afpd, "afp_write: of_find");
1124 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1125 err = AFPERR_ACCESS;
1130 writtenfork = ofork;
1133 if ( ofork->of_flags & AFPFORK_DATA) {
1135 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1136 } else if (ofork->of_flags & AFPFORK_RSRC) {
1139 err = AFPERR_ACCESS; /* should never happen */
1144 offset += ad_size(ofork->of_ad, eid);
1146 /* handle bogus parameters */
1147 if (reqcount < 0 || offset < 0) {
1152 /* offset can overflow on 64-bit capable filesystems.
1153 * report disk full if that's going to happen. */
1154 if (offset + reqcount < 0) {
1159 if (!reqcount) { /* handle request counts of 0 */
1161 offset = htonl(offset);
1162 memcpy(rbuf, &offset, sizeof(offset));
1167 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1173 /* this is yucky, but dsi can stream i/o and asp can't */
1174 switch (obj->proto) {
1177 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1179 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1180 return( AFPERR_PARAM );
1183 if (obj->options.flags & OPTION_DEBUG) {
1184 printf("(write) len: %d\n", *rbuflen);
1185 bprint(rbuf, *rbuflen);
1188 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1191 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1196 #endif /* no afp/asp */
1200 DSI *dsi = obj->handle;
1202 /* find out what we have already and write it out. */
1203 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1205 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1206 dsi_writeflush(dsi);
1208 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1213 #if 0 /*def HAVE_SENDFILE_WRITE*/
1214 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1215 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1216 offset, dsi->datasize)) < 0) {
1224 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1225 goto afp_write_loop;
1227 dsi_writeflush(dsi);
1229 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1235 goto afp_write_done;
1237 #endif /* 0, was HAVE_SENDFILE_WRITE */
1239 /* loop until everything gets written. currently
1240 * dsi_write handles the end case by itself. */
1241 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1242 if ( obj->options.flags & OPTION_DEBUG ) {
1243 printf("(write) command cont'd: %d\n", cc);
1247 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1248 dsi_writeflush(dsi);
1250 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1260 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1261 if ( ad_hfileno( ofork->of_ad ) != -1 )
1262 ofork->of_flags |= AFPFORK_DIRTY;
1264 offset = htonl( offset );
1265 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1266 bcopy(&offset, rbuf, sizeof(offset));
1267 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1268 memcpy(rbuf, &offset, sizeof(offset));
1269 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1270 *rbuflen = sizeof(offset);
1274 if (obj->proto == AFPPROTO_DSI) {
1275 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1276 dsi_writeflush(obj->handle);
1279 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1284 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1287 int ibuflen, *rbuflen;
1289 struct ofork *ofork;
1291 u_int16_t ofrefnum, bitmap;
1292 u_int16_t attrbits = 0;
1295 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1296 ibuf += sizeof( ofrefnum );
1297 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1298 bitmap = ntohs( bitmap );
1299 ibuf += sizeof( bitmap );
1302 if (( ofork = of_find( ofrefnum )) == NULL ) {
1303 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1304 return( AFPERR_PARAM );
1306 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1307 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1309 if (( ret = getforkparams( ofork, bitmap,
1310 rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
1314 *rbuflen = buflen + sizeof( u_short );
1315 bitmap = htons( bitmap );
1316 memcpy(rbuf, &bitmap, sizeof( bitmap ));