2 * $Id: fork.c,v 1.31 2002-08-20 19:40:45 srittau 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
146 static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
155 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
156 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
159 if ((access & (OPENACC_RD | OPENACC_DRD))) {
160 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
162 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
165 if ((access & OPENACC_RD) && denyreadset) {
169 if ((access & OPENACC_DRD) && readset) {
173 /* boolean logic is not enough, because getforkmode is not always telling the
176 mode = ((access & OPENACC_DRD))?EXCL: SHARE;
177 if ((access & OPENACC_RD)) {
178 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
182 if ((access & OPENACC_DRD)) {
183 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
188 /* ------------same for writing -------------- */
189 if ((access & (OPENACC_WR | OPENACC_DWR))) {
190 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
192 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
195 if ((access & OPENACC_WR) && denywriteset) {
199 if ((access & OPENACC_DWR) && writeset) {
203 mode = ((access & OPENACC_DWR))?EXCL: SHARE;
204 if ((access & OPENACC_WR)) {
205 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
209 if ((access & OPENACC_DWR)) {
210 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
218 /* ----------------------- */
219 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
222 int ibuflen, *rbuflen;
226 struct ofork *ofork, *opened;
227 struct adouble *adsame = NULL;
228 int buflen, ret, adflags, eid, lockop;
230 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
231 char fork, *path, *upath;
236 memcpy(&vid, ibuf, sizeof( vid ));
240 if (( vol = getvolbyvid( vid )) == NULL ) {
241 return( AFPERR_PARAM );
244 memcpy(&did, ibuf, sizeof( did ));
245 ibuf += sizeof( int );
247 if (( dir = dirsearch( vol, did )) == NULL ) {
248 return( AFPERR_NOOBJ );
251 memcpy(&bitmap, ibuf, sizeof( bitmap ));
252 bitmap = ntohs( bitmap );
253 ibuf += sizeof( bitmap );
254 memcpy(&access, ibuf, sizeof( access ));
255 access = ntohs( access );
256 ibuf += sizeof( access );
258 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
262 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
263 return( AFPERR_NOOBJ );
266 if ( fork == OPENFORK_DATA ) {
268 adflags = ADFLAGS_DF|ADFLAGS_HF;
271 adflags = ADFLAGS_HF;
274 /* XXX: this probably isn't the best way to do this. the already
275 open bits should really be set if the fork is opened by any
276 program, not just this one. however, that's problematic to do
277 if we can't write lock files somewhere. opened is also passed to
278 ad_open so that we can keep file locks together.
279 FIXME: add the fork we are opening?
281 if ((opened = of_findname(vol, curdir, path))) {
282 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
283 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
285 adsame = opened->of_ad;
288 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
290 return( AFPERR_NFILE );
292 if (access & OPENACC_WR) {
293 /* try opening in read-write mode */
294 upath = mtoupath(vol, path);
296 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
308 /* see if client asked for the data fork */
309 if (fork == OPENFORK_DATA) {
310 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
313 adflags = ADFLAGS_DF;
315 } else if (stat(upath, &st) == 0) {
316 /* here's the deal. we only try to create the resource
317 * fork if the user wants to open it for write acess. */
318 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
330 ret = AFPERR_BADTYPE;
334 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
341 /* try opening in read-only mode */
342 upath = mtoupath(vol, path);
344 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
349 /* check for a read-only data fork */
350 if ((adflags != ADFLAGS_HF) &&
351 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
354 adflags = ADFLAGS_DF;
360 /* see if client asked for the data fork */
361 if (fork == OPENFORK_DATA) {
362 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
365 adflags = ADFLAGS_DF;
367 } else if (stat(upath, &st) != 0) {
378 ret = AFPERR_BADTYPE;
382 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
389 if ((adflags & ADFLAGS_HF) &&
390 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
391 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
392 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
393 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
394 ad_flush( ofork->of_ad, adflags );
397 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
398 &buflen, attrbits )) != AFP_OK ) {
399 ad_close( ofork->of_ad, adflags );
403 *rbuflen = buflen + 2 * sizeof( u_int16_t );
404 bitmap = htons( bitmap );
405 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
406 rbuf += sizeof( u_int16_t );
408 /* check WriteInhibit bit, the test is done here, after some Mac trafic capture */
409 ad_getattr(ofork->of_ad, &bshort);
410 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
411 ad_close( ofork->of_ad, adflags );
414 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
415 return(AFPERR_OLOCK);
419 * synchronization locks:
422 /* don't try to lock non-existent rforks. */
423 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
425 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
426 /* can we access the fork? */
429 ad_close( ofork->of_ad, adflags );
432 case EAGAIN: /* return data anyway */
436 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
437 return( AFPERR_DENYCONF );
441 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
442 return( AFPERR_PARAM );
445 if ((access & OPENACC_WR))
446 ofork->of_flags |= AFPFORK_ACCWR;
447 if ((access & OPENACC_RD))
448 ofork->of_flags |= AFPFORK_ACCRD;
451 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
457 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
461 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
464 int ibuflen, *rbuflen;
468 u_int16_t ofrefnum, bitmap;
472 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
473 ibuf += sizeof( ofrefnum );
474 memcpy(&bitmap, ibuf, sizeof(bitmap));
475 bitmap = ntohs(bitmap);
476 ibuf += sizeof( bitmap );
477 memcpy(&size, ibuf, sizeof( size ));
478 size = ntohl( size );
481 if (( ofork = of_find( ofrefnum )) == NULL ) {
482 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
483 return( AFPERR_PARAM );
486 if (ofork->of_vol->v_flags & AFPVOL_RO)
489 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
490 return AFPERR_ACCESS;
495 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
496 err = ad_dtruncate( ofork->of_ad, size );
498 goto afp_setfork_err;
499 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
500 (ofork->of_flags & AFPFORK_RSRC)) {
501 ad_refresh( ofork->of_ad );
502 err = ad_rtruncate(ofork->of_ad, size);
504 goto afp_setfork_err;
506 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
507 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
509 return( AFPERR_PARAM );
512 return AFPERR_BITMAP;
515 if ( flushfork( ofork ) < 0 ) {
516 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
531 return AFPERR_ACCESS;
542 /* for this to work correctly, we need to check for locks before each
543 * read and write. that's most easily handled by always doing an
544 * appropriate check before each ad_read/ad_write. other things
545 * that can change files like truncate are handled internally to those
548 #define ENDBIT(a) ((a) & 0x80)
549 #define UNLOCKBIT(a) ((a) & 0x01)
550 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
553 int ibuflen, *rbuflen;
556 int32_t offset, length;
563 /* figure out parameters */
565 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
567 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
568 ibuf += sizeof(ofrefnum);
570 if (( ofork = of_find( ofrefnum )) == NULL ) {
571 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
572 return( AFPERR_PARAM );
575 if ( ofork->of_flags & AFPFORK_DATA) {
577 } else if (ofork->of_flags & AFPFORK_RSRC) {
582 memcpy(&offset, ibuf, sizeof( offset ));
583 offset = ntohl(offset);
584 ibuf += sizeof(offset);
586 memcpy(&length, ibuf, sizeof( length ));
587 length = ntohl(length);
588 if (length == 0xFFFFFFFF)
589 length = BYTELOCK_MAX;
590 else if (length <= 0) {
592 } else if ((length >= AD_FILELOCK_BASE) &&
593 (ad_hfileno(ofork->of_ad) == -1))
597 offset += ad_size(ofork->of_ad, eid);
599 if (offset < 0) /* error if we have a negative offset */
602 /* if the file is a read-only file, we use read locks instead of
603 * write locks. that way, we can prevent anyone from initiating
605 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
606 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
607 ADLOCK_WR : ADLOCK_RD), offset, length,
608 ofork->of_refnum) < 0) {
612 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
618 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
627 offset = htonl(offset);
628 memcpy(rbuf, &offset, sizeof( offset ));
629 *rbuflen = sizeof( offset );
635 static __inline__ int crlf( of )
640 if ( ad_hfileno( of->of_ad ) == -1 ||
641 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
643 if (( em = getextmap( of->of_name )) == NULL ||
644 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
650 if ( memcmp( ufinderi,
651 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
660 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
661 int offset, u_char nlmask,
662 u_char nlchar, char *rbuf,
663 int *rbuflen, const int xlate)
669 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
671 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
673 return( AFPERR_PARAM );
675 if ( cc < *rbuflen ) {
683 for ( p = rbuf, q = p + cc; p < q; ) {
684 if (( *p++ & nlmask ) == nlchar ) {
695 * If this file is of type TEXT, then swap \012 to \015.
698 for ( p = rbuf, q = p + cc; p < q; p++ ) {
699 if ( *p == '\012' ) {
701 } else if ( *p == '\015' ) {
710 return( AFPERR_EOF );
715 /* -----------------------------
716 * with ddp, afp_read can return fewer bytes than in reqcount
717 * so return EOF only if read actually past end of file not
718 * if offset +reqcount > size of file
720 * getfork size ==> 10430
721 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
722 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
723 * read fork offset 9248 size 1508 ==> 1182 (EOF)
724 * 10752 is a bug in Mac 7.5.x finder
726 * with dsi, should we check that reqcount < server quantum?
728 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
731 int ibuflen, *rbuflen;
735 int32_t offset, saveoff, reqcount, savereqcount;
736 int cc, err, eid, xlate = 0;
738 u_char nlmask, nlchar;
741 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
742 ibuf += sizeof( u_short );
744 if (( ofork = of_find( ofrefnum )) == NULL ) {
745 LOG(log_error, logtype_afpd, "afp_read: of_find");
750 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
755 memcpy(&offset, ibuf, sizeof( offset ));
756 offset = ntohl( offset );
757 ibuf += sizeof( offset );
758 memcpy(&reqcount, ibuf, sizeof( reqcount ));
759 reqcount = ntohl( reqcount );
760 ibuf += sizeof( reqcount );
765 /* if we wanted to be picky, we could add in the following
766 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
768 if (reqcount < 0 || offset < 0) {
773 if ( ofork->of_flags & AFPFORK_DATA) {
775 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
776 } else if (ofork->of_flags & AFPFORK_RSRC) {
778 } else { /* fork wasn't opened. this should never really happen. */
783 /* zero request count */
789 /* reqcount isn't always truthful. we need to deal with that. */
790 size = ad_size(ofork->of_ad, eid);
792 if (offset >= size) {
797 savereqcount = reqcount;
799 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
804 #define min(a,b) ((a)<(b)?(a):(b))
805 *rbuflen = min( reqcount, *rbuflen );
806 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
811 /* dsi can stream requests. we can only do this if we're not checking
812 * for an end-of-line character. oh well. */
813 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
814 DSI *dsi = obj->handle;
816 if (obj->options.flags & OPTION_DEBUG) {
817 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
818 reqcount, dsi->clientID);
819 bprint(rbuf, *rbuflen);
821 /* subtract off the offset */
823 if (reqcount > size) {
830 /* dsi_readinit() returns size of next read buffer. by this point,
831 * we know that we're sending some data. if we fail, something
832 * horrible happened. */
833 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
836 /* due to the nature of afp packets, we have to exit if we get
837 an error. we can't do this with translation on. */
838 #ifdef HAVE_SENDFILE_READ
839 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
840 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
841 dsi->datasize) < 0) {
845 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
855 #endif /* HAVE_SENDFILE_READ */
857 /* fill up our buffer. */
858 while (*rbuflen > 0) {
859 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
865 if (obj->options.flags & OPTION_DEBUG) {
866 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
867 bprint(rbuf, *rbuflen);
870 /* dsi_read() also returns buffer size of next allocation */
871 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
880 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
882 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
887 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
895 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
898 int ibuflen, *rbuflen;
906 memcpy(&vid, ibuf, sizeof(vid));
907 if (( vol = getvolbyvid( vid )) == NULL ) {
908 return( AFPERR_PARAM );
915 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
918 int ibuflen, *rbuflen;
925 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
927 if (( ofork = of_find( ofrefnum )) == NULL ) {
928 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
929 return( AFPERR_PARAM );
932 if ( flushfork( ofork ) < 0 ) {
933 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
939 /* this is very similar to closefork */
940 int flushfork( ofork )
944 int len, err = 0, doflush = 0;
946 if ( ad_dfileno( ofork->of_ad ) != -1 &&
947 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
948 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
949 ad_dfileno(ofork->of_ad), strerror(errno) );
953 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
955 /* read in the rfork length */
956 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
957 ad_refresh(ofork->of_ad);
959 /* set the date if we're dirty */
960 if ((ofork->of_flags & AFPFORK_DIRTY) &&
961 (gettimeofday(&tv, NULL) == 0)) {
962 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
963 ofork->of_flags &= ~AFPFORK_DIRTY;
967 /* if we're actually flushing this fork, make sure to set the
968 * length. otherwise, just use the stored length */
969 if ((ofork->of_flags & AFPFORK_RSRC) &&
970 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
971 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
976 /* flush the header (if it is a resource fork) */
977 if (ofork->of_flags & AFPFORK_RSRC)
978 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
981 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
985 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
986 ad_hfileno(ofork->of_ad), strerror(errno) );
992 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
995 int ibuflen, *rbuflen;
999 int adflags, aint, doflush = 0;
1004 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1006 if (( ofork = of_find( ofrefnum )) == NULL ) {
1007 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1008 return( AFPERR_PARAM );
1012 if ((ofork->of_flags & AFPFORK_DATA) &&
1013 (ad_dfileno( ofork->of_ad ) != -1)) {
1014 adflags |= ADFLAGS_DF;
1017 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1018 adflags |= ADFLAGS_HF;
1020 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1021 ad_refresh( ofork->of_ad );
1022 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1023 (gettimeofday(&tv, NULL) == 0)) {
1024 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1030 * Only set the rfork's length if we're closing the rfork.
1032 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1033 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1034 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1038 ad_flush( ofork->of_ad, adflags );
1042 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1043 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1044 return( AFPERR_PARAM );
1047 of_dealloc( ofork );
1052 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1053 off_t offset, char *rbuf,
1054 size_t rbuflen, const int xlate)
1060 * If this file is of type TEXT, swap \015 to \012.
1063 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1064 if ( *p == '\015' ) {
1066 } else if ( *p == '\012' ) {
1072 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1073 rbuf, rbuflen)) < 0 ) {
1078 return( AFPERR_DFULL );
1080 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1081 return( AFPERR_PARAM );
1088 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1089 * the client may have sent us a bunch of data that's not reflected
1090 * in reqcount et al. */
1091 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1094 int ibuflen, *rbuflen;
1096 struct ofork *ofork;
1097 int32_t offset, saveoff, reqcount;
1098 int endflag, eid, xlate = 0, err = AFP_OK;
1102 /* figure out parameters */
1104 endflag = ENDBIT(*ibuf);
1106 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1107 ibuf += sizeof( ofrefnum );
1108 memcpy(&offset, ibuf, sizeof( offset ));
1109 offset = ntohl( offset );
1110 ibuf += sizeof( offset );
1111 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1112 reqcount = ntohl( reqcount );
1113 ibuf += sizeof( reqcount );
1115 if (( ofork = of_find( ofrefnum )) == NULL ) {
1116 LOG(log_error, logtype_afpd, "afp_write: of_find");
1121 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1122 err = AFPERR_ACCESS;
1127 writtenfork = ofork;
1130 if ( ofork->of_flags & AFPFORK_DATA) {
1132 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1133 } else if (ofork->of_flags & AFPFORK_RSRC) {
1136 err = AFPERR_ACCESS; /* should never happen */
1141 offset += ad_size(ofork->of_ad, eid);
1143 /* handle bogus parameters */
1144 if (reqcount < 0 || offset < 0) {
1149 /* offset can overflow on 64-bit capable filesystems.
1150 * report disk full if that's going to happen. */
1151 if (offset + reqcount < 0) {
1156 if (!reqcount) { /* handle request counts of 0 */
1158 offset = htonl(offset);
1159 memcpy(rbuf, &offset, sizeof(offset));
1164 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1170 /* this is yucky, but dsi can stream i/o and asp can't */
1171 switch (obj->proto) {
1174 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1176 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1177 return( AFPERR_PARAM );
1180 if (obj->options.flags & OPTION_DEBUG) {
1181 printf("(write) len: %d\n", *rbuflen);
1182 bprint(rbuf, *rbuflen);
1185 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1188 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1193 #endif /* no afp/asp */
1197 DSI *dsi = obj->handle;
1199 /* find out what we have already and write it out. */
1200 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1202 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1203 dsi_writeflush(dsi);
1205 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1210 #if 0 /*def HAVE_SENDFILE_WRITE*/
1211 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1212 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1213 offset, dsi->datasize)) < 0) {
1221 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1222 goto afp_write_loop;
1224 dsi_writeflush(dsi);
1226 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1232 goto afp_write_done;
1234 #endif /* 0, was HAVE_SENDFILE_WRITE */
1236 /* loop until everything gets written. currently
1237 * dsi_write handles the end case by itself. */
1238 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1239 if ( obj->options.flags & OPTION_DEBUG ) {
1240 printf("(write) command cont'd: %d\n", cc);
1244 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1245 dsi_writeflush(dsi);
1247 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1257 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1258 if ( ad_hfileno( ofork->of_ad ) != -1 )
1259 ofork->of_flags |= AFPFORK_DIRTY;
1261 offset = htonl( offset );
1262 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1263 bcopy(&offset, rbuf, sizeof(offset));
1264 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1265 memcpy(rbuf, &offset, sizeof(offset));
1266 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1267 *rbuflen = sizeof(offset);
1271 if (obj->proto == AFPPROTO_DSI) {
1272 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1273 dsi_writeflush(obj->handle);
1276 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1281 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1284 int ibuflen, *rbuflen;
1286 struct ofork *ofork;
1288 u_int16_t ofrefnum, bitmap;
1289 u_int16_t attrbits = 0;
1292 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1293 ibuf += sizeof( ofrefnum );
1294 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1295 bitmap = ntohs( bitmap );
1296 ibuf += sizeof( bitmap );
1299 if (( ofork = of_find( ofrefnum )) == NULL ) {
1300 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1301 return( AFPERR_PARAM );
1303 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1304 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1306 if (( ret = getforkparams( ofork, bitmap,
1307 rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
1311 *rbuflen = buflen + sizeof( u_short );
1312 bitmap = htons( bitmap );
1313 memcpy(rbuf, &bitmap, sizeof( bitmap ));