2 * $Id: fork.c,v 1.41 2003-01-08 15:01:35 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 static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
148 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
149 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
152 if ((access & (OPENACC_RD | OPENACC_DRD))) {
153 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
155 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
158 if ((access & OPENACC_RD) && denyreadset) {
162 if ((access & OPENACC_DRD) && readset) {
166 /* boolean logic is not enough, because getforkmode is not always telling the
169 mode = ((access & OPENACC_DRD))?EXCL: SHARE;
170 if ((access & OPENACC_RD)) {
171 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
175 if ((access & OPENACC_DRD)) {
176 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
181 /* ------------same for writing -------------- */
182 if ((access & (OPENACC_WR | OPENACC_DWR))) {
183 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
185 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
188 if ((access & OPENACC_WR) && denywriteset) {
192 if ((access & OPENACC_DWR) && writeset) {
196 mode = ((access & OPENACC_DWR))?EXCL: SHARE;
197 if ((access & OPENACC_WR)) {
198 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
202 if ((access & OPENACC_DWR)) {
203 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
211 /* ----------------------- */
212 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
215 int ibuflen, *rbuflen;
219 struct ofork *ofork, *opened;
220 struct adouble *adsame = NULL;
221 int buflen, ret, adflags, eid, lockop;
223 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
224 char fork, *path, *upath;
231 memcpy(&vid, ibuf, sizeof( vid ));
235 if (( vol = getvolbyvid( vid )) == NULL ) {
236 return( AFPERR_PARAM );
239 memcpy(&did, ibuf, sizeof( did ));
240 ibuf += sizeof( int );
242 if (( dir = dirlookup( vol, did )) == NULL ) {
246 memcpy(&bitmap, ibuf, sizeof( bitmap ));
247 bitmap = ntohs( bitmap );
248 ibuf += sizeof( bitmap );
249 memcpy(&access, ibuf, sizeof( access ));
250 access = ntohs( access );
251 ibuf += sizeof( access );
253 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
257 if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
261 if (*s_path->m_name == '\0') {
263 return AFPERR_BADTYPE;
266 /* stat() data fork st is set because it's not a dir */
267 switch ( s_path->st_errno ) {
273 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
275 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
278 /* FIXME should we check first ? */
279 upath = s_path->u_name;
280 if (check_access(upath, access ) < 0) {
281 return AFPERR_ACCESS;
285 /* XXX: this probably isn't the best way to do this. the already
286 open bits should really be set if the fork is opened by any
287 program, not just this one. however, that's problematic to do
288 if we can't write lock files somewhere. opened is also passed to
289 ad_open so that we can keep file locks together.
290 FIXME: add the fork we are opening?
292 if ((opened = of_findname(s_path))) {
293 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
294 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
296 adsame = opened->of_ad;
299 if ( fork == OPENFORK_DATA ) {
301 adflags = ADFLAGS_DF|ADFLAGS_HF;
304 adflags = ADFLAGS_HF;
307 path = s_path->m_name;
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)
555 static off_t get_off_t(ibuf, is64)
562 memcpy(&temp, *ibuf, sizeof( temp ));
563 ret = ntohl(temp); /* ntohl is unsigned */
564 *ibuf += sizeof(temp);
567 memcpy(&temp, *ibuf, sizeof( temp ));
568 *ibuf += sizeof(temp);
569 ret = ntohl(temp)| (ret << 32);
574 /* ---------------------- */
575 static int set_off_t(offset, rbuf, is64)
585 temp = htonl(offset >> 32);
586 memcpy(rbuf, &temp, sizeof( temp ));
587 rbuf += sizeof(temp);
588 ret = sizeof( temp );
589 offset &= 0xffffffff;
591 temp = htonl(offset);
592 memcpy(rbuf, &temp, sizeof( temp ));
593 ret += sizeof( temp );
598 /* ---------------------- */
599 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
602 int ibuflen, *rbuflen;
606 off_t offset, length;
613 /* figure out parameters */
615 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
617 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
618 ibuf += sizeof(ofrefnum);
620 if (( ofork = of_find( ofrefnum )) == NULL ) {
621 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
622 return( AFPERR_PARAM );
625 if ( ofork->of_flags & AFPFORK_DATA) {
627 } else if (ofork->of_flags & AFPFORK_RSRC) {
632 offset = get_off_t(&ibuf, is64);
633 length = get_off_t(&ibuf, is64);
637 length = BYTELOCK_MAXL;
638 else if (length <= 0) {
640 } else if ((length >= AD_FILELOCK_BASE) &&
641 (ad_hfileno(ofork->of_ad) == -1)) {
646 if (length == 0xFFFFFFFF)
647 length = BYTELOCK_MAX;
648 else if (!length || (length & (1 << 31))) {
650 } else if ((length >= AD_FILELOCK_BASE) &&
651 (ad_hfileno(ofork->of_ad) == -1)) {
657 offset += ad_size(ofork->of_ad, eid);
659 if (offset < 0) /* error if we have a negative offset */
662 /* if the file is a read-only file, we use read locks instead of
663 * write locks. that way, we can prevent anyone from initiating
665 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
666 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
667 ADLOCK_WR : ADLOCK_RD), offset, length,
668 ofork->of_refnum) < 0) {
672 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
678 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
686 *rbuflen = set_off_t (offset, rbuf, is64);
690 /* --------------------------- */
691 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
694 int ibuflen, *rbuflen;
696 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
699 /* --------------------------- */
700 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
703 int ibuflen, *rbuflen;
705 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
710 /* --------------------------- */
711 static __inline__ int crlf( of )
716 if ( ad_hfileno( of->of_ad ) == -1 ||
717 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
719 if (( em = getextmap( of->of_name )) == NULL ||
720 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
726 if ( memcmp( ufinderi,
727 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
736 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
737 int offset, u_char nlmask,
738 u_char nlchar, char *rbuf,
739 int *rbuflen, const int xlate)
745 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
747 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
749 return( AFPERR_PARAM );
751 if ( cc < *rbuflen ) {
759 for ( p = rbuf, q = p + cc; p < q; ) {
760 if (( *p++ & nlmask ) == nlchar ) {
771 * If this file is of type TEXT, then swap \012 to \015.
774 for ( p = rbuf, q = p + cc; p < q; p++ ) {
775 if ( *p == '\012' ) {
777 } else if ( *p == '\015' ) {
786 return( AFPERR_EOF );
791 /* -----------------------------
792 * with ddp, afp_read can return fewer bytes than in reqcount
793 * so return EOF only if read actually past end of file not
794 * if offset +reqcount > size of file
796 * getfork size ==> 10430
797 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
798 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
799 * read fork offset 9248 size 1508 ==> 1182 (EOF)
800 * 10752 is a bug in Mac 7.5.x finder
802 * with dsi, should we check that reqcount < server quantum?
804 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
807 int ibuflen, *rbuflen;
812 off_t offset, saveoff, reqcount, savereqcount;
813 int cc, err, eid, xlate = 0;
815 u_char nlmask, nlchar;
818 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
819 ibuf += sizeof( u_short );
821 if (( ofork = of_find( ofrefnum )) == NULL ) {
822 LOG(log_error, logtype_afpd, "afp_read: of_find");
827 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
831 offset = get_off_t(&ibuf, is64);
832 reqcount = get_off_t(&ibuf, is64);
841 /* if we wanted to be picky, we could add in the following
842 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
844 if (reqcount < 0 || offset < 0) {
849 if ( ofork->of_flags & AFPFORK_DATA) {
851 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
852 } else if (ofork->of_flags & AFPFORK_RSRC) {
854 } else { /* fork wasn't opened. this should never really happen. */
859 /* zero request count */
865 /* reqcount isn't always truthful. we need to deal with that. */
866 size = ad_size(ofork->of_ad, eid);
868 if (offset >= size) {
873 savereqcount = reqcount;
875 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
880 #define min(a,b) ((a)<(b)?(a):(b))
881 *rbuflen = min( reqcount, *rbuflen );
882 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
887 /* dsi can stream requests. we can only do this if we're not checking
888 * for an end-of-line character. oh well. */
889 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
890 DSI *dsi = obj->handle;
892 if (obj->options.flags & OPTION_DEBUG) {
893 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
894 (int) reqcount, dsi->clientID);
895 bprint(rbuf, *rbuflen);
897 /* subtract off the offset */
899 if (reqcount > size) {
906 /* dsi_readinit() returns size of next read buffer. by this point,
907 * we know that we're sending some data. if we fail, something
908 * horrible happened. */
909 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
912 /* due to the nature of afp packets, we have to exit if we get
913 an error. we can't do this with translation on. */
914 #ifdef HAVE_SENDFILE_READ
915 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
916 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
917 dsi->datasize) < 0) {
921 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
931 #endif /* HAVE_SENDFILE_READ */
933 /* fill up our buffer. */
934 while (*rbuflen > 0) {
935 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
941 if (obj->options.flags & OPTION_DEBUG) {
942 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
943 bprint(rbuf, *rbuflen);
946 /* dsi_read() also returns buffer size of next allocation */
947 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
956 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
958 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
963 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
971 /* ---------------------- */
972 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
975 int ibuflen, *rbuflen;
977 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
980 /* ---------------------- */
981 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
984 int ibuflen, *rbuflen;
986 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
989 /* ---------------------- */
990 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
993 int ibuflen, *rbuflen;
1001 memcpy(&vid, ibuf, sizeof(vid));
1002 if (( vol = getvolbyvid( vid )) == NULL ) {
1003 return( AFPERR_PARAM );
1010 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1013 int ibuflen, *rbuflen;
1015 struct ofork *ofork;
1020 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1022 if (( ofork = of_find( ofrefnum )) == NULL ) {
1023 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1024 return( AFPERR_PARAM );
1027 if ( flushfork( ofork ) < 0 ) {
1028 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1034 /* this is very similar to closefork */
1035 int flushfork( ofork )
1036 struct ofork *ofork;
1040 int err = 0, doflush = 0;
1042 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1043 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1044 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1045 ad_dfileno(ofork->of_ad), strerror(errno) );
1049 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1050 (ofork->of_flags & AFPFORK_RSRC)) {
1052 /* read in the rfork length */
1053 ad_refresh(ofork->of_ad);
1055 /* set the date if we're dirty */
1056 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1057 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1058 ofork->of_flags &= ~AFPFORK_DIRTY;
1062 /* flush the header */
1063 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1066 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1070 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1071 ad_hfileno(ofork->of_ad), strerror(errno) );
1077 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1080 int ibuflen, *rbuflen;
1082 struct ofork *ofork;
1084 int adflags, doflush = 0;
1089 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1091 if (( ofork = of_find( ofrefnum )) == NULL ) {
1092 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1093 return( AFPERR_PARAM );
1097 if ((ofork->of_flags & AFPFORK_DATA) &&
1098 (ad_dfileno( ofork->of_ad ) != -1)) {
1099 adflags |= ADFLAGS_DF;
1102 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1103 adflags |= ADFLAGS_HF;
1105 * Only set the rfork's length if we're closing the rfork.
1107 if ((ofork->of_flags & AFPFORK_RSRC)) {
1108 ad_refresh( ofork->of_ad );
1109 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1110 !gettimeofday(&tv, NULL)) {
1111 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1115 ad_flush( ofork->of_ad, adflags );
1120 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1121 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1122 return( AFPERR_PARAM );
1125 of_dealloc( ofork );
1130 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1131 off_t offset, char *rbuf,
1132 size_t rbuflen, const int xlate)
1138 * If this file is of type TEXT, swap \015 to \012.
1141 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1142 if ( *p == '\015' ) {
1144 } else if ( *p == '\012' ) {
1150 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1151 rbuf, rbuflen)) < 0 ) {
1156 return( AFPERR_DFULL );
1158 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1159 return( AFPERR_PARAM );
1166 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1167 * the client may have sent us a bunch of data that's not reflected
1168 * in reqcount et al. */
1169 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1172 int ibuflen, *rbuflen;
1175 struct ofork *ofork;
1176 off_t offset, saveoff, reqcount;
1177 int endflag, eid, xlate = 0, err = AFP_OK;
1181 /* figure out parameters */
1183 endflag = ENDBIT(*ibuf);
1185 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1186 ibuf += sizeof( ofrefnum );
1188 offset = get_off_t(&ibuf, is64);
1189 reqcount = get_off_t(&ibuf, is64);
1191 if (( ofork = of_find( ofrefnum )) == NULL ) {
1192 LOG(log_error, logtype_afpd, "afp_write: of_find");
1197 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1198 err = AFPERR_ACCESS;
1203 writtenfork = ofork;
1206 if ( ofork->of_flags & AFPFORK_DATA) {
1208 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1209 } else if (ofork->of_flags & AFPFORK_RSRC) {
1212 err = AFPERR_ACCESS; /* should never happen */
1217 offset += ad_size(ofork->of_ad, eid);
1219 /* handle bogus parameters */
1220 if (reqcount < 0 || offset < 0) {
1225 /* offset can overflow on 64-bit capable filesystems.
1226 * report disk full if that's going to happen. */
1227 if (offset + reqcount < 0) {
1232 if (!reqcount) { /* handle request counts of 0 */
1234 *rbuflen = set_off_t (offset, rbuf, is64);
1239 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1245 /* this is yucky, but dsi can stream i/o and asp can't */
1246 switch (obj->proto) {
1249 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1251 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1252 return( AFPERR_PARAM );
1255 if (obj->options.flags & OPTION_DEBUG) {
1256 printf("(write) len: %d\n", *rbuflen);
1257 bprint(rbuf, *rbuflen);
1260 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1263 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1268 #endif /* no afp/asp */
1272 DSI *dsi = obj->handle;
1274 /* find out what we have already and write it out. */
1275 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1277 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1278 dsi_writeflush(dsi);
1280 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1285 #if 0 /*def HAVE_SENDFILE_WRITE*/
1286 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1287 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1288 offset, dsi->datasize)) < 0) {
1296 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1297 goto afp_write_loop;
1299 dsi_writeflush(dsi);
1301 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1307 goto afp_write_done;
1309 #endif /* 0, was HAVE_SENDFILE_WRITE */
1311 /* loop until everything gets written. currently
1312 * dsi_write handles the end case by itself. */
1313 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1314 if ( obj->options.flags & OPTION_DEBUG ) {
1315 printf("(write) command cont'd: %d\n", cc);
1319 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1320 dsi_writeflush(dsi);
1322 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1332 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1333 if ( ad_hfileno( ofork->of_ad ) != -1 )
1334 ofork->of_flags |= AFPFORK_DIRTY;
1336 *rbuflen = set_off_t (offset, rbuf, is64);
1340 if (obj->proto == AFPPROTO_DSI) {
1341 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1342 dsi_writeflush(obj->handle);
1345 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1349 /* ---------------------------- */
1350 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1353 int ibuflen, *rbuflen;
1355 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1358 /* ----------------------------
1359 * FIXME need to deal with SIGXFSZ signal
1361 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1364 int ibuflen, *rbuflen;
1366 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1369 /* ---------------------------- */
1370 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1373 int ibuflen, *rbuflen;
1375 struct ofork *ofork;
1377 u_int16_t ofrefnum, bitmap;
1378 u_int16_t attrbits = 0;
1381 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1382 ibuf += sizeof( ofrefnum );
1383 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1384 bitmap = ntohs( bitmap );
1385 ibuf += sizeof( bitmap );
1388 if (( ofork = of_find( ofrefnum )) == NULL ) {
1389 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1390 return( AFPERR_PARAM );
1392 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1393 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1395 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1396 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1397 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1398 return( AFPERR_PARAM );
1402 if (( ret = getforkparams( ofork, bitmap,
1403 rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
1407 *rbuflen = buflen + sizeof( u_short );
1408 bitmap = htons( bitmap );
1409 memcpy(rbuf, &bitmap, sizeof( bitmap ));