2
* $Id: fork.c,v 1.37.2.3 2003/11/20 17:21:01 bfernhomberg 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>
47
#include "directory.h"
51
#define BYTELOCK_MAX 0x7FFFFFFFU
53
struct ofork *writtenfork;
54
extern int getmetadata(struct vol *vol,
56
char *path, struct dir *dir, struct stat *st,
57
char *buf, int *buflen, struct adouble *adp, int attrbits );
59
static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
64
const u_int16_t attrbits;
74
if ( ad_hfileno( ofork->of_ad ) == -1 ) {
77
aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
78
if ( ad_refresh( ofork->of_ad ) < 0 ) {
79
LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
80
return( AFPERR_PARAM );
82
/* See afp_closefork() for why this is bad */
83
ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
87
/* can only get the length of the opened fork */
88
if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
89
((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
90
return( AFPERR_BITMAP );
96
if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
97
(1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
98
(1 << FILPBIT_BDATE))) {
99
if ( ad_dfileno( ofork->of_ad ) == -1 ) {
100
upath = mtoupath(vol, ofork->of_name);
101
if (movecwd(vol, dir) < 0)
102
return( AFPERR_NOOBJ );
103
if ( stat( upath, &st ) < 0 )
104
return( AFPERR_NOOBJ );
106
if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
107
return( AFPERR_BITMAP );
111
return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
114
/* -------------------------
118
static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
123
/* NOTE: we can't write lock a read-only file. on those, we just
124
* make sure that we have a read lock set. that way, we at least prevent
125
* someone else from really setting a deny read/write on the file.
127
lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
128
lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
130
return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
134
/* -------------------------
136
extern int ad_testlock(struct adouble *adp, int eid, int off);
138
static int getforkmode(struct adouble *adp, int eid, int what)
140
return ad_testlock(adp, eid, what);
143
/* --------------------------
144
a lot of races, some can be remove. but I try first to get the semantic right
147
static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
156
if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
157
return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
160
if ((access & (OPENACC_RD | OPENACC_DRD))) {
161
if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
163
if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
166
if ((access & OPENACC_RD) && denyreadset) {
170
if ((access & OPENACC_DRD) && readset) {
174
/* boolean logic is not enough, because getforkmode is not always telling the
177
mode = ((access & OPENACC_DRD))?EXCL: SHARE;
178
if ((access & OPENACC_RD)) {
179
ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
183
if ((access & OPENACC_DRD)) {
184
ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
189
/* ------------same for writing -------------- */
190
if ((access & (OPENACC_WR | OPENACC_DWR))) {
191
if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
193
if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
196
if ((access & OPENACC_WR) && denywriteset) {
200
if ((access & OPENACC_DWR) && writeset) {
204
mode = ((access & OPENACC_DWR))?EXCL: SHARE;
205
if ((access & OPENACC_WR)) {
206
ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
210
if ((access & OPENACC_DWR)) {
211
ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
219
/* ----------------------- */
220
int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
223
int ibuflen, *rbuflen;
227
struct ofork *ofork, *opened;
228
struct adouble *adsame = NULL;
229
int buflen, ret, adflags, eid;
231
u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
232
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 = dirlookup( 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
upath = mtoupath(vol, path);
277
if (check_access(upath, access ) < 0) {
278
return AFPERR_ACCESS;
281
/* stat() data fork */
282
if (stat(upath, &st) < 0) {
287
return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
289
LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
294
/* XXX: this probably isn't the best way to do this. the already
295
open bits should really be set if the fork is opened by any
296
program, not just this one. however, that's problematic to do
297
if we can't write lock files somewhere. opened is also passed to
298
ad_open so that we can keep file locks together.
299
FIXME: add the fork we are opening?
301
if ((opened = of_findname(upath, &st))) {
302
attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
303
attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
305
adsame = opened->of_ad;
308
if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
309
adsame, &st)) == NULL ) {
310
return( AFPERR_NFILE );
314
if (access & OPENACC_WR) {
315
/* try opening in read-write mode */
316
if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
324
if (fork == OPENFORK_DATA) {
325
if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
328
adflags = ADFLAGS_DF;
330
/* here's the deal. we only try to create the resource
331
* fork if the user wants to open it for write acess. */
332
if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
342
ret = AFPERR_BADTYPE;
346
LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
353
/* try opening in read-only mode */
355
if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
360
/* check for a read-only data fork */
361
if ((adflags != ADFLAGS_HF) &&
362
(ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
365
adflags = ADFLAGS_DF;
368
/* see if client asked for the data fork */
369
if (fork == OPENFORK_DATA) {
370
if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
373
adflags = ADFLAGS_DF;
382
ret = AFPERR_BADTYPE;
386
LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
393
if ((adflags & ADFLAGS_HF) &&
394
(ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
395
ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
396
memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
397
ad_getentrylen( ofork->of_ad, ADEID_NAME ));
398
ad_flush( ofork->of_ad, adflags );
401
if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
402
&buflen, attrbits )) != AFP_OK ) {
403
ad_close( ofork->of_ad, adflags );
407
*rbuflen = buflen + 2 * sizeof( u_int16_t );
408
bitmap = htons( bitmap );
409
memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
410
rbuf += sizeof( u_int16_t );
412
/* check WriteInhibit bit, the test is done here, after some Mac trafic capture */
413
ad_getattr(ofork->of_ad, &bshort);
414
if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
415
ad_close( ofork->of_ad, adflags );
418
memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
419
return(AFPERR_OLOCK);
423
* synchronization locks:
426
/* don't try to lock non-existent rforks. */
427
if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
429
ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
430
/* can we access the fork? */
433
ad_close( ofork->of_ad, adflags );
436
case EAGAIN: /* return data anyway */
440
memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
441
return( AFPERR_DENYCONF );
445
LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
446
return( AFPERR_PARAM );
449
if ((access & OPENACC_WR))
450
ofork->of_flags |= AFPFORK_ACCWR;
451
if ((access & OPENACC_RD))
452
ofork->of_flags |= AFPFORK_ACCRD;
455
memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
461
return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
465
int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
468
int ibuflen, *rbuflen;
472
u_int16_t ofrefnum, bitmap;
476
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
477
ibuf += sizeof( ofrefnum );
478
memcpy(&bitmap, ibuf, sizeof(bitmap));
479
bitmap = ntohs(bitmap);
480
ibuf += sizeof( bitmap );
481
memcpy(&size, ibuf, sizeof( size ));
482
size = ntohl( size );
485
if (( ofork = of_find( ofrefnum )) == NULL ) {
486
LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
487
return( AFPERR_PARAM );
490
if (ofork->of_vol->v_flags & AFPVOL_RO)
493
if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
494
return AFPERR_ACCESS;
499
if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
500
err = ad_dtruncate( ofork->of_ad, size );
502
goto afp_setfork_err;
503
} else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
504
(ofork->of_flags & AFPFORK_RSRC)) {
505
ad_refresh( ofork->of_ad );
506
err = ad_rtruncate(ofork->of_ad, size);
508
goto afp_setfork_err;
510
if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
511
LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
513
return( AFPERR_PARAM );
516
return AFPERR_BITMAP;
519
if ( flushfork( ofork ) < 0 ) {
520
LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
535
return AFPERR_ACCESS;
546
/* for this to work correctly, we need to check for locks before each
547
* read and write. that's most easily handled by always doing an
548
* appropriate check before each ad_read/ad_write. other things
549
* that can change files like truncate are handled internally to those
552
#define ENDBIT(a) ((a) & 0x80)
553
#define UNLOCKBIT(a) ((a) & 0x01)
554
int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
557
int ibuflen, *rbuflen;
560
int32_t offset, length;
567
/* figure out parameters */
569
flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
571
memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
572
ibuf += sizeof(ofrefnum);
574
if (( ofork = of_find( ofrefnum )) == NULL ) {
575
LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
576
return( AFPERR_PARAM );
579
if ( ofork->of_flags & AFPFORK_DATA) {
581
} else if (ofork->of_flags & AFPFORK_RSRC) {
586
memcpy(&offset, ibuf, sizeof( offset ));
587
offset = ntohl(offset);
588
ibuf += sizeof(offset);
590
memcpy(&length, ibuf, sizeof( length ));
591
length = ntohl(length);
592
if (length == 0xFFFFFFFF)
593
length = BYTELOCK_MAX;
594
else if (length <= 0) {
596
} else if ((length >= AD_FILELOCK_BASE) &&
597
(ad_hfileno(ofork->of_ad) == -1))
601
offset += ad_size(ofork->of_ad, eid);
603
if (offset < 0) /* error if we have a negative offset */
606
/* if the file is a read-only file, we use read locks instead of
607
* write locks. that way, we can prevent anyone from initiating
609
if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
610
((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
611
ADLOCK_WR : ADLOCK_RD), offset, length,
612
ofork->of_refnum) < 0) {
616
return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
622
return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
631
offset = htonl(offset);
632
memcpy(rbuf, &offset, sizeof( offset ));
633
*rbuflen = sizeof( offset );
639
static __inline__ int crlf( of )
644
if ( ad_hfileno( of->of_ad ) == -1 ||
645
memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
647
if (( em = getextmap( of->of_name )) == NULL ||
648
memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
654
if ( memcmp( ufinderi,
655
ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
664
static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
665
int offset, u_char nlmask,
666
u_char nlchar, char *rbuf,
667
int *rbuflen, const int xlate)
673
cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
675
LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
677
return( AFPERR_PARAM );
679
if ( cc < *rbuflen ) {
687
for ( p = rbuf, q = p + cc; p < q; ) {
688
if (( *p++ & nlmask ) == nlchar ) {
699
* If this file is of type TEXT, then swap \012 to \015.
702
for ( p = rbuf, q = p + cc; p < q; p++ ) {
703
if ( *p == '\012' ) {
705
} else if ( *p == '\015' ) {
714
return( AFPERR_EOF );
719
/* -----------------------------
720
* with ddp, afp_read can return fewer bytes than in reqcount
721
* so return EOF only if read actually past end of file not
722
* if offset +reqcount > size of file
724
* getfork size ==> 10430
725
* read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
726
* read fork offset 4264 size 6128 ==> 4264 (without EOF)
727
* read fork offset 9248 size 1508 ==> 1182 (EOF)
728
* 10752 is a bug in Mac 7.5.x finder
730
* with dsi, should we check that reqcount < server quantum?
732
int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
735
int ibuflen, *rbuflen;
739
int32_t offset, saveoff, reqcount, savereqcount;
740
int cc, err, eid, xlate = 0;
742
u_char nlmask, nlchar;
745
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
746
ibuf += sizeof( u_short );
748
if (( ofork = of_find( ofrefnum )) == NULL ) {
749
LOG(log_error, logtype_afpd, "afp_read: of_find");
754
if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
759
memcpy(&offset, ibuf, sizeof( offset ));
760
offset = ntohl( offset );
761
ibuf += sizeof( offset );
762
memcpy(&reqcount, ibuf, sizeof( reqcount ));
763
reqcount = ntohl( reqcount );
764
ibuf += sizeof( reqcount );
769
/* if we wanted to be picky, we could add in the following
770
* bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
772
if (reqcount < 0 || offset < 0) {
777
if ( ofork->of_flags & AFPFORK_DATA) {
779
xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
780
} else if (ofork->of_flags & AFPFORK_RSRC) {
782
} else { /* fork wasn't opened. this should never really happen. */
787
/* zero request count */
793
/* reqcount isn't always truthful. we need to deal with that. */
794
size = ad_size(ofork->of_ad, eid);
796
if (offset >= size) {
801
savereqcount = reqcount;
803
if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
808
#define min(a,b) ((a)<(b)?(a):(b))
809
*rbuflen = min( reqcount, *rbuflen );
810
err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
815
/* dsi can stream requests. we can only do this if we're not checking
816
* for an end-of-line character. oh well. */
817
if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
818
DSI *dsi = obj->handle;
820
if (obj->options.flags & OPTION_DEBUG) {
821
printf( "(read) reply: %d/%d, %d\n", *rbuflen,
822
reqcount, dsi->clientID);
823
bprint(rbuf, *rbuflen);
825
/* subtract off the offset */
827
if (reqcount > size) {
834
/* dsi_readinit() returns size of next read buffer. by this point,
835
* we know that we're sending some data. if we fail, something
836
* horrible happened. */
837
if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
840
/* due to the nature of afp packets, we have to exit if we get
841
an error. we can't do this with translation on. */
842
#ifdef HAVE_SENDFILE_READ
843
if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
844
if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
845
dsi->datasize) < 0) {
849
LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
859
#endif /* HAVE_SENDFILE_READ */
861
/* fill up our buffer. */
862
while (*rbuflen > 0) {
863
cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
869
if (obj->options.flags & OPTION_DEBUG) {
870
printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
871
bprint(rbuf, *rbuflen);
874
/* dsi_read() also returns buffer size of next allocation */
875
cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
884
LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
886
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
891
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
899
int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
902
int ibuflen, *rbuflen;
910
memcpy(&vid, ibuf, sizeof(vid));
911
if (( vol = getvolbyvid( vid )) == NULL ) {
912
return( AFPERR_PARAM );
919
int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
922
int ibuflen, *rbuflen;
929
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
931
if (( ofork = of_find( ofrefnum )) == NULL ) {
932
LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d)", ofrefnum);
933
return( AFPERR_PARAM );
936
if ( flushfork( ofork ) < 0 ) {
937
LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
943
/* this is very similar to closefork */
944
int flushfork( ofork )
948
int len, err = 0, doflush = 0;
950
if ( ad_dfileno( ofork->of_ad ) != -1 &&
951
fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
952
LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
953
ad_dfileno(ofork->of_ad), strerror(errno) );
957
if ( ad_hfileno( ofork->of_ad ) != -1 ) {
959
/* read in the rfork length */
960
len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
961
ad_refresh(ofork->of_ad);
963
/* set the date if we're dirty */
964
if ((ofork->of_flags & AFPFORK_DIRTY) &&
965
(gettimeofday(&tv, NULL) == 0)) {
966
ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
967
ofork->of_flags &= ~AFPFORK_DIRTY;
971
/* if we're actually flushing this fork, make sure to set the
972
* length. otherwise, just use the stored length */
973
if ((ofork->of_flags & AFPFORK_RSRC) &&
974
(len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
975
ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
980
/* flush the header (if it is a resource fork) */
981
if (ofork->of_flags & AFPFORK_RSRC)
982
if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
985
if (fsync( ad_hfileno( ofork->of_ad )) < 0)
989
LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
990
ad_hfileno(ofork->of_ad), strerror(errno) );
996
int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
999
int ibuflen, *rbuflen;
1001
struct ofork *ofork;
1003
int adflags, aint, doflush = 0;
1008
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1010
if (( ofork = of_find( ofrefnum )) == NULL ) {
1011
LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1012
return( AFPERR_PARAM );
1016
if ((ofork->of_flags & AFPFORK_DATA) &&
1017
(ad_dfileno( ofork->of_ad ) != -1)) {
1018
adflags |= ADFLAGS_DF;
1021
if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1022
adflags |= ADFLAGS_HF;
1024
aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1025
ad_refresh( ofork->of_ad );
1026
if ((ofork->of_flags & AFPFORK_DIRTY) &&
1027
(gettimeofday(&tv, NULL) == 0)) {
1028
ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1034
* Only set the rfork's length if we're closing the rfork.
1036
if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1037
ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1038
ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1042
ad_flush( ofork->of_ad, adflags );
1046
if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1047
LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1048
return( AFPERR_PARAM );
1051
of_dealloc( ofork );
1056
static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1057
off_t offset, char *rbuf,
1058
size_t rbuflen, const int xlate)
1064
* If this file is of type TEXT, swap \015 to \012.
1067
for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1068
if ( *p == '\015' ) {
1070
} else if ( *p == '\012' ) {
1076
if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1077
rbuf, rbuflen)) < 0 ) {
1082
return( AFPERR_DFULL );
1084
LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1085
return( AFPERR_PARAM );
1092
/* FPWrite. NOTE: on an error, we always use afp_write_err as
1093
* the client may have sent us a bunch of data that's not reflected
1094
* in reqcount et al. */
1095
int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1098
int ibuflen, *rbuflen;
1100
struct ofork *ofork;
1101
int32_t offset, saveoff, reqcount;
1102
int endflag, eid, xlate = 0, err = AFP_OK;
1106
/* figure out parameters */
1108
endflag = ENDBIT(*ibuf);
1110
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1111
ibuf += sizeof( ofrefnum );
1112
memcpy(&offset, ibuf, sizeof( offset ));
1113
offset = ntohl( offset );
1114
ibuf += sizeof( offset );
1115
memcpy(&reqcount, ibuf, sizeof( reqcount ));
1116
reqcount = ntohl( reqcount );
1117
ibuf += sizeof( reqcount );
1119
if (( ofork = of_find( ofrefnum )) == NULL ) {
1120
LOG(log_error, logtype_afpd, "afp_write: of_find");
1125
if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1126
err = AFPERR_ACCESS;
1131
writtenfork = ofork;
1134
if ( ofork->of_flags & AFPFORK_DATA) {
1136
xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1137
} else if (ofork->of_flags & AFPFORK_RSRC) {
1140
err = AFPERR_ACCESS; /* should never happen */
1145
offset += ad_size(ofork->of_ad, eid);
1147
/* handle bogus parameters */
1148
if (reqcount < 0 || offset < 0) {
1153
/* offset can overflow on 64-bit capable filesystems.
1154
* report disk full if that's going to happen. */
1155
if (offset + reqcount < 0) {
1160
if (!reqcount) { /* handle request counts of 0 */
1162
offset = htonl(offset);
1163
memcpy(rbuf, &offset, sizeof(offset));
1168
if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1174
/* this is yucky, but dsi can stream i/o and asp can't */
1175
switch (obj->proto) {
1178
if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1180
LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1181
return( AFPERR_PARAM );
1184
if (obj->options.flags & OPTION_DEBUG) {
1185
printf("(write) len: %d\n", *rbuflen);
1186
bprint(rbuf, *rbuflen);
1189
if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1192
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1197
#endif /* no afp/asp */
1201
DSI *dsi = obj->handle;
1203
/* find out what we have already and write it out. */
1204
cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1206
(cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1207
dsi_writeflush(dsi);
1209
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1214
#if 0 /*def HAVE_SENDFILE_WRITE*/
1215
if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1216
if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1217
offset, dsi->datasize)) < 0) {
1225
LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1226
goto afp_write_loop;
1228
dsi_writeflush(dsi);
1230
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1236
goto afp_write_done;
1238
#endif /* 0, was HAVE_SENDFILE_WRITE */
1240
/* loop until everything gets written. currently
1241
* dsi_write handles the end case by itself. */
1242
while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1243
if ( obj->options.flags & OPTION_DEBUG ) {
1244
printf("(write) command cont'd: %d\n", cc);
1248
if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1249
dsi_writeflush(dsi);
1251
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1261
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1262
if ( ad_hfileno( ofork->of_ad ) != -1 )
1263
ofork->of_flags |= AFPFORK_DIRTY;
1265
offset = htonl( offset );
1266
#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1267
bcopy(&offset, rbuf, sizeof(offset));
1268
#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1269
memcpy(rbuf, &offset, sizeof(offset));
1270
#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1271
*rbuflen = sizeof(offset);
1275
if (obj->proto == AFPPROTO_DSI) {
1276
dsi_writeinit(obj->handle, rbuf, *rbuflen);
1277
dsi_writeflush(obj->handle);
1280
*rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1285
int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1288
int ibuflen, *rbuflen;
1290
struct ofork *ofork;
1292
u_int16_t ofrefnum, bitmap;
1293
u_int16_t attrbits = 0;
1296
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1297
ibuf += sizeof( ofrefnum );
1298
memcpy(&bitmap, ibuf, sizeof( bitmap ));
1299
bitmap = ntohs( bitmap );
1300
ibuf += sizeof( bitmap );
1303
if (( ofork = of_find( ofrefnum )) == NULL ) {
1304
LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1305
return( AFPERR_PARAM );
1307
attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1308
attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1310
if (( ret = getforkparams( ofork, bitmap,
1311
rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
1315
*rbuflen = buflen + sizeof( u_short );
1316
bitmap = htons( bitmap );
1317
memcpy(rbuf, &bitmap, sizeof( bitmap ));