2 * $Id: fork.c,v 1.70 2009-10-27 23:35:17 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
17 #include <atalk/adouble.h>
18 #include <atalk/logger.h>
20 #include <sys/param.h>
21 #include <sys/socket.h>
23 #include <netatalk/at.h>
25 #include <atalk/dsi.h>
26 #include <atalk/atp.h>
27 #include <atalk/asp.h>
28 #include <atalk/afp.h>
30 #include <atalk/util.h>
31 #include <atalk/cnid.h>
36 #include "directory.h"
41 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
47 struct ofork *writtenfork;
50 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
60 /* can only get the length of the opened fork */
61 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
62 && (ofork->of_flags & AFPFORK_RSRC))
64 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
65 && (ofork->of_flags & AFPFORK_DATA))) {
66 return( AFPERR_BITMAP );
69 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
78 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
79 return( AFPERR_MISC );
81 path.m_name = of_name(ofork);
83 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
84 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
85 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
86 if ( ad_data_fileno( ofork->of_ad ) == -1 ) {
87 if (movecwd(vol, dir) < 0)
88 return( AFPERR_NOOBJ );
89 if ( stat( path.u_name, st ) < 0 )
90 return( AFPERR_NOOBJ );
92 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
93 return( AFPERR_BITMAP );
97 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
100 /* ---------------------------- */
101 static off_t get_off_t(char **ibuf, int is64)
107 memcpy(&temp, *ibuf, sizeof( temp ));
108 ret = ntohl(temp); /* ntohl is unsigned */
109 *ibuf += sizeof(temp);
112 memcpy(&temp, *ibuf, sizeof( temp ));
113 *ibuf += sizeof(temp);
114 ret = ntohl(temp)| (ret << 32);
117 ret = (int)ret; /* sign extend */
122 /* ---------------------- */
123 static int set_off_t(off_t offset, char *rbuf, int is64)
130 temp = htonl(offset >> 32);
131 memcpy(rbuf, &temp, sizeof( temp ));
132 rbuf += sizeof(temp);
133 ret = sizeof( temp );
134 offset &= 0xffffffff;
136 temp = htonl(offset);
137 memcpy(rbuf, &temp, sizeof( temp ));
138 ret += sizeof( temp );
143 /* ------------------------
145 static int is_neg(int is64, off_t val)
147 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
152 static int sum_neg(int is64, off_t offset, off_t reqcount)
154 if (is_neg(is64, offset +reqcount) )
159 /* -------------------------
161 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
163 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
166 /* -------------------------
168 int getforkmode(struct adouble *adp, int eid, int what)
170 return ad_testlock(adp, eid, what);
173 /* -------------------------
175 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
183 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
184 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
187 if ((access & (OPENACC_RD | OPENACC_DRD))) {
188 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
190 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
193 if ((access & OPENACC_RD) && denyreadset) {
197 if ((access & OPENACC_DRD) && readset) {
201 /* boolean logic is not enough, because getforkmode is not always telling the
204 if ((access & OPENACC_RD)) {
205 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
209 if ((access & OPENACC_DRD)) {
210 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
215 /* ------------same for writing -------------- */
216 if ((access & (OPENACC_WR | OPENACC_DWR))) {
217 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
219 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
222 if ((access & OPENACC_WR) && denywriteset) {
226 if ((access & OPENACC_DWR) && writeset) {
230 if ((access & OPENACC_WR)) {
231 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
235 if ((access & OPENACC_DWR)) {
236 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
241 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
242 return ad_excl_lock(adp, eid);
247 /* ----------------------- */
248 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
252 struct ofork *ofork, *opened;
253 struct adouble *adsame = NULL;
255 int ret, adflags, eid;
257 u_int16_t vid, bitmap, access, ofrefnum;
258 char fork, *path, *upath;
265 memcpy(&vid, ibuf, sizeof( vid ));
269 if (NULL == ( vol = getvolbyvid( vid ))) {
270 return( AFPERR_PARAM );
273 memcpy(&did, ibuf, sizeof( did ));
274 ibuf += sizeof( int );
276 if (NULL == ( dir = dirlookup( vol, did ))) {
280 memcpy(&bitmap, ibuf, sizeof( bitmap ));
281 bitmap = ntohs( bitmap );
282 ibuf += sizeof( bitmap );
283 memcpy(&access, ibuf, sizeof( access ));
284 access = ntohs( access );
285 ibuf += sizeof( access );
287 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
291 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
292 return get_afp_errno(AFPERR_PARAM);
295 if (*s_path->m_name == '\0') {
297 return AFPERR_BADTYPE;
300 /* stat() data fork st is set because it's not a dir */
301 switch ( s_path->st_errno ) {
307 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
309 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
312 /* FIXME should we check it first ? */
313 upath = s_path->u_name;
314 if (!vol_unix_priv(vol)) {
315 if (check_access(upath, access ) < 0) {
316 return AFPERR_ACCESS;
320 if (file_access(s_path, access ) < 0) {
321 return AFPERR_ACCESS;
326 /* XXX: this probably isn't the best way to do this. the already
327 open bits should really be set if the fork is opened by any
328 program, not just this one. however, that's problematic to do
329 if we can't write lock files somewhere. opened is also passed to
330 ad_open so that we can keep file locks together.
331 FIXME: add the fork we are opening?
333 if ((opened = of_findname(s_path))) {
334 adsame = opened->of_ad;
337 if ( fork == OPENFORK_DATA ) {
339 adflags = ADFLAGS_DF|ADFLAGS_HF;
342 adflags = ADFLAGS_HF;
345 path = s_path->m_name;
346 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
347 adsame, st)) == NULL ) {
348 return( AFPERR_NFILE );
352 if (access & OPENACC_WR) {
353 /* try opening in read-write mode */
354 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
362 if (fork == OPENFORK_DATA) {
363 /* try to open only the data fork */
364 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
367 adflags = ADFLAGS_DF;
370 /* here's the deal. we only try to create the resource
371 * fork if the user wants to open it for write acess. */
372 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
374 ofork->of_flags |= AFPFORK_OPEN;
383 ret = AFPERR_BADTYPE;
387 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
394 /* the ressource fork is open too */
395 ofork->of_flags |= AFPFORK_OPEN;
398 /* try opening in read-only mode */
400 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
408 /* see if client asked for a read only data fork */
409 if (fork == OPENFORK_DATA) {
410 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
413 adflags = ADFLAGS_DF;
415 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
416 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
417 * then create in open read-write.
418 * FIXME , it doesn't play well with byte locking example:
419 * ressource fork open read only
420 * locking set on it (no effect, there's no file!)
421 * ressource fork open read write now
430 ret = AFPERR_BADTYPE;
434 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
440 /* the ressource fork is open too */
441 ofork->of_flags |= AFPFORK_OPEN;
445 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
446 if (ad_setname(ofork->of_ad, path)) {
447 ad_flush( ofork->of_ad );
451 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
452 &buflen )) != AFP_OK ) {
453 ad_close( ofork->of_ad, adflags );
457 *rbuflen = buflen + 2 * sizeof( u_int16_t );
458 bitmap = htons( bitmap );
459 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
460 rbuf += sizeof( u_int16_t );
462 /* check WriteInhibit bit if we have a ressource fork
463 * the test is done here, after some Mac trafic capture
465 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
466 ad_getattr(ofork->of_ad, &bshort);
467 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
468 ad_close( ofork->of_ad, adflags );
471 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
472 return(AFPERR_OLOCK);
477 * synchronization locks:
480 /* don't try to lock non-existent rforks. */
481 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
483 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
484 /* can we access the fork? */
487 ad_close( ofork->of_ad, adflags );
490 case EAGAIN: /* return data anyway */
494 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
495 return( AFPERR_DENYCONF );
499 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
500 return( AFPERR_PARAM );
503 if ((access & OPENACC_WR))
504 ofork->of_flags |= AFPFORK_ACCWR;
506 /* the file may be open read only without ressource fork */
507 if ((access & OPENACC_RD))
508 ofork->of_flags |= AFPFORK_ACCRD;
510 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
516 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
520 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
524 u_int16_t ofrefnum, bitmap;
532 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
533 ibuf += sizeof( ofrefnum );
535 memcpy(&bitmap, ibuf, sizeof(bitmap));
536 bitmap = ntohs(bitmap);
537 ibuf += sizeof( bitmap );
540 if (NULL == ( ofork = of_find( ofrefnum )) ) {
541 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
542 return( AFPERR_PARAM );
545 if (ofork->of_vol->v_flags & AFPVOL_RO)
548 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
549 return AFPERR_ACCESS;
551 if ( ofork->of_flags & AFPFORK_DATA) {
553 } else if (ofork->of_flags & AFPFORK_RSRC) {
558 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
559 && eid == ADEID_RFORK
561 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
562 && eid == ADEID_DFORK)) {
563 return AFPERR_BITMAP;
567 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
568 if (afp_version >= 30) {
572 return AFPERR_BITMAP;
575 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
576 return AFPERR_PARAM ;
578 size = get_off_t(&ibuf, is64);
581 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
584 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
585 st_size = ad_size(ofork->of_ad, eid);
587 if (st_size > size &&
588 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
589 goto afp_setfork_err;
591 err = ad_dtruncate( ofork->of_ad, size );
593 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
595 goto afp_setfork_err;
596 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
597 ad_refresh( ofork->of_ad );
599 st_size = ad_size(ofork->of_ad, eid);
601 if (st_size > size &&
602 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
603 goto afp_setfork_err;
605 err = ad_rtruncate(ofork->of_ad, size);
607 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
609 goto afp_setfork_err;
611 if (ad_flush( ofork->of_ad ) < 0) {
612 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
616 return AFPERR_BITMAP;
619 if ( flushfork( ofork ) < 0 ) {
620 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
635 return AFPERR_ACCESS;
646 /* for this to work correctly, we need to check for locks before each
647 * read and write. that's most easily handled by always doing an
648 * appropriate check before each ad_read/ad_write. other things
649 * that can change files like truncate are handled internally to those
652 #define ENDBIT(a) ((a) & 0x80)
653 #define UNLOCKBIT(a) ((a) & 0x01)
656 /* ---------------------- */
657 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
660 off_t offset, length;
668 /* figure out parameters */
670 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
672 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
673 ibuf += sizeof(ofrefnum);
675 if (NULL == ( ofork = of_find( ofrefnum )) ) {
676 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
677 return( AFPERR_PARAM );
680 if ( ofork->of_flags & AFPFORK_DATA) {
682 } else if (ofork->of_flags & AFPFORK_RSRC) {
687 offset = get_off_t(&ibuf, is64);
688 length = get_off_t(&ibuf, is64);
690 /* FIXME AD_FILELOCK test is surely wrong */
692 length = BYTELOCK_MAX;
693 else if (!length || is_neg(is64, length)) {
695 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
700 offset += ad_size(ofork->of_ad, eid);
701 /* FIXME what do we do if file size > 2 GB and
702 it's not byte_lock_ext?
705 if (offset < 0) /* error if we have a negative offset */
708 /* if the file is a read-only file, we use read locks instead of
709 * write locks. that way, we can prevent anyone from initiating
711 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
712 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
713 ofork->of_refnum) < 0) {
717 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
723 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
731 *rbuflen = set_off_t (offset, rbuf, is64);
735 /* --------------------------- */
736 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
738 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
741 /* --------------------------- */
742 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
744 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
749 /* --------------------------- */
750 static int crlf(struct ofork *of)
754 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
755 /* no resource fork or no finderinfo, use our files extension mapping */
756 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
759 /* file type is TEXT */
762 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
769 static ssize_t read_file(struct ofork *ofork, int eid,
770 off_t offset, u_char nlmask,
771 u_char nlchar, char *rbuf,
772 size_t *rbuflen, const int xlate)
778 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
780 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
782 return( AFPERR_PARAM );
784 if ( (size_t)cc < *rbuflen ) {
792 for ( p = rbuf, q = p + cc; p < q; ) {
793 if (( *p++ & nlmask ) == nlchar ) {
804 * If this file is of type TEXT, then swap \012 to \015.
807 for ( p = rbuf, q = p + cc; p < q; p++ ) {
808 if ( *p == '\012' ) {
810 } else if ( *p == '\015' ) {
819 return( AFPERR_EOF );
824 /* -----------------------------
825 * with ddp, afp_read can return fewer bytes than in reqcount
826 * so return EOF only if read actually past end of file not
827 * if offset +reqcount > size of file
829 * getfork size ==> 10430
830 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
831 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
832 * read fork offset 9248 size 1508 ==> 1182 (EOF)
833 * 10752 is a bug in Mac 7.5.x finder
835 * with dsi, should we check that reqcount < server quantum?
837 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
840 off_t offset, saveoff, reqcount, savereqcount;
844 u_char nlmask, nlchar;
847 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
848 ibuf += sizeof( u_short );
850 if (NULL == ( ofork = of_find( ofrefnum )) ) {
851 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
856 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
860 offset = get_off_t(&ibuf, is64);
861 reqcount = get_off_t(&ibuf, is64);
870 /* if we wanted to be picky, we could add in the following
871 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
873 if (reqcount < 0 || offset < 0) {
878 if ( ofork->of_flags & AFPFORK_DATA) {
880 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
881 } else if (ofork->of_flags & AFPFORK_RSRC) {
883 } else { /* fork wasn't opened. this should never really happen. */
888 /* zero request count */
894 savereqcount = reqcount;
896 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
901 #define min(a,b) ((a)<(b)?(a):(b))
902 *rbuflen = min( reqcount, *rbuflen );
903 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
907 /* dsi can stream requests. we can only do this if we're not checking
908 * for an end-of-line character. oh well. */
909 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
910 DSI *dsi = obj->handle;
913 /* reqcount isn't always truthful. we need to deal with that. */
914 size = ad_size(ofork->of_ad, eid);
916 /* subtract off the offset */
918 if (reqcount > size) {
925 /* dsi_readinit() returns size of next read buffer. by this point,
926 * we know that we're sending some data. if we fail, something
927 * horrible happened. */
928 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
931 /* due to the nature of afp packets, we have to exit if we get
932 an error. we can't do this with translation on. */
934 if (!(xlate || Debug(obj) )) {
937 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
938 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
939 if (errno == EINVAL || errno == ENOSYS)
942 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
954 /* fill up our buffer. */
955 while (*rbuflen > 0) {
956 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
962 if (obj->options.flags & OPTION_DEBUG) {
963 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
964 bprint(rbuf, *rbuflen);
967 /* dsi_read() also returns buffer size of next allocation */
968 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
977 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
979 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
980 obj->exit(EXITERR_CLNT);
984 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
992 /* ---------------------- */
993 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
995 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
998 /* ---------------------- */
999 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1001 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1004 /* ---------------------- */
1005 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1013 memcpy(&vid, ibuf, sizeof(vid));
1014 if (NULL == ( vol = getvolbyvid( vid )) ) {
1015 return( AFPERR_PARAM );
1022 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1024 struct ofork *ofork;
1029 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1031 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1032 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1033 return( AFPERR_PARAM );
1036 if ( flushfork( ofork ) < 0 ) {
1037 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1045 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1046 fsync(2) on OSX is implemented differently than on other platforms.
1047 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1049 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1051 struct ofork *ofork;
1057 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1058 ibuf += sizeof( ofrefnum );
1060 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1061 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1062 return( AFPERR_PARAM );
1065 if ( flushfork( ofork ) < 0 ) {
1066 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1073 /* this is very similar to closefork */
1074 int flushfork(struct ofork *ofork)
1078 int err = 0, doflush = 0;
1080 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1081 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1082 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1083 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1087 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1088 (ofork->of_flags & AFPFORK_RSRC)) {
1090 /* read in the rfork length */
1091 ad_refresh(ofork->of_ad);
1093 /* set the date if we're dirty */
1094 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1095 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1096 ofork->of_flags &= ~AFPFORK_DIRTY;
1100 /* flush the header */
1101 if (doflush && ad_flush(ofork->of_ad) < 0)
1104 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1108 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1109 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1115 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1117 struct ofork *ofork;
1122 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1124 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1125 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1126 return( AFPERR_PARAM );
1128 if ( of_closefork( ofork ) < 0 ) {
1129 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1130 return( AFPERR_PARAM );
1137 static 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(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1166 return( AFPERR_PARAM );
1174 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1175 * the client may have sent us a bunch of data that's not reflected
1176 * in reqcount et al. */
1177 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1179 struct ofork *ofork;
1180 off_t offset, saveoff, reqcount;
1181 int endflag, eid, xlate = 0, err = AFP_OK;
1185 /* figure out parameters */
1187 endflag = ENDBIT(*ibuf);
1189 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1190 ibuf += sizeof( ofrefnum );
1192 offset = get_off_t(&ibuf, is64);
1193 reqcount = get_off_t(&ibuf, is64);
1195 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1196 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1201 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1202 err = AFPERR_ACCESS;
1207 writtenfork = ofork;
1210 if ( ofork->of_flags & AFPFORK_DATA) {
1212 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1213 } else if (ofork->of_flags & AFPFORK_RSRC) {
1216 err = AFPERR_ACCESS; /* should never happen */
1221 offset += ad_size(ofork->of_ad, eid);
1223 /* handle bogus parameters */
1224 if (reqcount < 0 || offset < 0) {
1229 /* offset can overflow on 64-bit capable filesystems.
1230 * report disk full if that's going to happen. */
1231 if (sum_neg(is64, offset, reqcount)) {
1236 if (!reqcount) { /* handle request counts of 0 */
1238 *rbuflen = set_off_t (offset, rbuf, is64);
1243 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1244 reqcount, ofork->of_refnum) < 0) {
1249 /* this is yucky, but dsi can stream i/o and asp can't */
1250 switch (obj->proto) {
1253 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1255 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1256 return( AFPERR_PARAM );
1260 if (obj->options.flags & OPTION_DEBUG) {
1261 printf("(write) len: %d\n", *rbuflen);
1262 bprint(rbuf, *rbuflen);
1265 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1268 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1273 #endif /* no afp/asp */
1277 DSI *dsi = obj->handle;
1279 /* find out what we have already and write it out. */
1280 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1281 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1282 dsi_writeflush(dsi);
1284 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1289 #if 0 /*def HAVE_SENDFILE_WRITE*/
1290 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1291 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1292 offset, dsi->datasize)) < 0) {
1300 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1301 goto afp_write_loop;
1303 dsi_writeflush(dsi);
1305 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1306 reqcount, ofork->of_refnum);
1311 goto afp_write_done;
1313 #endif /* 0, was HAVE_SENDFILE_WRITE */
1315 /* loop until everything gets written. currently
1316 * dsi_write handles the end case by itself. */
1317 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1318 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1319 dsi_writeflush(dsi);
1321 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1322 reqcount, ofork->of_refnum);
1331 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1332 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1333 ofork->of_flags |= AFPFORK_DIRTY;
1335 *rbuflen = set_off_t (offset, rbuf, is64);
1339 if (obj->proto == AFPPROTO_DSI) {
1340 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1341 dsi_writeflush(obj->handle);
1343 if (err != AFP_OK) {
1349 /* ---------------------------- */
1350 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1352 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1355 /* ----------------------------
1356 * FIXME need to deal with SIGXFSZ signal
1358 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1360 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1363 /* ---------------------------- */
1364 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1366 struct ofork *ofork;
1368 u_int16_t ofrefnum, bitmap;
1371 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1372 ibuf += sizeof( ofrefnum );
1373 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1374 bitmap = ntohs( bitmap );
1375 ibuf += sizeof( bitmap );
1378 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1379 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1380 return( AFPERR_PARAM );
1383 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1384 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1385 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1386 return( AFPERR_PARAM );
1390 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1391 rbuf + sizeof( u_short ), &buflen ))) {
1395 *rbuflen = buflen + sizeof( u_short );
1396 bitmap = htons( bitmap );
1397 memcpy(rbuf, &bitmap, sizeof( bitmap ));