2 * $Id: fork.c,v 1.33 2002-08-26 08:57:50 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;
242 memcpy(&vid, ibuf, sizeof( vid ));
246 if (( vol = getvolbyvid( vid )) == NULL ) {
247 return( AFPERR_PARAM );
250 memcpy(&did, ibuf, sizeof( did ));
251 ibuf += sizeof( int );
253 if (( dir = dirsearch( vol, did )) == NULL ) {
254 return( AFPERR_NOOBJ );
257 memcpy(&bitmap, ibuf, sizeof( bitmap ));
258 bitmap = ntohs( bitmap );
259 ibuf += sizeof( bitmap );
260 memcpy(&access, ibuf, sizeof( access ));
261 access = ntohs( access );
262 ibuf += sizeof( access );
264 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
268 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
269 return( AFPERR_NOOBJ );
272 if ( fork == OPENFORK_DATA ) {
274 adflags = ADFLAGS_DF|ADFLAGS_HF;
277 adflags = ADFLAGS_HF;
280 /* XXX: this probably isn't the best way to do this. the already
281 open bits should really be set if the fork is opened by any
282 program, not just this one. however, that's problematic to do
283 if we can't write lock files somewhere. opened is also passed to
284 ad_open so that we can keep file locks together.
285 FIXME: add the fork we are opening?
287 if ((opened = of_findname(vol, curdir, path))) {
288 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
289 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
291 adsame = opened->of_ad;
294 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
296 return( AFPERR_NFILE );
298 if (access & OPENACC_WR) {
299 /* try opening in read-write mode */
300 upath = mtoupath(vol, path);
302 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
314 /* see if client asked for the data fork */
315 if (fork == OPENFORK_DATA) {
316 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
319 adflags = ADFLAGS_DF;
321 } else if (stat(upath, &st) == 0) {
322 /* here's the deal. we only try to create the resource
323 * fork if the user wants to open it for write acess. */
324 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
336 ret = AFPERR_BADTYPE;
340 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
347 /* try opening in read-only mode */
348 upath = mtoupath(vol, path);
350 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
355 /* check for a read-only data fork */
356 if ((adflags != ADFLAGS_HF) &&
357 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
360 adflags = ADFLAGS_DF;
366 /* see if client asked for the data fork */
367 if (fork == OPENFORK_DATA) {
368 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
371 adflags = ADFLAGS_DF;
373 } else if (stat(upath, &st) != 0) {
384 ret = AFPERR_BADTYPE;
388 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
395 if ((adflags & ADFLAGS_HF) &&
396 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
397 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
398 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
399 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
400 ad_flush( ofork->of_ad, adflags );
403 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
404 &buflen, attrbits )) != AFP_OK ) {
405 ad_close( ofork->of_ad, adflags );
409 *rbuflen = buflen + 2 * sizeof( u_int16_t );
410 bitmap = htons( bitmap );
411 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
412 rbuf += sizeof( u_int16_t );
414 /* check WriteInhibit bit, the test is done here, after some Mac trafic capture */
415 ad_getattr(ofork->of_ad, &bshort);
416 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
417 ad_close( ofork->of_ad, adflags );
420 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
421 return(AFPERR_OLOCK);
425 * synchronization locks:
428 /* don't try to lock non-existent rforks. */
429 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
431 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
432 /* can we access the fork? */
435 ad_close( ofork->of_ad, adflags );
438 case EAGAIN: /* return data anyway */
442 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
443 return( AFPERR_DENYCONF );
447 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
448 return( AFPERR_PARAM );
451 if ((access & OPENACC_WR))
452 ofork->of_flags |= AFPFORK_ACCWR;
453 if ((access & OPENACC_RD))
454 ofork->of_flags |= AFPFORK_ACCRD;
457 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
463 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
467 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
470 int ibuflen, *rbuflen;
474 u_int16_t ofrefnum, bitmap;
478 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
479 ibuf += sizeof( ofrefnum );
480 memcpy(&bitmap, ibuf, sizeof(bitmap));
481 bitmap = ntohs(bitmap);
482 ibuf += sizeof( bitmap );
483 memcpy(&size, ibuf, sizeof( size ));
484 size = ntohl( size );
487 if (( ofork = of_find( ofrefnum )) == NULL ) {
488 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
489 return( AFPERR_PARAM );
492 if (ofork->of_vol->v_flags & AFPVOL_RO)
495 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
496 return AFPERR_ACCESS;
501 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
502 err = ad_dtruncate( ofork->of_ad, size );
504 goto afp_setfork_err;
505 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
506 (ofork->of_flags & AFPFORK_RSRC)) {
507 ad_refresh( ofork->of_ad );
508 err = ad_rtruncate(ofork->of_ad, size);
510 goto afp_setfork_err;
512 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
513 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
515 return( AFPERR_PARAM );
518 return AFPERR_BITMAP;
521 if ( flushfork( ofork ) < 0 ) {
522 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
537 return AFPERR_ACCESS;
548 /* for this to work correctly, we need to check for locks before each
549 * read and write. that's most easily handled by always doing an
550 * appropriate check before each ad_read/ad_write. other things
551 * that can change files like truncate are handled internally to those
554 #define ENDBIT(a) ((a) & 0x80)
555 #define UNLOCKBIT(a) ((a) & 0x01)
556 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
559 int ibuflen, *rbuflen;
562 int32_t offset, length;
569 /* figure out parameters */
571 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
573 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
574 ibuf += sizeof(ofrefnum);
576 if (( ofork = of_find( ofrefnum )) == NULL ) {
577 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
578 return( AFPERR_PARAM );
581 if ( ofork->of_flags & AFPFORK_DATA) {
583 } else if (ofork->of_flags & AFPFORK_RSRC) {
588 memcpy(&offset, ibuf, sizeof( offset ));
589 offset = ntohl(offset);
590 ibuf += sizeof(offset);
592 memcpy(&length, ibuf, sizeof( length ));
593 length = ntohl(length);
594 if (length == 0xFFFFFFFF)
595 length = BYTELOCK_MAX;
596 else if (length <= 0) {
598 } else if ((length >= AD_FILELOCK_BASE) &&
599 (ad_hfileno(ofork->of_ad) == -1))
603 offset += ad_size(ofork->of_ad, eid);
605 if (offset < 0) /* error if we have a negative offset */
608 /* if the file is a read-only file, we use read locks instead of
609 * write locks. that way, we can prevent anyone from initiating
611 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
612 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
613 ADLOCK_WR : ADLOCK_RD), offset, length,
614 ofork->of_refnum) < 0) {
618 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
624 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
633 offset = htonl(offset);
634 memcpy(rbuf, &offset, sizeof( offset ));
635 *rbuflen = sizeof( offset );
641 static __inline__ int crlf( of )
646 if ( ad_hfileno( of->of_ad ) == -1 ||
647 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
649 if (( em = getextmap( of->of_name )) == NULL ||
650 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
656 if ( memcmp( ufinderi,
657 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
666 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
667 int offset, u_char nlmask,
668 u_char nlchar, char *rbuf,
669 int *rbuflen, const int xlate)
675 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
677 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
679 return( AFPERR_PARAM );
681 if ( cc < *rbuflen ) {
689 for ( p = rbuf, q = p + cc; p < q; ) {
690 if (( *p++ & nlmask ) == nlchar ) {
701 * If this file is of type TEXT, then swap \012 to \015.
704 for ( p = rbuf, q = p + cc; p < q; p++ ) {
705 if ( *p == '\012' ) {
707 } else if ( *p == '\015' ) {
716 return( AFPERR_EOF );
721 /* -----------------------------
722 * with ddp, afp_read can return fewer bytes than in reqcount
723 * so return EOF only if read actually past end of file not
724 * if offset +reqcount > size of file
726 * getfork size ==> 10430
727 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
728 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
729 * read fork offset 9248 size 1508 ==> 1182 (EOF)
730 * 10752 is a bug in Mac 7.5.x finder
732 * with dsi, should we check that reqcount < server quantum?
734 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
737 int ibuflen, *rbuflen;
741 int32_t offset, saveoff, reqcount, savereqcount;
742 int cc, err, eid, xlate = 0;
744 u_char nlmask, nlchar;
747 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
748 ibuf += sizeof( u_short );
750 if (( ofork = of_find( ofrefnum )) == NULL ) {
751 LOG(log_error, logtype_afpd, "afp_read: of_find");
756 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
761 memcpy(&offset, ibuf, sizeof( offset ));
762 offset = ntohl( offset );
763 ibuf += sizeof( offset );
764 memcpy(&reqcount, ibuf, sizeof( reqcount ));
765 reqcount = ntohl( reqcount );
766 ibuf += sizeof( reqcount );
771 /* if we wanted to be picky, we could add in the following
772 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
774 if (reqcount < 0 || offset < 0) {
779 if ( ofork->of_flags & AFPFORK_DATA) {
781 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
782 } else if (ofork->of_flags & AFPFORK_RSRC) {
784 } else { /* fork wasn't opened. this should never really happen. */
789 /* zero request count */
795 /* reqcount isn't always truthful. we need to deal with that. */
796 size = ad_size(ofork->of_ad, eid);
798 if (offset >= size) {
803 savereqcount = reqcount;
805 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
810 #define min(a,b) ((a)<(b)?(a):(b))
811 *rbuflen = min( reqcount, *rbuflen );
812 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
817 /* dsi can stream requests. we can only do this if we're not checking
818 * for an end-of-line character. oh well. */
819 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
820 DSI *dsi = obj->handle;
822 if (obj->options.flags & OPTION_DEBUG) {
823 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
824 reqcount, dsi->clientID);
825 bprint(rbuf, *rbuflen);
827 /* subtract off the offset */
829 if (reqcount > size) {
836 /* dsi_readinit() returns size of next read buffer. by this point,
837 * we know that we're sending some data. if we fail, something
838 * horrible happened. */
839 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
842 /* due to the nature of afp packets, we have to exit if we get
843 an error. we can't do this with translation on. */
844 #ifdef HAVE_SENDFILE_READ
845 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
846 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
847 dsi->datasize) < 0) {
851 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
861 #endif /* HAVE_SENDFILE_READ */
863 /* fill up our buffer. */
864 while (*rbuflen > 0) {
865 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
871 if (obj->options.flags & OPTION_DEBUG) {
872 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
873 bprint(rbuf, *rbuflen);
876 /* dsi_read() also returns buffer size of next allocation */
877 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
886 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
888 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
893 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
901 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
904 int ibuflen, *rbuflen;
912 memcpy(&vid, ibuf, sizeof(vid));
913 if (( vol = getvolbyvid( vid )) == NULL ) {
914 return( AFPERR_PARAM );
921 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
924 int ibuflen, *rbuflen;
931 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
933 if (( ofork = of_find( ofrefnum )) == NULL ) {
934 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
935 return( AFPERR_PARAM );
938 if ( flushfork( ofork ) < 0 ) {
939 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
945 /* this is very similar to closefork */
946 int flushfork( ofork )
950 int len, err = 0, doflush = 0;
952 if ( ad_dfileno( ofork->of_ad ) != -1 &&
953 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
954 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
955 ad_dfileno(ofork->of_ad), strerror(errno) );
959 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
961 /* read in the rfork length */
962 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
963 ad_refresh(ofork->of_ad);
965 /* set the date if we're dirty */
966 if ((ofork->of_flags & AFPFORK_DIRTY) &&
967 (gettimeofday(&tv, NULL) == 0)) {
968 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
969 ofork->of_flags &= ~AFPFORK_DIRTY;
973 /* if we're actually flushing this fork, make sure to set the
974 * length. otherwise, just use the stored length */
975 if ((ofork->of_flags & AFPFORK_RSRC) &&
976 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
977 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
982 /* flush the header (if it is a resource fork) */
983 if (ofork->of_flags & AFPFORK_RSRC)
984 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
987 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
991 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
992 ad_hfileno(ofork->of_ad), strerror(errno) );
998 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1001 int ibuflen, *rbuflen;
1003 struct ofork *ofork;
1005 int adflags, aint, doflush = 0;
1010 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1012 if (( ofork = of_find( ofrefnum )) == NULL ) {
1013 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1014 return( AFPERR_PARAM );
1018 if ((ofork->of_flags & AFPFORK_DATA) &&
1019 (ad_dfileno( ofork->of_ad ) != -1)) {
1020 adflags |= ADFLAGS_DF;
1023 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1024 adflags |= ADFLAGS_HF;
1026 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1027 ad_refresh( ofork->of_ad );
1028 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1029 (gettimeofday(&tv, NULL) == 0)) {
1030 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1036 * Only set the rfork's length if we're closing the rfork.
1038 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1039 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1040 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1044 ad_flush( ofork->of_ad, adflags );
1048 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1049 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1050 return( AFPERR_PARAM );
1053 of_dealloc( ofork );
1058 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1059 off_t offset, char *rbuf,
1060 size_t rbuflen, const int xlate)
1066 * If this file is of type TEXT, swap \015 to \012.
1069 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1070 if ( *p == '\015' ) {
1072 } else if ( *p == '\012' ) {
1078 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1079 rbuf, rbuflen)) < 0 ) {
1084 return( AFPERR_DFULL );
1086 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1087 return( AFPERR_PARAM );
1094 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1095 * the client may have sent us a bunch of data that's not reflected
1096 * in reqcount et al. */
1097 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1100 int ibuflen, *rbuflen;
1102 struct ofork *ofork;
1103 int32_t offset, saveoff, reqcount;
1104 int endflag, eid, xlate = 0, err = AFP_OK;
1108 /* figure out parameters */
1110 endflag = ENDBIT(*ibuf);
1112 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1113 ibuf += sizeof( ofrefnum );
1114 memcpy(&offset, ibuf, sizeof( offset ));
1115 offset = ntohl( offset );
1116 ibuf += sizeof( offset );
1117 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1118 reqcount = ntohl( reqcount );
1119 ibuf += sizeof( reqcount );
1121 if (( ofork = of_find( ofrefnum )) == NULL ) {
1122 LOG(log_error, logtype_afpd, "afp_write: of_find");
1127 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1128 err = AFPERR_ACCESS;
1133 writtenfork = ofork;
1136 if ( ofork->of_flags & AFPFORK_DATA) {
1138 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1139 } else if (ofork->of_flags & AFPFORK_RSRC) {
1142 err = AFPERR_ACCESS; /* should never happen */
1147 offset += ad_size(ofork->of_ad, eid);
1149 /* handle bogus parameters */
1150 if (reqcount < 0 || offset < 0) {
1155 /* offset can overflow on 64-bit capable filesystems.
1156 * report disk full if that's going to happen. */
1157 if (offset + reqcount < 0) {
1162 if (!reqcount) { /* handle request counts of 0 */
1164 offset = htonl(offset);
1165 memcpy(rbuf, &offset, sizeof(offset));
1170 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1176 /* this is yucky, but dsi can stream i/o and asp can't */
1177 switch (obj->proto) {
1180 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1182 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1183 return( AFPERR_PARAM );
1186 if (obj->options.flags & OPTION_DEBUG) {
1187 printf("(write) len: %d\n", *rbuflen);
1188 bprint(rbuf, *rbuflen);
1191 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1194 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1199 #endif /* no afp/asp */
1203 DSI *dsi = obj->handle;
1205 /* find out what we have already and write it out. */
1206 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1208 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1209 dsi_writeflush(dsi);
1211 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1216 #if 0 /*def HAVE_SENDFILE_WRITE*/
1217 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1218 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1219 offset, dsi->datasize)) < 0) {
1227 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1228 goto afp_write_loop;
1230 dsi_writeflush(dsi);
1232 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1238 goto afp_write_done;
1240 #endif /* 0, was HAVE_SENDFILE_WRITE */
1242 /* loop until everything gets written. currently
1243 * dsi_write handles the end case by itself. */
1244 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1245 if ( obj->options.flags & OPTION_DEBUG ) {
1246 printf("(write) command cont'd: %d\n", cc);
1250 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1251 dsi_writeflush(dsi);
1253 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1263 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1264 if ( ad_hfileno( ofork->of_ad ) != -1 )
1265 ofork->of_flags |= AFPFORK_DIRTY;
1267 offset = htonl( offset );
1268 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1269 bcopy(&offset, rbuf, sizeof(offset));
1270 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1271 memcpy(rbuf, &offset, sizeof(offset));
1272 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1273 *rbuflen = sizeof(offset);
1277 if (obj->proto == AFPPROTO_DSI) {
1278 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1279 dsi_writeflush(obj->handle);
1282 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1287 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1290 int ibuflen, *rbuflen;
1292 struct ofork *ofork;
1294 u_int16_t ofrefnum, bitmap;
1295 u_int16_t attrbits = 0;
1298 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1299 ibuf += sizeof( ofrefnum );
1300 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1301 bitmap = ntohs( bitmap );
1302 ibuf += sizeof( bitmap );
1305 if (( ofork = of_find( ofrefnum )) == NULL ) {
1306 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1307 return( AFPERR_PARAM );
1309 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1310 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1312 if (( ret = getforkparams( ofork, bitmap,
1313 rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
1317 *rbuflen = buflen + sizeof( u_short );
1318 bitmap = htons( bitmap );
1319 memcpy(rbuf, &bitmap, sizeof( bitmap ));