2 * $Id: fork.c,v 1.29 2002-06-01 05:10:24 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 */
70 char *data, *nameoff = NULL, *upath;
79 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
82 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
83 if ( ad_refresh( ofork->of_ad ) < 0 ) {
84 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
85 return( AFPERR_PARAM );
87 /* See afp_closefork() for why this is bad */
88 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
92 /* can only get the length of the opened fork */
93 if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
94 ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
95 return( AFPERR_BITMAP );
98 if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
99 (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
100 (1 << FILPBIT_BDATE))) {
101 upath = mtoupath(ofork->of_vol, ofork->of_name);
102 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
103 if ( stat( upath, &st ) < 0 )
104 return( AFPERR_NOOBJ );
106 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
107 return( AFPERR_BITMAP );
113 return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
116 /* -------------------------
120 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
125 /* NOTE: we can't write lock a read-only file. on those, we just
126 * make sure that we have a read lock set. that way, we at least prevent
127 * someone else from really setting a deny read/write on the file.
129 lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
130 lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
132 return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
136 /* -------------------------
138 extern int ad_testlock(struct adouble *adp, int eid, int off);
140 static int getforkmode(struct adouble *adp, int eid, int what)
142 return ad_testlock(adp, eid, what);
145 /* --------------------------
146 a lot of races, some can be remove. but I try first to get the semantic right
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;
238 memcpy(&vid, ibuf, sizeof( vid ));
242 if (( vol = getvolbyvid( vid )) == NULL ) {
243 return( AFPERR_PARAM );
246 memcpy(&did, ibuf, sizeof( did ));
247 ibuf += sizeof( int );
249 if (( dir = dirsearch( vol, did )) == NULL ) {
250 return( AFPERR_NOOBJ );
253 memcpy(&bitmap, ibuf, sizeof( bitmap ));
254 bitmap = ntohs( bitmap );
255 ibuf += sizeof( bitmap );
256 memcpy(&access, ibuf, sizeof( access ));
257 access = ntohs( access );
258 ibuf += sizeof( access );
260 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
264 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
265 return( AFPERR_NOOBJ );
268 if ( fork == OPENFORK_DATA ) {
270 adflags = ADFLAGS_DF|ADFLAGS_HF;
273 adflags = ADFLAGS_HF;
276 /* XXX: this probably isn't the best way to do this. the already
277 open bits should really be set if the fork is opened by any
278 program, not just this one. however, that's problematic to do
279 if we can't write lock files somewhere. opened is also passed to
280 ad_open so that we can keep file locks together. */
281 if ((opened = of_findname(vol, curdir, path))) {
282 attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) |
283 ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
284 adsame = opened->of_ad;
287 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
289 return( AFPERR_NFILE );
291 if (access & OPENACC_WR) {
292 /* try opening in read-write mode */
293 upath = mtoupath(vol, path);
295 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
307 /* see if client asked for the data fork */
308 if (fork == OPENFORK_DATA) {
309 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
312 adflags = ADFLAGS_DF;
314 } else if (stat(upath, &st) == 0) {
315 /* here's the deal. we only try to create the resource
316 * fork if the user wants to open it for write acess. */
317 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
329 ret = AFPERR_BADTYPE;
333 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
340 /* try opening in read-only mode */
341 upath = mtoupath(vol, path);
343 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
348 /* check for a read-only data fork */
349 if ((adflags != ADFLAGS_HF) &&
350 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
353 adflags = ADFLAGS_DF;
359 /* see if client asked for the data fork */
360 if (fork == OPENFORK_DATA) {
361 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
364 adflags = ADFLAGS_DF;
366 } else if (stat(upath, &st) != 0) {
377 ret = AFPERR_BADTYPE;
381 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
388 if ((adflags & ADFLAGS_HF) &&
389 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
390 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
391 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
392 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
393 ad_flush( ofork->of_ad, adflags );
396 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
397 &buflen, attrbits )) != AFP_OK ) {
398 ad_close( ofork->of_ad, adflags );
402 *rbuflen = buflen + 2 * sizeof( u_int16_t );
403 bitmap = htons( bitmap );
404 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
405 rbuf += sizeof( u_int16_t );
408 * synchronization locks:
411 /* don't try to lock non-existent rforks. */
412 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
414 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
415 /* can we access the fork? */
418 ad_close( ofork->of_ad, adflags );
421 case EAGAIN: /* return data anyway */
425 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
426 return( AFPERR_DENYCONF );
430 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
431 return( AFPERR_PARAM );
434 if ((access & OPENACC_WR))
435 ofork->of_flags |= AFPFORK_ACCWR;
436 if ((access & OPENACC_RD))
437 ofork->of_flags |= AFPFORK_ACCRD;
440 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
446 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
450 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
453 int ibuflen, *rbuflen;
457 u_int16_t ofrefnum, bitmap;
461 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
462 ibuf += sizeof( ofrefnum );
463 memcpy(&bitmap, ibuf, sizeof(bitmap));
464 bitmap = ntohs(bitmap);
465 ibuf += sizeof( bitmap );
466 memcpy(&size, ibuf, sizeof( size ));
467 size = ntohl( size );
470 if (( ofork = of_find( ofrefnum )) == NULL ) {
471 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
472 return( AFPERR_PARAM );
475 if (ofork->of_vol->v_flags & AFPVOL_RO)
478 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
479 return AFPERR_ACCESS;
484 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
485 err = ad_dtruncate( ofork->of_ad, size );
487 goto afp_setfork_err;
488 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
489 (ofork->of_flags & AFPFORK_RSRC)) {
490 ad_refresh( ofork->of_ad );
491 err = ad_rtruncate(ofork->of_ad, size);
493 goto afp_setfork_err;
495 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
496 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
498 return( AFPERR_PARAM );
501 return AFPERR_BITMAP;
504 if ( flushfork( ofork ) < 0 ) {
505 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
520 return AFPERR_ACCESS;
531 /* for this to work correctly, we need to check for locks before each
532 * read and write. that's most easily handled by always doing an
533 * appropriate check before each ad_read/ad_write. other things
534 * that can change files like truncate are handled internally to those
537 #define ENDBIT(a) ((a) & 0x80)
538 #define UNLOCKBIT(a) ((a) & 0x01)
539 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
542 int ibuflen, *rbuflen;
545 int32_t offset, length;
552 /* figure out parameters */
554 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
556 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
557 ibuf += sizeof(ofrefnum);
559 if (( ofork = of_find( ofrefnum )) == NULL ) {
560 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
561 return( AFPERR_PARAM );
564 if ( ofork->of_flags & AFPFORK_DATA) {
566 } else if (ofork->of_flags & AFPFORK_RSRC) {
571 memcpy(&offset, ibuf, sizeof( offset ));
572 offset = ntohl(offset);
573 ibuf += sizeof(offset);
575 memcpy(&length, ibuf, sizeof( length ));
576 length = ntohl(length);
577 if (length == 0xFFFFFFFF)
578 length = BYTELOCK_MAX;
579 else if (length <= 0) {
581 } else if ((length >= AD_FILELOCK_BASE) &&
582 (ad_hfileno(ofork->of_ad) == -1))
586 offset += ad_size(ofork->of_ad, eid);
588 if (offset < 0) /* error if we have a negative offset */
591 /* if the file is a read-only file, we use read locks instead of
592 * write locks. that way, we can prevent anyone from initiating
594 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
595 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
596 ADLOCK_WR : ADLOCK_RD), offset, length,
597 ofork->of_refnum) < 0) {
601 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
607 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
616 offset = htonl(offset);
617 memcpy(rbuf, &offset, sizeof( offset ));
618 *rbuflen = sizeof( offset );
624 static __inline__ int crlf( of )
629 if ( ad_hfileno( of->of_ad ) == -1 ||
630 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
632 if (( em = getextmap( of->of_name )) == NULL ||
633 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
639 if ( memcmp( ufinderi,
640 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
649 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
650 int offset, u_char nlmask,
651 u_char nlchar, char *rbuf,
652 int *rbuflen, const int xlate)
658 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
660 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
662 return( AFPERR_PARAM );
664 if ( cc < *rbuflen ) {
672 for ( p = rbuf, q = p + cc; p < q; ) {
673 if (( *p++ & nlmask ) == nlchar ) {
684 * If this file is of type TEXT, then swap \012 to \015.
687 for ( p = rbuf, q = p + cc; p < q; p++ ) {
688 if ( *p == '\012' ) {
690 } else if ( *p == '\015' ) {
699 return( AFPERR_EOF );
704 /* -----------------------------
705 * with ddp, afp_read can return fewer bytes than in reqcount
706 * so return EOF only if read actually past end of file not
707 * if offset +reqcount > size of file
709 * getfork size ==> 10430
710 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
711 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
712 * read fork offset 9248 size 1508 ==> 1182 (EOF)
713 * 10752 is a bug in Mac 7.5.x finder
715 * with dsi, should we check that reqcount < server quantum?
717 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
720 int ibuflen, *rbuflen;
724 int32_t offset, saveoff, reqcount, savereqcount;
725 int cc, err, eid, xlate = 0;
727 u_char nlmask, nlchar;
730 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
731 ibuf += sizeof( u_short );
733 if (( ofork = of_find( ofrefnum )) == NULL ) {
734 LOG(log_error, logtype_afpd, "afp_read: of_find");
739 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
744 memcpy(&offset, ibuf, sizeof( offset ));
745 offset = ntohl( offset );
746 ibuf += sizeof( offset );
747 memcpy(&reqcount, ibuf, sizeof( reqcount ));
748 reqcount = ntohl( reqcount );
749 ibuf += sizeof( reqcount );
754 /* if we wanted to be picky, we could add in the following
755 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
757 if (reqcount < 0 || offset < 0) {
762 if ( ofork->of_flags & AFPFORK_DATA) {
764 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
765 } else if (ofork->of_flags & AFPFORK_RSRC) {
767 } else { /* fork wasn't opened. this should never really happen. */
772 /* zero request count */
778 /* reqcount isn't always truthful. we need to deal with that. */
779 size = ad_size(ofork->of_ad, eid);
781 if (offset >= size) {
786 savereqcount = reqcount;
788 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
793 #define min(a,b) ((a)<(b)?(a):(b))
794 *rbuflen = min( reqcount, *rbuflen );
795 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
800 /* dsi can stream requests. we can only do this if we're not checking
801 * for an end-of-line character. oh well. */
802 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
803 DSI *dsi = obj->handle;
805 if (obj->options.flags & OPTION_DEBUG) {
806 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
807 reqcount, dsi->clientID);
808 bprint(rbuf, *rbuflen);
810 /* subtract off the offset */
812 if (reqcount > size) {
819 /* dsi_readinit() returns size of next read buffer. by this point,
820 * we know that we're sending some data. if we fail, something
821 * horrible happened. */
822 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
825 /* due to the nature of afp packets, we have to exit if we get
826 an error. we can't do this with translation on. */
827 #ifdef HAVE_SENDFILE_READ
828 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
829 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
830 dsi->datasize) < 0) {
834 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
844 #endif /* HAVE_SENDFILE_READ */
846 /* fill up our buffer. */
847 while (*rbuflen > 0) {
848 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
854 if (obj->options.flags & OPTION_DEBUG) {
855 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
856 bprint(rbuf, *rbuflen);
859 /* dsi_read() also returns buffer size of next allocation */
860 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
869 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
871 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
876 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
884 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
887 int ibuflen, *rbuflen;
895 memcpy(&vid, ibuf, sizeof(vid));
896 if (( vol = getvolbyvid( vid )) == NULL ) {
897 return( AFPERR_PARAM );
904 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
907 int ibuflen, *rbuflen;
914 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
916 if (( ofork = of_find( ofrefnum )) == NULL ) {
917 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
918 return( AFPERR_PARAM );
921 if ( flushfork( ofork ) < 0 ) {
922 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
928 /* this is very similar to closefork */
929 int flushfork( ofork )
933 int len, err = 0, doflush = 0;
935 if ( ad_dfileno( ofork->of_ad ) != -1 &&
936 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
937 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
938 ad_dfileno(ofork->of_ad), strerror(errno) );
942 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
944 /* read in the rfork length */
945 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
946 ad_refresh(ofork->of_ad);
948 /* set the date if we're dirty */
949 if ((ofork->of_flags & AFPFORK_DIRTY) &&
950 (gettimeofday(&tv, NULL) == 0)) {
951 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
952 ofork->of_flags &= ~AFPFORK_DIRTY;
956 /* if we're actually flushing this fork, make sure to set the
957 * length. otherwise, just use the stored length */
958 if ((ofork->of_flags & AFPFORK_RSRC) &&
959 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
960 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
965 /* flush the header (if it is a resource fork) */
966 if (ofork->of_flags & AFPFORK_RSRC)
967 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
970 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
974 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
975 ad_hfileno(ofork->of_ad), strerror(errno) );
981 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
984 int ibuflen, *rbuflen;
988 int adflags, aint, doflush = 0;
993 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
995 if (( ofork = of_find( ofrefnum )) == NULL ) {
996 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
997 return( AFPERR_PARAM );
1001 if ((ofork->of_flags & AFPFORK_DATA) &&
1002 (ad_dfileno( ofork->of_ad ) != -1)) {
1003 adflags |= ADFLAGS_DF;
1006 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1007 adflags |= ADFLAGS_HF;
1009 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1010 ad_refresh( ofork->of_ad );
1011 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1012 (gettimeofday(&tv, NULL) == 0)) {
1013 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1019 * Only set the rfork's length if we're closing the rfork.
1021 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1022 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1023 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1027 ad_flush( ofork->of_ad, adflags );
1031 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1032 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1033 return( AFPERR_PARAM );
1036 of_dealloc( ofork );
1041 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1042 off_t offset, char *rbuf,
1043 size_t rbuflen, const int xlate)
1049 * If this file is of type TEXT, swap \015 to \012.
1052 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1053 if ( *p == '\015' ) {
1055 } else if ( *p == '\012' ) {
1061 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1062 rbuf, rbuflen)) < 0 ) {
1067 return( AFPERR_DFULL );
1069 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1070 return( AFPERR_PARAM );
1077 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1078 * the client may have sent us a bunch of data that's not reflected
1079 * in reqcount et al. */
1080 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1083 int ibuflen, *rbuflen;
1085 struct ofork *ofork;
1086 int32_t offset, saveoff, reqcount;
1087 int endflag, eid, xlate = 0, err = AFP_OK;
1091 /* figure out parameters */
1093 endflag = ENDBIT(*ibuf);
1095 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1096 ibuf += sizeof( ofrefnum );
1097 memcpy(&offset, ibuf, sizeof( offset ));
1098 offset = ntohl( offset );
1099 ibuf += sizeof( offset );
1100 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1101 reqcount = ntohl( reqcount );
1102 ibuf += sizeof( reqcount );
1104 if (( ofork = of_find( ofrefnum )) == NULL ) {
1105 LOG(log_error, logtype_afpd, "afp_write: of_find");
1110 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1111 err = AFPERR_ACCESS;
1116 writtenfork = ofork;
1119 if ( ofork->of_flags & AFPFORK_DATA) {
1121 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1122 } else if (ofork->of_flags & AFPFORK_RSRC) {
1125 err = AFPERR_ACCESS; /* should never happen */
1130 offset += ad_size(ofork->of_ad, eid);
1132 /* handle bogus parameters */
1133 if (reqcount < 0 || offset < 0) {
1138 /* offset can overflow on 64-bit capable filesystems.
1139 * report disk full if that's going to happen. */
1140 if (offset + reqcount < 0) {
1145 if (!reqcount) { /* handle request counts of 0 */
1147 offset = htonl(offset);
1148 memcpy(rbuf, &offset, sizeof(offset));
1153 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1159 /* this is yucky, but dsi can stream i/o and asp can't */
1160 switch (obj->proto) {
1163 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1165 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1166 return( AFPERR_PARAM );
1169 if (obj->options.flags & OPTION_DEBUG) {
1170 printf("(write) len: %d\n", *rbuflen);
1171 bprint(rbuf, *rbuflen);
1174 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1177 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1182 #endif /* no afp/asp */
1186 DSI *dsi = obj->handle;
1188 /* find out what we have already and write it out. */
1189 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1191 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1192 dsi_writeflush(dsi);
1194 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1199 #if 0 /*def HAVE_SENDFILE_WRITE*/
1200 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1201 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1202 offset, dsi->datasize)) < 0) {
1210 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1211 goto afp_write_loop;
1213 dsi_writeflush(dsi);
1215 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1221 goto afp_write_done;
1223 #endif /* 0, was HAVE_SENDFILE_WRITE */
1225 /* loop until everything gets written. currently
1226 * dsi_write handles the end case by itself. */
1227 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1228 if ( obj->options.flags & OPTION_DEBUG ) {
1229 printf("(write) command cont'd: %d\n", cc);
1233 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1234 dsi_writeflush(dsi);
1236 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1246 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1247 if ( ad_hfileno( ofork->of_ad ) != -1 )
1248 ofork->of_flags |= AFPFORK_DIRTY;
1250 offset = htonl( offset );
1251 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1252 bcopy(&offset, rbuf, sizeof(offset));
1253 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1254 memcpy(rbuf, &offset, sizeof(offset));
1255 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1256 *rbuflen = sizeof(offset);
1260 if (obj->proto == AFPPROTO_DSI) {
1261 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1262 dsi_writeflush(obj->handle);
1265 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1270 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1273 int ibuflen, *rbuflen;
1275 struct ofork *ofork;
1277 u_int16_t ofrefnum, bitmap;
1280 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1281 ibuf += sizeof( ofrefnum );
1282 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1283 bitmap = ntohs( bitmap );
1284 ibuf += sizeof( bitmap );
1287 if (( ofork = of_find( ofrefnum )) == NULL ) {
1288 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1289 return( AFPERR_PARAM );
1292 if (( ret = getforkparams( ofork, bitmap,
1293 rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1297 *rbuflen = buflen + sizeof( u_short );
1298 bitmap = htons( bitmap );
1299 memcpy(rbuf, &bitmap, sizeof( bitmap ));