2 * $Id: fork.c,v 1.62 2009-09-11 09:14:16 franklahm Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #include <atalk/adouble.h>
19 #include <atalk/logger.h>
21 #include <sys/param.h>
22 #include <sys/socket.h>
24 #include <netatalk/at.h>
26 #include <atalk/dsi.h>
27 #include <atalk/atp.h>
28 #include <atalk/asp.h>
29 #include <atalk/afp.h>
31 #include <atalk/util.h>
32 #include <atalk/cnid.h>
37 #include "directory.h"
42 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
47 struct ofork *writtenfork;
48 extern int getmetadata(struct vol *vol,
50 struct path *path, struct dir *dir, char *buf,
51 int *buflen, struct adouble *adp);
53 static int getforkparams(ofork, bitmap, buf, buflen )
67 /* can only get the length of the opened fork */
68 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
69 && (ofork->of_flags & AFPFORK_RSRC))
71 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
72 && (ofork->of_flags & AFPFORK_DATA))) {
73 return( AFPERR_BITMAP );
76 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
85 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
86 return( AFPERR_MISC );
88 path.m_name = of_name(ofork);
90 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
91 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
92 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
93 if ( ad_data_fileno( ofork->of_ad ) == -1 ) {
94 if (movecwd(vol, dir) < 0)
95 return( AFPERR_NOOBJ );
96 if ( stat( path.u_name, st ) < 0 )
97 return( AFPERR_NOOBJ );
99 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
100 return( AFPERR_BITMAP );
104 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
107 /* ---------------------------- */
108 static off_t get_off_t(ibuf, is64)
116 memcpy(&temp, *ibuf, sizeof( temp ));
117 ret = ntohl(temp); /* ntohl is unsigned */
118 *ibuf += sizeof(temp);
121 memcpy(&temp, *ibuf, sizeof( temp ));
122 *ibuf += sizeof(temp);
123 ret = ntohl(temp)| (ret << 32);
126 ret = (int)ret; /* sign extend */
131 /* ---------------------- */
132 static int set_off_t(offset, rbuf, is64)
142 temp = htonl(offset >> 32);
143 memcpy(rbuf, &temp, sizeof( temp ));
144 rbuf += sizeof(temp);
145 ret = sizeof( temp );
146 offset &= 0xffffffff;
148 temp = htonl(offset);
149 memcpy(rbuf, &temp, sizeof( temp ));
150 ret += sizeof( temp );
155 /* ------------------------
157 static int is_neg(int is64, off_t val)
159 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
164 static int sum_neg(int is64, off_t offset, off_t reqcount)
166 if (is_neg(is64, offset +reqcount) )
171 /* -------------------------
173 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
175 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
178 /* -------------------------
180 int getforkmode(struct adouble *adp, int eid, int what)
182 return ad_testlock(adp, eid, what);
185 /* -------------------------
187 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
195 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
196 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
199 if ((access & (OPENACC_RD | OPENACC_DRD))) {
200 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
202 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
205 if ((access & OPENACC_RD) && denyreadset) {
209 if ((access & OPENACC_DRD) && readset) {
213 /* boolean logic is not enough, because getforkmode is not always telling the
216 if ((access & OPENACC_RD)) {
217 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
221 if ((access & OPENACC_DRD)) {
222 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
227 /* ------------same for writing -------------- */
228 if ((access & (OPENACC_WR | OPENACC_DWR))) {
229 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
231 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
234 if ((access & OPENACC_WR) && denywriteset) {
238 if ((access & OPENACC_DWR) && writeset) {
242 if ((access & OPENACC_WR)) {
243 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
247 if ((access & OPENACC_DWR)) {
248 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
253 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
254 return ad_excl_lock(adp, eid);
259 /* ----------------------- */
260 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
263 int ibuflen _U_, *rbuflen;
267 struct ofork *ofork, *opened;
268 struct adouble *adsame = NULL;
269 int buflen, ret, adflags, eid;
271 u_int16_t vid, bitmap, access, ofrefnum;
272 char fork, *path, *upath;
279 memcpy(&vid, ibuf, sizeof( vid ));
283 if (NULL == ( vol = getvolbyvid( vid ))) {
284 return( AFPERR_PARAM );
287 memcpy(&did, ibuf, sizeof( did ));
288 ibuf += sizeof( int );
290 if (NULL == ( dir = dirlookup( vol, did ))) {
294 memcpy(&bitmap, ibuf, sizeof( bitmap ));
295 bitmap = ntohs( bitmap );
296 ibuf += sizeof( bitmap );
297 memcpy(&access, ibuf, sizeof( access ));
298 access = ntohs( access );
299 ibuf += sizeof( access );
301 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
305 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
306 return get_afp_errno(AFPERR_PARAM);
309 if (*s_path->m_name == '\0') {
311 return AFPERR_BADTYPE;
314 /* stat() data fork st is set because it's not a dir */
315 switch ( s_path->st_errno ) {
321 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
323 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
326 /* FIXME should we check it first ? */
327 upath = s_path->u_name;
328 if (!vol_unix_priv(vol)) {
329 if (check_access(upath, access ) < 0) {
330 return AFPERR_ACCESS;
334 if (file_access(s_path, access ) < 0) {
335 return AFPERR_ACCESS;
340 /* XXX: this probably isn't the best way to do this. the already
341 open bits should really be set if the fork is opened by any
342 program, not just this one. however, that's problematic to do
343 if we can't write lock files somewhere. opened is also passed to
344 ad_open so that we can keep file locks together.
345 FIXME: add the fork we are opening?
347 if ((opened = of_findname(s_path))) {
348 adsame = opened->of_ad;
351 if ( fork == OPENFORK_DATA ) {
353 adflags = ADFLAGS_DF|ADFLAGS_HF;
356 adflags = ADFLAGS_HF;
359 path = s_path->m_name;
360 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
361 adsame, st)) == NULL ) {
362 return( AFPERR_NFILE );
366 if (access & OPENACC_WR) {
367 /* try opening in read-write mode */
368 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
376 if (fork == OPENFORK_DATA) {
377 /* try to open only the data fork */
378 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
381 adflags = ADFLAGS_DF;
384 /* here's the deal. we only try to create the resource
385 * fork if the user wants to open it for write acess. */
386 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
388 ofork->of_flags |= AFPFORK_OPEN;
397 ret = AFPERR_BADTYPE;
401 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
408 /* the ressource fork is open too */
409 ofork->of_flags |= AFPFORK_OPEN;
412 /* try opening in read-only mode */
414 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
422 /* see if client asked for a read only data fork */
423 if (fork == OPENFORK_DATA) {
424 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
427 adflags = ADFLAGS_DF;
429 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
430 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
431 * then create in open read-write.
432 * FIXME , it doesn't play well with byte locking example:
433 * ressource fork open read only
434 * locking set on it (no effect, there's no file!)
435 * ressource fork open read write now
444 ret = AFPERR_BADTYPE;
448 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
454 /* the ressource fork is open too */
455 ofork->of_flags |= AFPFORK_OPEN;
459 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
460 if (ad_setname(ofork->of_ad, path)) {
461 ad_flush( ofork->of_ad );
465 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
466 &buflen )) != AFP_OK ) {
467 ad_close( ofork->of_ad, adflags );
471 *rbuflen = buflen + 2 * sizeof( u_int16_t );
472 bitmap = htons( bitmap );
473 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
474 rbuf += sizeof( u_int16_t );
476 /* check WriteInhibit bit if we have a ressource fork
477 * the test is done here, after some Mac trafic capture
479 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
480 ad_getattr(ofork->of_ad, &bshort);
481 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
482 ad_close( ofork->of_ad, adflags );
485 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
486 return(AFPERR_OLOCK);
491 * synchronization locks:
494 /* don't try to lock non-existent rforks. */
495 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
497 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
498 /* can we access the fork? */
501 ad_close( ofork->of_ad, adflags );
504 case EAGAIN: /* return data anyway */
508 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
509 return( AFPERR_DENYCONF );
513 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
514 return( AFPERR_PARAM );
517 if ((access & OPENACC_WR))
518 ofork->of_flags |= AFPFORK_ACCWR;
520 /* the file may be open read only without ressource fork */
521 if ((access & OPENACC_RD))
522 ofork->of_flags |= AFPFORK_ACCRD;
524 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
530 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
534 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
536 char *ibuf, *rbuf _U_;
537 int ibuflen, *rbuflen;
541 u_int16_t ofrefnum, bitmap;
549 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
550 ibuf += sizeof( ofrefnum );
552 memcpy(&bitmap, ibuf, sizeof(bitmap));
553 bitmap = ntohs(bitmap);
554 ibuf += sizeof( bitmap );
557 if (NULL == ( ofork = of_find( ofrefnum )) ) {
558 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
559 return( AFPERR_PARAM );
562 if (ofork->of_vol->v_flags & AFPVOL_RO)
565 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
566 return AFPERR_ACCESS;
568 if ( ofork->of_flags & AFPFORK_DATA) {
570 } else if (ofork->of_flags & AFPFORK_RSRC) {
575 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
576 && eid == ADEID_RFORK
578 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
579 && eid == ADEID_DFORK)) {
580 return AFPERR_BITMAP;
584 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
585 if (afp_version >= 30) {
589 return AFPERR_BITMAP;
592 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
593 return AFPERR_PARAM ;
595 size = get_off_t(&ibuf, is64);
598 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
601 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
602 st_size = ad_size(ofork->of_ad, eid);
604 if (st_size > size &&
605 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
606 goto afp_setfork_err;
608 err = ad_dtruncate( ofork->of_ad, size );
610 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
612 goto afp_setfork_err;
613 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
614 ad_refresh( ofork->of_ad );
616 st_size = ad_size(ofork->of_ad, eid);
618 if (st_size > size &&
619 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
620 goto afp_setfork_err;
622 err = ad_rtruncate(ofork->of_ad, size);
624 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
626 goto afp_setfork_err;
628 if (ad_flush( ofork->of_ad ) < 0) {
629 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
633 return AFPERR_BITMAP;
636 if ( flushfork( ofork ) < 0 ) {
637 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
652 return AFPERR_ACCESS;
663 /* for this to work correctly, we need to check for locks before each
664 * read and write. that's most easily handled by always doing an
665 * appropriate check before each ad_read/ad_write. other things
666 * that can change files like truncate are handled internally to those
669 #define ENDBIT(a) ((a) & 0x80)
670 #define UNLOCKBIT(a) ((a) & 0x01)
673 /* ---------------------- */
674 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
677 int ibuflen _U_, *rbuflen;
681 off_t offset, length;
689 /* figure out parameters */
691 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
693 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
694 ibuf += sizeof(ofrefnum);
696 if (NULL == ( ofork = of_find( ofrefnum )) ) {
697 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
698 return( AFPERR_PARAM );
701 if ( ofork->of_flags & AFPFORK_DATA) {
703 } else if (ofork->of_flags & AFPFORK_RSRC) {
708 offset = get_off_t(&ibuf, is64);
709 length = get_off_t(&ibuf, is64);
711 /* FIXME AD_FILELOCK test is surely wrong */
713 length = BYTELOCK_MAX;
714 else if (!length || is_neg(is64, length)) {
716 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
721 offset += ad_size(ofork->of_ad, eid);
722 /* FIXME what do we do if file size > 2 GB and
723 it's not byte_lock_ext?
726 if (offset < 0) /* error if we have a negative offset */
729 /* if the file is a read-only file, we use read locks instead of
730 * write locks. that way, we can prevent anyone from initiating
732 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
733 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
734 ofork->of_refnum) < 0) {
738 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
744 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
752 *rbuflen = set_off_t (offset, rbuf, is64);
756 /* --------------------------- */
757 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
760 int ibuflen, *rbuflen;
762 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
765 /* --------------------------- */
766 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
769 int ibuflen, *rbuflen;
771 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
776 /* --------------------------- */
777 static int crlf( of )
782 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
783 /* no resource fork or no finderinfo, use our files extension mapping */
784 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
787 /* file type is TEXT */
790 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
797 static ssize_t read_file(struct ofork *ofork, int eid,
798 off_t offset, u_char nlmask,
799 u_char nlchar, char *rbuf,
800 int *rbuflen, const int xlate)
806 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
808 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
810 return( AFPERR_PARAM );
812 if ( cc < *rbuflen ) {
820 for ( p = rbuf, q = p + cc; p < q; ) {
821 if (( *p++ & nlmask ) == nlchar ) {
832 * If this file is of type TEXT, then swap \012 to \015.
835 for ( p = rbuf, q = p + cc; p < q; p++ ) {
836 if ( *p == '\012' ) {
838 } else if ( *p == '\015' ) {
847 return( AFPERR_EOF );
852 /* -----------------------------
853 * with ddp, afp_read can return fewer bytes than in reqcount
854 * so return EOF only if read actually past end of file not
855 * if offset +reqcount > size of file
857 * getfork size ==> 10430
858 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
859 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
860 * read fork offset 9248 size 1508 ==> 1182 (EOF)
861 * 10752 is a bug in Mac 7.5.x finder
863 * with dsi, should we check that reqcount < server quantum?
865 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
868 int ibuflen _U_, *rbuflen;
872 off_t offset, saveoff, reqcount, savereqcount;
873 int cc, err, eid, xlate = 0;
875 u_char nlmask, nlchar;
878 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
879 ibuf += sizeof( u_short );
881 if (NULL == ( ofork = of_find( ofrefnum )) ) {
882 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
887 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
891 offset = get_off_t(&ibuf, is64);
892 reqcount = get_off_t(&ibuf, is64);
901 /* if we wanted to be picky, we could add in the following
902 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
904 if (reqcount < 0 || offset < 0) {
909 if ( ofork->of_flags & AFPFORK_DATA) {
911 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
912 } else if (ofork->of_flags & AFPFORK_RSRC) {
914 } else { /* fork wasn't opened. this should never really happen. */
919 /* zero request count */
925 savereqcount = reqcount;
927 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
932 #define min(a,b) ((a)<(b)?(a):(b))
933 *rbuflen = min( reqcount, *rbuflen );
934 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
938 /* dsi can stream requests. we can only do this if we're not checking
939 * for an end-of-line character. oh well. */
940 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
941 DSI *dsi = obj->handle;
943 int non_blocking = 0;
946 if (obj->options.flags & OPTION_DEBUG) {
947 printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID);
948 bprint(rbuf, *rbuflen);
951 /* reqcount isn't always truthful. we need to deal with that. */
952 size = ad_size(ofork->of_ad, eid);
954 /* subtract off the offset */
956 if (reqcount > size) {
963 /* dsi_readinit() returns size of next read buffer. by this point,
964 * we know that we're sending some data. if we fail, something
965 * horrible happened. */
966 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
969 /* due to the nature of afp packets, we have to exit if we get
970 an error. we can't do this with translation on. */
971 #if 0 /* ifdef WITH_SENDFILE */
972 /* FIXME with OS X deadlock partial workaround we can't use sendfile */
973 if (!(xlate || Debug(obj) )) {
974 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize) < 0) {
975 if (errno == EINVAL || errno == ENOSYS)
978 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
990 /* fill up our buffer. */
992 /* set to non blocking mode */
996 /* fill up our buffer. */
997 while (*rbuflen > 0) {
998 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
1004 if (obj->options.flags & OPTION_DEBUG) {
1005 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1006 bprint(rbuf, *rbuflen);
1009 /* dsi_read() also returns buffer size of next allocation */
1010 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1016 /* set back to blocking mode */
1023 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
1025 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1026 obj->exit(EXITERR_CLNT);
1030 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1038 /* ---------------------- */
1039 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1042 int ibuflen, *rbuflen;
1044 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1047 /* ---------------------- */
1048 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1051 int ibuflen, *rbuflen;
1053 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1056 /* ---------------------- */
1057 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1059 char *ibuf, *rbuf _U_;
1060 int ibuflen _U_, *rbuflen;
1068 memcpy(&vid, ibuf, sizeof(vid));
1069 if (NULL == ( vol = getvolbyvid( vid )) ) {
1070 return( AFPERR_PARAM );
1077 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1079 char *ibuf, *rbuf _U_;
1080 int ibuflen _U_, *rbuflen;
1082 struct ofork *ofork;
1087 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1089 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1090 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1091 return( AFPERR_PARAM );
1094 if ( flushfork( ofork ) < 0 ) {
1095 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1103 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1104 fsync(2) on OSX is implemented differently than on other platforms.
1105 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1107 int afp_syncfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1109 char *ibuf, *rbuf _U_;
1110 int ibuflen _U_, *rbuflen;
1112 struct ofork *ofork;
1118 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1119 ibuf += sizeof( ofrefnum );
1121 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1122 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1123 return( AFPERR_PARAM );
1126 if ( flushfork( ofork ) < 0 ) {
1127 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1134 /* this is very similar to closefork */
1135 int flushfork( ofork )
1136 struct ofork *ofork;
1140 int err = 0, doflush = 0;
1142 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1143 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1144 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1145 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1149 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1150 (ofork->of_flags & AFPFORK_RSRC)) {
1152 /* read in the rfork length */
1153 ad_refresh(ofork->of_ad);
1155 /* set the date if we're dirty */
1156 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1157 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1158 ofork->of_flags &= ~AFPFORK_DIRTY;
1162 /* flush the header */
1163 if (doflush && ad_flush(ofork->of_ad) < 0)
1166 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1170 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1171 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1177 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1179 char *ibuf, *rbuf _U_;
1180 int ibuflen _U_, *rbuflen;
1182 struct ofork *ofork;
1187 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1189 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1190 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1191 return( AFPERR_PARAM );
1193 if ( of_closefork( ofork ) < 0 ) {
1194 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1195 return( AFPERR_PARAM );
1202 static ssize_t write_file(struct ofork *ofork, int eid,
1203 off_t offset, char *rbuf,
1204 size_t rbuflen, const int xlate)
1210 * If this file is of type TEXT, swap \015 to \012.
1213 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1214 if ( *p == '\015' ) {
1216 } else if ( *p == '\012' ) {
1222 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1223 rbuf, rbuflen)) < 0 ) {
1228 return( AFPERR_DFULL );
1230 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1231 return( AFPERR_PARAM );
1239 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1240 * the client may have sent us a bunch of data that's not reflected
1241 * in reqcount et al. */
1242 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1245 int ibuflen _U_, *rbuflen;
1248 struct ofork *ofork;
1249 off_t offset, saveoff, reqcount;
1250 int endflag, eid, xlate = 0, err = AFP_OK;
1254 /* figure out parameters */
1256 endflag = ENDBIT(*ibuf);
1258 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1259 ibuf += sizeof( ofrefnum );
1261 offset = get_off_t(&ibuf, is64);
1262 reqcount = get_off_t(&ibuf, is64);
1264 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1265 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1270 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1271 err = AFPERR_ACCESS;
1276 writtenfork = ofork;
1279 if ( ofork->of_flags & AFPFORK_DATA) {
1281 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1282 } else if (ofork->of_flags & AFPFORK_RSRC) {
1285 err = AFPERR_ACCESS; /* should never happen */
1290 offset += ad_size(ofork->of_ad, eid);
1292 /* handle bogus parameters */
1293 if (reqcount < 0 || offset < 0) {
1298 /* offset can overflow on 64-bit capable filesystems.
1299 * report disk full if that's going to happen. */
1300 if (sum_neg(is64, offset, reqcount)) {
1305 if (!reqcount) { /* handle request counts of 0 */
1307 *rbuflen = set_off_t (offset, rbuf, is64);
1312 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1313 reqcount, ofork->of_refnum) < 0) {
1318 /* this is yucky, but dsi can stream i/o and asp can't */
1319 switch (obj->proto) {
1322 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1324 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1325 return( AFPERR_PARAM );
1329 if (obj->options.flags & OPTION_DEBUG) {
1330 printf("(write) len: %d\n", *rbuflen);
1331 bprint(rbuf, *rbuflen);
1334 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1337 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1342 #endif /* no afp/asp */
1346 DSI *dsi = obj->handle;
1348 /* find out what we have already and write it out. */
1349 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1350 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1351 dsi_writeflush(dsi);
1353 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1358 #if 0 /*def HAVE_SENDFILE_WRITE*/
1359 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1360 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1361 offset, dsi->datasize)) < 0) {
1369 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1370 goto afp_write_loop;
1372 dsi_writeflush(dsi);
1374 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1375 reqcount, ofork->of_refnum);
1380 goto afp_write_done;
1382 #endif /* 0, was HAVE_SENDFILE_WRITE */
1384 /* loop until everything gets written. currently
1385 * dsi_write handles the end case by itself. */
1386 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1388 if ( obj->options.flags & OPTION_DEBUG ) {
1389 printf("(write) command cont'd: %d\n", cc);
1393 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1394 dsi_writeflush(dsi);
1396 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1397 reqcount, ofork->of_refnum);
1406 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1407 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1408 ofork->of_flags |= AFPFORK_DIRTY;
1410 *rbuflen = set_off_t (offset, rbuf, is64);
1414 if (obj->proto == AFPPROTO_DSI) {
1415 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1416 dsi_writeflush(obj->handle);
1418 if (err != AFP_OK) {
1424 /* ---------------------------- */
1425 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1428 int ibuflen, *rbuflen;
1430 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1433 /* ----------------------------
1434 * FIXME need to deal with SIGXFSZ signal
1436 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1439 int ibuflen, *rbuflen;
1441 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1444 /* ---------------------------- */
1445 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1448 int ibuflen _U_, *rbuflen;
1450 struct ofork *ofork;
1452 u_int16_t ofrefnum, bitmap;
1455 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1456 ibuf += sizeof( ofrefnum );
1457 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1458 bitmap = ntohs( bitmap );
1459 ibuf += sizeof( bitmap );
1462 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1463 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1464 return( AFPERR_PARAM );
1467 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1468 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1469 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1470 return( AFPERR_PARAM );
1474 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1475 rbuf + sizeof( u_short ), &buflen ))) {
1479 *rbuflen = buflen + sizeof( u_short );
1480 bitmap = htons( bitmap );
1481 memcpy(rbuf, &bitmap, sizeof( bitmap ));