2 * $Id: fork.c,v 1.36 2002-09-05 14:52:06 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 );
98 if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
99 (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
100 (1 << FILPBIT_BDATE))) {
101 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
102 upath = mtoupath(vol, ofork->of_name);
103 if (movecwd(vol, dir) < 0)
104 return( AFPERR_NOOBJ );
105 if ( stat( upath, &st ) < 0 )
106 return( AFPERR_NOOBJ );
108 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
109 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
148 #ifdef USE_FLOCK_LOCKS
149 #error sorry, for now configure --with-flock-locks is broken...
152 static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
161 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
162 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
165 if ((access & (OPENACC_RD | OPENACC_DRD))) {
166 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
168 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
171 if ((access & OPENACC_RD) && denyreadset) {
175 if ((access & OPENACC_DRD) && readset) {
179 /* boolean logic is not enough, because getforkmode is not always telling the
182 mode = ((access & OPENACC_DRD))?EXCL: SHARE;
183 if ((access & OPENACC_RD)) {
184 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
188 if ((access & OPENACC_DRD)) {
189 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
194 /* ------------same for writing -------------- */
195 if ((access & (OPENACC_WR | OPENACC_DWR))) {
196 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
198 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
201 if ((access & OPENACC_WR) && denywriteset) {
205 if ((access & OPENACC_DWR) && writeset) {
209 mode = ((access & OPENACC_DWR))?EXCL: SHARE;
210 if ((access & OPENACC_WR)) {
211 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
215 if ((access & OPENACC_DWR)) {
216 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
224 /* ----------------------- */
225 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
228 int ibuflen, *rbuflen;
232 struct ofork *ofork, *opened;
233 struct adouble *adsame = NULL;
234 int buflen, ret, adflags, eid, lockop;
236 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
237 char fork, *path, *upath;
243 memcpy(&vid, ibuf, sizeof( vid ));
247 if (( vol = getvolbyvid( vid )) == NULL ) {
248 return( AFPERR_PARAM );
251 memcpy(&did, ibuf, sizeof( did ));
252 ibuf += sizeof( int );
254 if (( dir = dirsearch( vol, did )) == NULL ) {
255 return( AFPERR_NOOBJ );
258 memcpy(&bitmap, ibuf, sizeof( bitmap ));
259 bitmap = ntohs( bitmap );
260 ibuf += sizeof( bitmap );
261 memcpy(&access, ibuf, sizeof( access ));
262 access = ntohs( access );
263 ibuf += sizeof( access );
265 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
269 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
270 return( AFPERR_NOOBJ );
273 if ( fork == OPENFORK_DATA ) {
275 adflags = ADFLAGS_DF|ADFLAGS_HF;
278 adflags = ADFLAGS_HF;
281 upath = mtoupath(vol, path);
282 if (check_access(upath, access ) < 0) {
283 return AFPERR_ACCESS;
286 /* stat() data fork */
287 if (stat(upath, &st) < 0) {
292 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
294 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
299 /* XXX: this probably isn't the best way to do this. the already
300 open bits should really be set if the fork is opened by any
301 program, not just this one. however, that's problematic to do
302 if we can't write lock files somewhere. opened is also passed to
303 ad_open so that we can keep file locks together.
304 FIXME: add the fork we are opening?
306 if ((opened = of_findname(upath, &st))) {
307 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
308 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
310 adsame = opened->of_ad;
313 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
314 adsame, &st)) == NULL ) {
315 return( AFPERR_NFILE );
319 if (access & OPENACC_WR) {
320 /* try opening in read-write mode */
321 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
329 if (fork == OPENFORK_DATA) {
330 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
333 adflags = ADFLAGS_DF;
335 /* here's the deal. we only try to create the resource
336 * fork if the user wants to open it for write acess. */
337 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
347 ret = AFPERR_BADTYPE;
351 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
358 /* try opening in read-only mode */
360 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
365 /* check for a read-only data fork */
366 if ((adflags != ADFLAGS_HF) &&
367 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
370 adflags = ADFLAGS_DF;
373 /* see if client asked for the data fork */
374 if (fork == OPENFORK_DATA) {
375 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
378 adflags = ADFLAGS_DF;
387 ret = AFPERR_BADTYPE;
391 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
398 if ((adflags & ADFLAGS_HF) &&
399 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
400 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
401 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
402 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
403 ad_flush( ofork->of_ad, adflags );
406 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
407 &buflen, attrbits )) != AFP_OK ) {
408 ad_close( ofork->of_ad, adflags );
412 *rbuflen = buflen + 2 * sizeof( u_int16_t );
413 bitmap = htons( bitmap );
414 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
415 rbuf += sizeof( u_int16_t );
417 /* check WriteInhibit bit, the test is done here, after some Mac trafic capture */
418 ad_getattr(ofork->of_ad, &bshort);
419 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
420 ad_close( ofork->of_ad, adflags );
423 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
424 return(AFPERR_OLOCK);
428 * synchronization locks:
431 /* don't try to lock non-existent rforks. */
432 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
434 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
435 /* can we access the fork? */
438 ad_close( ofork->of_ad, adflags );
441 case EAGAIN: /* return data anyway */
445 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
446 return( AFPERR_DENYCONF );
450 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
451 return( AFPERR_PARAM );
454 if ((access & OPENACC_WR))
455 ofork->of_flags |= AFPFORK_ACCWR;
456 if ((access & OPENACC_RD))
457 ofork->of_flags |= AFPFORK_ACCRD;
460 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
466 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
470 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
473 int ibuflen, *rbuflen;
477 u_int16_t ofrefnum, bitmap;
481 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
482 ibuf += sizeof( ofrefnum );
483 memcpy(&bitmap, ibuf, sizeof(bitmap));
484 bitmap = ntohs(bitmap);
485 ibuf += sizeof( bitmap );
486 memcpy(&size, ibuf, sizeof( size ));
487 size = ntohl( size );
490 if (( ofork = of_find( ofrefnum )) == NULL ) {
491 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
492 return( AFPERR_PARAM );
495 if (ofork->of_vol->v_flags & AFPVOL_RO)
498 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
499 return AFPERR_ACCESS;
504 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
505 err = ad_dtruncate( ofork->of_ad, size );
507 goto afp_setfork_err;
508 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
509 (ofork->of_flags & AFPFORK_RSRC)) {
510 ad_refresh( ofork->of_ad );
511 err = ad_rtruncate(ofork->of_ad, size);
513 goto afp_setfork_err;
515 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
516 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
518 return( AFPERR_PARAM );
521 return AFPERR_BITMAP;
524 if ( flushfork( ofork ) < 0 ) {
525 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
540 return AFPERR_ACCESS;
551 /* for this to work correctly, we need to check for locks before each
552 * read and write. that's most easily handled by always doing an
553 * appropriate check before each ad_read/ad_write. other things
554 * that can change files like truncate are handled internally to those
557 #define ENDBIT(a) ((a) & 0x80)
558 #define UNLOCKBIT(a) ((a) & 0x01)
559 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
562 int ibuflen, *rbuflen;
565 int32_t offset, length;
572 /* figure out parameters */
574 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
576 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
577 ibuf += sizeof(ofrefnum);
579 if (( ofork = of_find( ofrefnum )) == NULL ) {
580 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
581 return( AFPERR_PARAM );
584 if ( ofork->of_flags & AFPFORK_DATA) {
586 } else if (ofork->of_flags & AFPFORK_RSRC) {
591 memcpy(&offset, ibuf, sizeof( offset ));
592 offset = ntohl(offset);
593 ibuf += sizeof(offset);
595 memcpy(&length, ibuf, sizeof( length ));
596 length = ntohl(length);
597 if (length == 0xFFFFFFFF)
598 length = BYTELOCK_MAX;
599 else if (length <= 0) {
601 } else if ((length >= AD_FILELOCK_BASE) &&
602 (ad_hfileno(ofork->of_ad) == -1))
606 offset += ad_size(ofork->of_ad, eid);
608 if (offset < 0) /* error if we have a negative offset */
611 /* if the file is a read-only file, we use read locks instead of
612 * write locks. that way, we can prevent anyone from initiating
614 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
615 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
616 ADLOCK_WR : ADLOCK_RD), offset, length,
617 ofork->of_refnum) < 0) {
621 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
627 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
636 offset = htonl(offset);
637 memcpy(rbuf, &offset, sizeof( offset ));
638 *rbuflen = sizeof( offset );
644 static __inline__ int crlf( of )
649 if ( ad_hfileno( of->of_ad ) == -1 ||
650 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
652 if (( em = getextmap( of->of_name )) == NULL ||
653 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
659 if ( memcmp( ufinderi,
660 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
669 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
670 int offset, u_char nlmask,
671 u_char nlchar, char *rbuf,
672 int *rbuflen, const int xlate)
678 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
680 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
682 return( AFPERR_PARAM );
684 if ( cc < *rbuflen ) {
692 for ( p = rbuf, q = p + cc; p < q; ) {
693 if (( *p++ & nlmask ) == nlchar ) {
704 * If this file is of type TEXT, then swap \012 to \015.
707 for ( p = rbuf, q = p + cc; p < q; p++ ) {
708 if ( *p == '\012' ) {
710 } else if ( *p == '\015' ) {
719 return( AFPERR_EOF );
724 /* -----------------------------
725 * with ddp, afp_read can return fewer bytes than in reqcount
726 * so return EOF only if read actually past end of file not
727 * if offset +reqcount > size of file
729 * getfork size ==> 10430
730 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
731 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
732 * read fork offset 9248 size 1508 ==> 1182 (EOF)
733 * 10752 is a bug in Mac 7.5.x finder
735 * with dsi, should we check that reqcount < server quantum?
737 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
740 int ibuflen, *rbuflen;
744 int32_t offset, saveoff, reqcount, savereqcount;
745 int cc, err, eid, xlate = 0;
747 u_char nlmask, nlchar;
750 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
751 ibuf += sizeof( u_short );
753 if (( ofork = of_find( ofrefnum )) == NULL ) {
754 LOG(log_error, logtype_afpd, "afp_read: of_find");
759 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
764 memcpy(&offset, ibuf, sizeof( offset ));
765 offset = ntohl( offset );
766 ibuf += sizeof( offset );
767 memcpy(&reqcount, ibuf, sizeof( reqcount ));
768 reqcount = ntohl( reqcount );
769 ibuf += sizeof( reqcount );
774 /* if we wanted to be picky, we could add in the following
775 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
777 if (reqcount < 0 || offset < 0) {
782 if ( ofork->of_flags & AFPFORK_DATA) {
784 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
785 } else if (ofork->of_flags & AFPFORK_RSRC) {
787 } else { /* fork wasn't opened. this should never really happen. */
792 /* zero request count */
798 /* reqcount isn't always truthful. we need to deal with that. */
799 size = ad_size(ofork->of_ad, eid);
801 if (offset >= size) {
806 savereqcount = reqcount;
808 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
813 #define min(a,b) ((a)<(b)?(a):(b))
814 *rbuflen = min( reqcount, *rbuflen );
815 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
820 /* dsi can stream requests. we can only do this if we're not checking
821 * for an end-of-line character. oh well. */
822 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
823 DSI *dsi = obj->handle;
825 if (obj->options.flags & OPTION_DEBUG) {
826 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
827 reqcount, dsi->clientID);
828 bprint(rbuf, *rbuflen);
830 /* subtract off the offset */
832 if (reqcount > size) {
839 /* dsi_readinit() returns size of next read buffer. by this point,
840 * we know that we're sending some data. if we fail, something
841 * horrible happened. */
842 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
845 /* due to the nature of afp packets, we have to exit if we get
846 an error. we can't do this with translation on. */
847 #ifdef HAVE_SENDFILE_READ
848 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
849 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
850 dsi->datasize) < 0) {
854 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
864 #endif /* HAVE_SENDFILE_READ */
866 /* fill up our buffer. */
867 while (*rbuflen > 0) {
868 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
874 if (obj->options.flags & OPTION_DEBUG) {
875 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
876 bprint(rbuf, *rbuflen);
879 /* dsi_read() also returns buffer size of next allocation */
880 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
889 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
891 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
896 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
904 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
907 int ibuflen, *rbuflen;
915 memcpy(&vid, ibuf, sizeof(vid));
916 if (( vol = getvolbyvid( vid )) == NULL ) {
917 return( AFPERR_PARAM );
924 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
927 int ibuflen, *rbuflen;
934 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
936 if (( ofork = of_find( ofrefnum )) == NULL ) {
937 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
938 return( AFPERR_PARAM );
941 if ( flushfork( ofork ) < 0 ) {
942 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
948 /* this is very similar to closefork */
949 int flushfork( ofork )
953 int len, err = 0, doflush = 0;
955 if ( ad_dfileno( ofork->of_ad ) != -1 &&
956 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
957 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
958 ad_dfileno(ofork->of_ad), strerror(errno) );
962 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
964 /* read in the rfork length */
965 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
966 ad_refresh(ofork->of_ad);
968 /* set the date if we're dirty */
969 if ((ofork->of_flags & AFPFORK_DIRTY) &&
970 (gettimeofday(&tv, NULL) == 0)) {
971 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
972 ofork->of_flags &= ~AFPFORK_DIRTY;
976 /* if we're actually flushing this fork, make sure to set the
977 * length. otherwise, just use the stored length */
978 if ((ofork->of_flags & AFPFORK_RSRC) &&
979 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
980 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
985 /* flush the header (if it is a resource fork) */
986 if (ofork->of_flags & AFPFORK_RSRC)
987 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
990 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
994 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
995 ad_hfileno(ofork->of_ad), strerror(errno) );
1001 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1004 int ibuflen, *rbuflen;
1006 struct ofork *ofork;
1008 int adflags, aint, doflush = 0;
1013 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1015 if (( ofork = of_find( ofrefnum )) == NULL ) {
1016 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1017 return( AFPERR_PARAM );
1021 if ((ofork->of_flags & AFPFORK_DATA) &&
1022 (ad_dfileno( ofork->of_ad ) != -1)) {
1023 adflags |= ADFLAGS_DF;
1026 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1027 adflags |= ADFLAGS_HF;
1029 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1030 ad_refresh( ofork->of_ad );
1031 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1032 (gettimeofday(&tv, NULL) == 0)) {
1033 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1039 * Only set the rfork's length if we're closing the rfork.
1041 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1042 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1043 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1047 ad_flush( ofork->of_ad, adflags );
1051 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1052 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1053 return( AFPERR_PARAM );
1056 of_dealloc( ofork );
1061 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1062 off_t offset, char *rbuf,
1063 size_t rbuflen, const int xlate)
1069 * If this file is of type TEXT, swap \015 to \012.
1072 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1073 if ( *p == '\015' ) {
1075 } else if ( *p == '\012' ) {
1081 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1082 rbuf, rbuflen)) < 0 ) {
1087 return( AFPERR_DFULL );
1089 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1090 return( AFPERR_PARAM );
1097 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1098 * the client may have sent us a bunch of data that's not reflected
1099 * in reqcount et al. */
1100 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1103 int ibuflen, *rbuflen;
1105 struct ofork *ofork;
1106 int32_t offset, saveoff, reqcount;
1107 int endflag, eid, xlate = 0, err = AFP_OK;
1111 /* figure out parameters */
1113 endflag = ENDBIT(*ibuf);
1115 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1116 ibuf += sizeof( ofrefnum );
1117 memcpy(&offset, ibuf, sizeof( offset ));
1118 offset = ntohl( offset );
1119 ibuf += sizeof( offset );
1120 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1121 reqcount = ntohl( reqcount );
1122 ibuf += sizeof( reqcount );
1124 if (( ofork = of_find( ofrefnum )) == NULL ) {
1125 LOG(log_error, logtype_afpd, "afp_write: of_find");
1130 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1131 err = AFPERR_ACCESS;
1136 writtenfork = ofork;
1139 if ( ofork->of_flags & AFPFORK_DATA) {
1141 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1142 } else if (ofork->of_flags & AFPFORK_RSRC) {
1145 err = AFPERR_ACCESS; /* should never happen */
1150 offset += ad_size(ofork->of_ad, eid);
1152 /* handle bogus parameters */
1153 if (reqcount < 0 || offset < 0) {
1158 /* offset can overflow on 64-bit capable filesystems.
1159 * report disk full if that's going to happen. */
1160 if (offset + reqcount < 0) {
1165 if (!reqcount) { /* handle request counts of 0 */
1167 offset = htonl(offset);
1168 memcpy(rbuf, &offset, sizeof(offset));
1173 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1179 /* this is yucky, but dsi can stream i/o and asp can't */
1180 switch (obj->proto) {
1183 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1185 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1186 return( AFPERR_PARAM );
1189 if (obj->options.flags & OPTION_DEBUG) {
1190 printf("(write) len: %d\n", *rbuflen);
1191 bprint(rbuf, *rbuflen);
1194 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1197 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1202 #endif /* no afp/asp */
1206 DSI *dsi = obj->handle;
1208 /* find out what we have already and write it out. */
1209 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1211 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1212 dsi_writeflush(dsi);
1214 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1219 #if 0 /*def HAVE_SENDFILE_WRITE*/
1220 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1221 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1222 offset, dsi->datasize)) < 0) {
1230 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1231 goto afp_write_loop;
1233 dsi_writeflush(dsi);
1235 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1241 goto afp_write_done;
1243 #endif /* 0, was HAVE_SENDFILE_WRITE */
1245 /* loop until everything gets written. currently
1246 * dsi_write handles the end case by itself. */
1247 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1248 if ( obj->options.flags & OPTION_DEBUG ) {
1249 printf("(write) command cont'd: %d\n", cc);
1253 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1254 dsi_writeflush(dsi);
1256 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1266 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1267 if ( ad_hfileno( ofork->of_ad ) != -1 )
1268 ofork->of_flags |= AFPFORK_DIRTY;
1270 offset = htonl( offset );
1271 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1272 bcopy(&offset, rbuf, sizeof(offset));
1273 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1274 memcpy(rbuf, &offset, sizeof(offset));
1275 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1276 *rbuflen = sizeof(offset);
1280 if (obj->proto == AFPPROTO_DSI) {
1281 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1282 dsi_writeflush(obj->handle);
1285 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1290 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1293 int ibuflen, *rbuflen;
1295 struct ofork *ofork;
1297 u_int16_t ofrefnum, bitmap;
1298 u_int16_t attrbits = 0;
1301 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1302 ibuf += sizeof( ofrefnum );
1303 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1304 bitmap = ntohs( bitmap );
1305 ibuf += sizeof( bitmap );
1308 if (( ofork = of_find( ofrefnum )) == NULL ) {
1309 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1310 return( AFPERR_PARAM );
1312 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1313 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1315 if (( ret = getforkparams( ofork, bitmap,
1316 rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
1320 *rbuflen = buflen + sizeof( u_short );
1321 bitmap = htons( bitmap );
1322 memcpy(rbuf, &bitmap, sizeof( bitmap ));