2 * $Id: fork.c,v 1.28 2002-05-29 17:40:36 jmarcus 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 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
707 int ibuflen, *rbuflen;
711 int32_t offset, saveoff, reqcount, savereqcount;
712 int cc, err, saveerr, eid, xlate = 0;
714 u_char nlmask, nlchar;
717 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
718 ibuf += sizeof( u_short );
720 if (( ofork = of_find( ofrefnum )) == NULL ) {
721 LOG(log_error, logtype_afpd, "afp_read: of_find");
726 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
731 memcpy(&offset, ibuf, sizeof( offset ));
732 offset = ntohl( offset );
733 ibuf += sizeof( offset );
734 memcpy(&reqcount, ibuf, sizeof( reqcount ));
735 reqcount = ntohl( reqcount );
736 ibuf += sizeof( reqcount );
741 /* if we wanted to be picky, we could add in the following
742 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
744 if (reqcount < 0 || offset < 0) {
749 if ( ofork->of_flags & AFPFORK_DATA) {
751 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
752 } else if (ofork->of_flags & AFPFORK_RSRC) {
754 } else { /* fork wasn't opened. this should never really happen. */
759 /* zero request count */
765 /* reqcount isn't always truthful. we need to deal with that. */
766 size = ad_size(ofork->of_ad, eid);
768 if (offset >= size) {
773 /* subtract off the offset */
775 savereqcount = reqcount;
776 if (reqcount > size) {
782 /* if EOF lock on the old reqcount, some prg may need it */
783 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
788 #define min(a,b) ((a)<(b)?(a):(b))
789 *rbuflen = min( reqcount, *rbuflen );
791 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
798 /* dsi can stream requests. we can only do this if we're not checking
799 * for an end-of-line character. oh well. */
800 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
801 DSI *dsi = obj->handle;
803 if (obj->options.flags & OPTION_DEBUG) {
804 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
805 reqcount, dsi->clientID);
806 bprint(rbuf, *rbuflen);
811 /* dsi_readinit() returns size of next read buffer. by this point,
812 * we know that we're sending some data. if we fail, something
813 * horrible happened. */
814 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
817 /* due to the nature of afp packets, we have to exit if we get
818 an error. we can't do this with translation on. */
819 #ifdef HAVE_SENDFILE_READ
820 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
821 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
822 dsi->datasize) < 0) {
826 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
836 #endif /* HAVE_SENDFILE_READ */
838 /* fill up our buffer. */
839 while (*rbuflen > 0) {
840 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
846 if (obj->options.flags & OPTION_DEBUG) {
847 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
848 bprint(rbuf, *rbuflen);
851 /* dsi_read() also returns buffer size of next allocation */
852 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
861 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
863 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
868 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
876 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
879 int ibuflen, *rbuflen;
887 memcpy(&vid, ibuf, sizeof(vid));
888 if (( vol = getvolbyvid( vid )) == NULL ) {
889 return( AFPERR_PARAM );
896 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
899 int ibuflen, *rbuflen;
906 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
908 if (( ofork = of_find( ofrefnum )) == NULL ) {
909 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
910 return( AFPERR_PARAM );
913 if ( flushfork( ofork ) < 0 ) {
914 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
920 /* this is very similar to closefork */
921 int flushfork( ofork )
925 int len, err = 0, doflush = 0;
927 if ( ad_dfileno( ofork->of_ad ) != -1 &&
928 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
929 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
930 ad_dfileno(ofork->of_ad), strerror(errno) );
934 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
936 /* read in the rfork length */
937 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
938 ad_refresh(ofork->of_ad);
940 /* set the date if we're dirty */
941 if ((ofork->of_flags & AFPFORK_DIRTY) &&
942 (gettimeofday(&tv, NULL) == 0)) {
943 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
944 ofork->of_flags &= ~AFPFORK_DIRTY;
948 /* if we're actually flushing this fork, make sure to set the
949 * length. otherwise, just use the stored length */
950 if ((ofork->of_flags & AFPFORK_RSRC) &&
951 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
952 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
957 /* flush the header (if it is a resource fork) */
958 if (ofork->of_flags & AFPFORK_RSRC)
959 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
962 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
966 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
967 ad_hfileno(ofork->of_ad), strerror(errno) );
973 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
976 int ibuflen, *rbuflen;
980 int adflags, aint, doflush = 0;
985 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
987 if (( ofork = of_find( ofrefnum )) == NULL ) {
988 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
989 return( AFPERR_PARAM );
993 if ((ofork->of_flags & AFPFORK_DATA) &&
994 (ad_dfileno( ofork->of_ad ) != -1)) {
995 adflags |= ADFLAGS_DF;
998 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
999 adflags |= ADFLAGS_HF;
1001 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1002 ad_refresh( ofork->of_ad );
1003 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1004 (gettimeofday(&tv, NULL) == 0)) {
1005 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1011 * Only set the rfork's length if we're closing the rfork.
1013 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1014 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1015 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1019 ad_flush( ofork->of_ad, adflags );
1023 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1024 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1025 return( AFPERR_PARAM );
1028 of_dealloc( ofork );
1033 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1034 off_t offset, char *rbuf,
1035 size_t rbuflen, const int xlate)
1041 * If this file is of type TEXT, swap \015 to \012.
1044 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1045 if ( *p == '\015' ) {
1047 } else if ( *p == '\012' ) {
1053 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1054 rbuf, rbuflen)) < 0 ) {
1059 return( AFPERR_DFULL );
1061 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1062 return( AFPERR_PARAM );
1069 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1070 * the client may have sent us a bunch of data that's not reflected
1071 * in reqcount et al. */
1072 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1075 int ibuflen, *rbuflen;
1077 struct ofork *ofork;
1078 int32_t offset, saveoff, reqcount;
1079 int endflag, eid, xlate = 0, err = AFP_OK;
1083 /* figure out parameters */
1085 endflag = ENDBIT(*ibuf);
1087 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1088 ibuf += sizeof( ofrefnum );
1089 memcpy(&offset, ibuf, sizeof( offset ));
1090 offset = ntohl( offset );
1091 ibuf += sizeof( offset );
1092 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1093 reqcount = ntohl( reqcount );
1094 ibuf += sizeof( reqcount );
1096 if (( ofork = of_find( ofrefnum )) == NULL ) {
1097 LOG(log_error, logtype_afpd, "afp_write: of_find");
1102 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1103 err = AFPERR_ACCESS;
1108 writtenfork = ofork;
1111 if ( ofork->of_flags & AFPFORK_DATA) {
1113 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1114 } else if (ofork->of_flags & AFPFORK_RSRC) {
1117 err = AFPERR_ACCESS; /* should never happen */
1122 offset += ad_size(ofork->of_ad, eid);
1124 /* handle bogus parameters */
1125 if (reqcount < 0 || offset < 0) {
1130 /* offset can overflow on 64-bit capable filesystems.
1131 * report disk full if that's going to happen. */
1132 if (offset + reqcount < 0) {
1137 if (!reqcount) { /* handle request counts of 0 */
1139 offset = htonl(offset);
1140 memcpy(rbuf, &offset, sizeof(offset));
1145 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1151 /* this is yucky, but dsi can stream i/o and asp can't */
1152 switch (obj->proto) {
1155 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1157 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1158 return( AFPERR_PARAM );
1161 if (obj->options.flags & OPTION_DEBUG) {
1162 printf("(write) len: %d\n", *rbuflen);
1163 bprint(rbuf, *rbuflen);
1166 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1169 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1174 #endif /* no afp/asp */
1178 DSI *dsi = obj->handle;
1180 /* find out what we have already and write it out. */
1181 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1183 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1184 dsi_writeflush(dsi);
1186 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1191 #if 0 /*def HAVE_SENDFILE_WRITE*/
1192 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1193 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1194 offset, dsi->datasize)) < 0) {
1202 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1203 goto afp_write_loop;
1205 dsi_writeflush(dsi);
1207 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1213 goto afp_write_done;
1215 #endif /* 0, was HAVE_SENDFILE_WRITE */
1217 /* loop until everything gets written. currently
1218 * dsi_write handles the end case by itself. */
1219 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1220 if ( obj->options.flags & OPTION_DEBUG ) {
1221 printf("(write) command cont'd: %d\n", cc);
1225 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1226 dsi_writeflush(dsi);
1228 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1238 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1239 if ( ad_hfileno( ofork->of_ad ) != -1 )
1240 ofork->of_flags |= AFPFORK_DIRTY;
1242 offset = htonl( offset );
1243 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1244 bcopy(&offset, rbuf, sizeof(offset));
1245 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1246 memcpy(rbuf, &offset, sizeof(offset));
1247 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1248 *rbuflen = sizeof(offset);
1252 if (obj->proto == AFPPROTO_DSI) {
1253 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1254 dsi_writeflush(obj->handle);
1257 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1262 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1265 int ibuflen, *rbuflen;
1267 struct ofork *ofork;
1269 u_int16_t ofrefnum, bitmap;
1272 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1273 ibuf += sizeof( ofrefnum );
1274 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1275 bitmap = ntohs( bitmap );
1276 ibuf += sizeof( bitmap );
1279 if (( ofork = of_find( ofrefnum )) == NULL ) {
1280 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1281 return( AFPERR_PARAM );
1284 if (( ret = getforkparams( ofork, bitmap,
1285 rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1289 *rbuflen = buflen + sizeof( u_short );
1290 bitmap = htons( bitmap );
1291 memcpy(rbuf, &bitmap, sizeof( bitmap ));