2 * $Id: fork.c,v 1.39 2002-10-13 06:18:14 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
51 #define BYTELOCK_MAXL 0x7FFFFFFFFFFFFFFFULL
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 /* can only get the length of the opened fork */
75 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
76 && (ofork->of_flags & AFPFORK_RSRC))
78 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
79 && (ofork->of_flags & AFPFORK_DATA))) {
80 return( AFPERR_BITMAP );
83 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
92 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
93 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
94 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
95 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
96 upath = mtoupath(vol, ofork->of_name);
97 if (movecwd(vol, dir) < 0)
98 return( AFPERR_NOOBJ );
99 if ( stat( upath, &st ) < 0 )
100 return( AFPERR_NOOBJ );
102 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
103 return( AFPERR_BITMAP );
107 return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
110 /* -------------------------
114 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
119 /* NOTE: we can't write lock a read-only file. on those, we just
120 * make sure that we have a read lock set. that way, we at least prevent
121 * someone else from really setting a deny read/write on the file.
123 lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
124 lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
126 return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
130 /* -------------------------
132 extern int ad_testlock(struct adouble *adp, int eid, int off);
134 static int getforkmode(struct adouble *adp, int eid, int what)
136 return ad_testlock(adp, eid, what);
139 /* --------------------------
140 a lot of races, some can be remove. but I try first to get the semantic right
142 #ifdef USE_FLOCK_LOCKS
143 #error sorry, for now configure --with-flock-locks is broken...
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;
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 (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
268 if (*s_path->m_name == '\0') {
270 return AFPERR_BADTYPE;
273 /* stat() data fork st is set because it's not a dir */
274 switch ( s_path->st_errno ) {
280 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
282 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
285 /* FIXME should we check first ? */
286 upath = s_path->u_name;
287 if (check_access(upath, access ) < 0) {
288 return AFPERR_ACCESS;
292 /* XXX: this probably isn't the best way to do this. the already
293 open bits should really be set if the fork is opened by any
294 program, not just this one. however, that's problematic to do
295 if we can't write lock files somewhere. opened is also passed to
296 ad_open so that we can keep file locks together.
297 FIXME: add the fork we are opening?
299 if ((opened = of_findname(s_path))) {
300 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
301 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
303 adsame = opened->of_ad;
306 if ( fork == OPENFORK_DATA ) {
308 adflags = ADFLAGS_DF|ADFLAGS_HF;
311 adflags = ADFLAGS_HF;
314 path = s_path->m_name;
315 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
316 adsame, st)) == NULL ) {
317 return( AFPERR_NFILE );
321 if (access & OPENACC_WR) {
322 /* try opening in read-write mode */
323 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
331 if (fork == OPENFORK_DATA) {
332 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
335 adflags = ADFLAGS_DF;
337 /* here's the deal. we only try to create the resource
338 * fork if the user wants to open it for write acess. */
339 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
349 ret = AFPERR_BADTYPE;
353 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
360 /* try opening in read-only mode */
362 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
367 /* check for a read-only data fork */
368 if ((adflags != ADFLAGS_HF) &&
369 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
372 adflags = ADFLAGS_DF;
375 /* see if client asked for the data fork */
376 if (fork == OPENFORK_DATA) {
377 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
380 adflags = ADFLAGS_DF;
389 ret = AFPERR_BADTYPE;
393 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
400 if ((adflags & ADFLAGS_HF) &&
401 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
402 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
403 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
404 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
405 ad_flush( ofork->of_ad, adflags );
408 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
409 &buflen, attrbits )) != AFP_OK ) {
410 ad_close( ofork->of_ad, adflags );
414 *rbuflen = buflen + 2 * sizeof( u_int16_t );
415 bitmap = htons( bitmap );
416 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
417 rbuf += sizeof( u_int16_t );
419 /* check WriteInhibit bit, the test is done here, after some Mac trafic capture */
420 ad_getattr(ofork->of_ad, &bshort);
421 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
422 ad_close( ofork->of_ad, adflags );
425 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
426 return(AFPERR_OLOCK);
430 * synchronization locks:
433 /* don't try to lock non-existent rforks. */
434 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
436 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
437 /* can we access the fork? */
440 ad_close( ofork->of_ad, adflags );
443 case EAGAIN: /* return data anyway */
447 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
448 return( AFPERR_DENYCONF );
452 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
453 return( AFPERR_PARAM );
456 if ((access & OPENACC_WR))
457 ofork->of_flags |= AFPFORK_ACCWR;
458 if ((access & OPENACC_RD))
459 ofork->of_flags |= AFPFORK_ACCRD;
462 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
468 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
472 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
475 int ibuflen, *rbuflen;
479 u_int16_t ofrefnum, bitmap;
483 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
484 ibuf += sizeof( ofrefnum );
485 memcpy(&bitmap, ibuf, sizeof(bitmap));
486 bitmap = ntohs(bitmap);
487 ibuf += sizeof( bitmap );
488 memcpy(&size, ibuf, sizeof( size ));
489 size = ntohl( size );
492 if (( ofork = of_find( ofrefnum )) == NULL ) {
493 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
494 return( AFPERR_PARAM );
497 if (ofork->of_vol->v_flags & AFPVOL_RO)
500 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
501 return AFPERR_ACCESS;
506 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
507 err = ad_dtruncate( ofork->of_ad, size );
509 goto afp_setfork_err;
510 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
511 (ofork->of_flags & AFPFORK_RSRC)) {
512 ad_refresh( ofork->of_ad );
513 err = ad_rtruncate(ofork->of_ad, size);
515 goto afp_setfork_err;
517 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
518 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
520 return( AFPERR_PARAM );
523 return AFPERR_BITMAP;
526 if ( flushfork( ofork ) < 0 ) {
527 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
542 return AFPERR_ACCESS;
553 /* for this to work correctly, we need to check for locks before each
554 * read and write. that's most easily handled by always doing an
555 * appropriate check before each ad_read/ad_write. other things
556 * that can change files like truncate are handled internally to those
559 #define ENDBIT(a) ((a) & 0x80)
560 #define UNLOCKBIT(a) ((a) & 0x01)
562 static off_t get_off_t(ibuf, is64)
569 memcpy(&temp, *ibuf, sizeof( temp ));
570 ret = ntohl(temp); /* ntohl is unsigned */
571 *ibuf += sizeof(temp);
574 memcpy(&temp, *ibuf, sizeof( temp ));
575 *ibuf += sizeof(temp);
576 ret = ntohl(temp)| (ret << 32);
581 /* ---------------------- */
582 static int set_off_t(offset, rbuf, is64)
592 temp = htonl(offset >> 32);
593 memcpy(rbuf, &temp, sizeof( temp ));
594 rbuf += sizeof(temp);
595 ret = sizeof( temp );
596 offset &= 0xffffffff;
598 temp = htonl(offset);
599 memcpy(rbuf, &temp, sizeof( temp ));
600 ret += sizeof( temp );
605 /* ---------------------- */
606 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
609 int ibuflen, *rbuflen;
613 off_t offset, length;
620 /* figure out parameters */
622 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
624 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
625 ibuf += sizeof(ofrefnum);
627 if (( ofork = of_find( ofrefnum )) == NULL ) {
628 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
629 return( AFPERR_PARAM );
632 if ( ofork->of_flags & AFPFORK_DATA) {
634 } else if (ofork->of_flags & AFPFORK_RSRC) {
639 offset = get_off_t(&ibuf, is64);
640 length = get_off_t(&ibuf, is64);
644 length = BYTELOCK_MAXL;
645 else if (length <= 0) {
647 } else if ((length >= AD_FILELOCK_BASE) &&
648 (ad_hfileno(ofork->of_ad) == -1)) {
653 if (length == 0xFFFFFFFF)
654 length = BYTELOCK_MAX;
655 else if (!length || (length & (1 << 31))) {
657 } else if ((length >= AD_FILELOCK_BASE) &&
658 (ad_hfileno(ofork->of_ad) == -1)) {
664 offset += ad_size(ofork->of_ad, eid);
666 if (offset < 0) /* error if we have a negative offset */
669 /* if the file is a read-only file, we use read locks instead of
670 * write locks. that way, we can prevent anyone from initiating
672 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
673 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
674 ADLOCK_WR : ADLOCK_RD), offset, length,
675 ofork->of_refnum) < 0) {
679 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
685 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
693 *rbuflen = set_off_t (offset, rbuf, is64);
697 /* --------------------------- */
698 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
701 int ibuflen, *rbuflen;
703 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
706 /* --------------------------- */
707 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
710 int ibuflen, *rbuflen;
712 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
717 /* --------------------------- */
718 static __inline__ int crlf( of )
723 if ( ad_hfileno( of->of_ad ) == -1 ||
724 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
726 if (( em = getextmap( of->of_name )) == NULL ||
727 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
733 if ( memcmp( ufinderi,
734 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
743 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
744 int offset, u_char nlmask,
745 u_char nlchar, char *rbuf,
746 int *rbuflen, const int xlate)
752 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
754 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
756 return( AFPERR_PARAM );
758 if ( cc < *rbuflen ) {
766 for ( p = rbuf, q = p + cc; p < q; ) {
767 if (( *p++ & nlmask ) == nlchar ) {
778 * If this file is of type TEXT, then swap \012 to \015.
781 for ( p = rbuf, q = p + cc; p < q; p++ ) {
782 if ( *p == '\012' ) {
784 } else if ( *p == '\015' ) {
793 return( AFPERR_EOF );
798 /* -----------------------------
799 * with ddp, afp_read can return fewer bytes than in reqcount
800 * so return EOF only if read actually past end of file not
801 * if offset +reqcount > size of file
803 * getfork size ==> 10430
804 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
805 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
806 * read fork offset 9248 size 1508 ==> 1182 (EOF)
807 * 10752 is a bug in Mac 7.5.x finder
809 * with dsi, should we check that reqcount < server quantum?
811 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
814 int ibuflen, *rbuflen;
819 off_t offset, saveoff, reqcount, savereqcount;
820 int cc, err, eid, xlate = 0;
822 u_char nlmask, nlchar;
825 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
826 ibuf += sizeof( u_short );
828 if (( ofork = of_find( ofrefnum )) == NULL ) {
829 LOG(log_error, logtype_afpd, "afp_read: of_find");
834 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
838 offset = get_off_t(&ibuf, is64);
839 reqcount = get_off_t(&ibuf, is64);
848 /* if we wanted to be picky, we could add in the following
849 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
851 if (reqcount < 0 || offset < 0) {
856 if ( ofork->of_flags & AFPFORK_DATA) {
858 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
859 } else if (ofork->of_flags & AFPFORK_RSRC) {
861 } else { /* fork wasn't opened. this should never really happen. */
866 /* zero request count */
872 /* reqcount isn't always truthful. we need to deal with that. */
873 size = ad_size(ofork->of_ad, eid);
875 if (offset >= size) {
880 savereqcount = reqcount;
882 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
887 #define min(a,b) ((a)<(b)?(a):(b))
888 *rbuflen = min( reqcount, *rbuflen );
889 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
894 /* dsi can stream requests. we can only do this if we're not checking
895 * for an end-of-line character. oh well. */
896 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
897 DSI *dsi = obj->handle;
899 if (obj->options.flags & OPTION_DEBUG) {
900 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
901 (int) reqcount, dsi->clientID);
902 bprint(rbuf, *rbuflen);
904 /* subtract off the offset */
906 if (reqcount > size) {
913 /* dsi_readinit() returns size of next read buffer. by this point,
914 * we know that we're sending some data. if we fail, something
915 * horrible happened. */
916 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
919 /* due to the nature of afp packets, we have to exit if we get
920 an error. we can't do this with translation on. */
921 #ifdef HAVE_SENDFILE_READ
922 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
923 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
924 dsi->datasize) < 0) {
928 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
938 #endif /* HAVE_SENDFILE_READ */
940 /* fill up our buffer. */
941 while (*rbuflen > 0) {
942 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
948 if (obj->options.flags & OPTION_DEBUG) {
949 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
950 bprint(rbuf, *rbuflen);
953 /* dsi_read() also returns buffer size of next allocation */
954 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
963 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
965 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
970 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
978 /* ---------------------- */
979 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
982 int ibuflen, *rbuflen;
984 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
987 /* ---------------------- */
988 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
991 int ibuflen, *rbuflen;
993 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
996 /* ---------------------- */
997 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1000 int ibuflen, *rbuflen;
1008 memcpy(&vid, ibuf, sizeof(vid));
1009 if (( vol = getvolbyvid( vid )) == NULL ) {
1010 return( AFPERR_PARAM );
1017 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1020 int ibuflen, *rbuflen;
1022 struct ofork *ofork;
1027 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1029 if (( ofork = of_find( ofrefnum )) == NULL ) {
1030 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1031 return( AFPERR_PARAM );
1034 if ( flushfork( ofork ) < 0 ) {
1035 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1041 /* this is very similar to closefork */
1042 int flushfork( ofork )
1043 struct ofork *ofork;
1047 int err = 0, doflush = 0;
1049 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1050 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1051 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1052 ad_dfileno(ofork->of_ad), strerror(errno) );
1056 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1057 (ofork->of_flags & AFPFORK_RSRC)) {
1059 /* read in the rfork length */
1060 ad_refresh(ofork->of_ad);
1062 /* set the date if we're dirty */
1063 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1064 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1065 ofork->of_flags &= ~AFPFORK_DIRTY;
1069 /* flush the header */
1070 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1073 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1077 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1078 ad_hfileno(ofork->of_ad), strerror(errno) );
1084 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1087 int ibuflen, *rbuflen;
1089 struct ofork *ofork;
1091 int adflags, doflush = 0;
1096 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1098 if (( ofork = of_find( ofrefnum )) == NULL ) {
1099 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1100 return( AFPERR_PARAM );
1104 if ((ofork->of_flags & AFPFORK_DATA) &&
1105 (ad_dfileno( ofork->of_ad ) != -1)) {
1106 adflags |= ADFLAGS_DF;
1109 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1110 adflags |= ADFLAGS_HF;
1112 * Only set the rfork's length if we're closing the rfork.
1114 if ((ofork->of_flags & AFPFORK_RSRC)) {
1115 ad_refresh( ofork->of_ad );
1116 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1117 !gettimeofday(&tv, NULL)) {
1118 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1122 ad_flush( ofork->of_ad, adflags );
1127 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1128 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1129 return( AFPERR_PARAM );
1132 of_dealloc( ofork );
1137 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1138 off_t offset, char *rbuf,
1139 size_t rbuflen, const int xlate)
1145 * If this file is of type TEXT, swap \015 to \012.
1148 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1149 if ( *p == '\015' ) {
1151 } else if ( *p == '\012' ) {
1157 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1158 rbuf, rbuflen)) < 0 ) {
1163 return( AFPERR_DFULL );
1165 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1166 return( AFPERR_PARAM );
1173 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1174 * the client may have sent us a bunch of data that's not reflected
1175 * in reqcount et al. */
1176 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1179 int ibuflen, *rbuflen;
1182 struct ofork *ofork;
1183 off_t offset, saveoff, reqcount;
1184 int endflag, eid, xlate = 0, err = AFP_OK;
1188 /* figure out parameters */
1190 endflag = ENDBIT(*ibuf);
1192 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1193 ibuf += sizeof( ofrefnum );
1195 offset = get_off_t(&ibuf, is64);
1196 reqcount = get_off_t(&ibuf, is64);
1198 if (( ofork = of_find( ofrefnum )) == NULL ) {
1199 LOG(log_error, logtype_afpd, "afp_write: of_find");
1204 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1205 err = AFPERR_ACCESS;
1210 writtenfork = ofork;
1213 if ( ofork->of_flags & AFPFORK_DATA) {
1215 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1216 } else if (ofork->of_flags & AFPFORK_RSRC) {
1219 err = AFPERR_ACCESS; /* should never happen */
1224 offset += ad_size(ofork->of_ad, eid);
1226 /* handle bogus parameters */
1227 if (reqcount < 0 || offset < 0) {
1232 /* offset can overflow on 64-bit capable filesystems.
1233 * report disk full if that's going to happen. */
1234 if (offset + reqcount < 0) {
1239 if (!reqcount) { /* handle request counts of 0 */
1241 *rbuflen = set_off_t (offset, rbuf, is64);
1246 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1252 /* this is yucky, but dsi can stream i/o and asp can't */
1253 switch (obj->proto) {
1256 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1258 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1259 return( AFPERR_PARAM );
1262 if (obj->options.flags & OPTION_DEBUG) {
1263 printf("(write) len: %d\n", *rbuflen);
1264 bprint(rbuf, *rbuflen);
1267 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1270 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1275 #endif /* no afp/asp */
1279 DSI *dsi = obj->handle;
1281 /* find out what we have already and write it out. */
1282 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1284 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1285 dsi_writeflush(dsi);
1287 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1292 #if 0 /*def HAVE_SENDFILE_WRITE*/
1293 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1294 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1295 offset, dsi->datasize)) < 0) {
1303 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1304 goto afp_write_loop;
1306 dsi_writeflush(dsi);
1308 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1314 goto afp_write_done;
1316 #endif /* 0, was HAVE_SENDFILE_WRITE */
1318 /* loop until everything gets written. currently
1319 * dsi_write handles the end case by itself. */
1320 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1321 if ( obj->options.flags & OPTION_DEBUG ) {
1322 printf("(write) command cont'd: %d\n", cc);
1326 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1327 dsi_writeflush(dsi);
1329 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1339 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1340 if ( ad_hfileno( ofork->of_ad ) != -1 )
1341 ofork->of_flags |= AFPFORK_DIRTY;
1343 *rbuflen = set_off_t (offset, rbuf, is64);
1347 if (obj->proto == AFPPROTO_DSI) {
1348 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1349 dsi_writeflush(obj->handle);
1352 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1356 /* ---------------------------- */
1357 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1360 int ibuflen, *rbuflen;
1362 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1365 /* ----------------------------
1366 * FIXME need to deal with SIGXFSZ signal
1368 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1371 int ibuflen, *rbuflen;
1373 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1376 /* ---------------------------- */
1377 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1380 int ibuflen, *rbuflen;
1382 struct ofork *ofork;
1384 u_int16_t ofrefnum, bitmap;
1385 u_int16_t attrbits = 0;
1388 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1389 ibuf += sizeof( ofrefnum );
1390 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1391 bitmap = ntohs( bitmap );
1392 ibuf += sizeof( bitmap );
1395 if (( ofork = of_find( ofrefnum )) == NULL ) {
1396 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1397 return( AFPERR_PARAM );
1399 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1400 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1402 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1403 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1404 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1405 return( AFPERR_PARAM );
1409 if (( ret = getforkparams( ofork, bitmap,
1410 rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
1414 *rbuflen = buflen + sizeof( u_short );
1415 bitmap = htons( bitmap );
1416 memcpy(rbuf, &bitmap, sizeof( bitmap ));