2 * $Id: fork.c,v 1.59 2009-02-25 22:41:03 didg 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) );
1135 /* this is very similar to closefork */
1136 int flushfork( ofork )
1137 struct ofork *ofork;
1141 int err = 0, doflush = 0;
1143 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1144 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1145 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1146 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1150 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1151 (ofork->of_flags & AFPFORK_RSRC)) {
1153 /* read in the rfork length */
1154 ad_refresh(ofork->of_ad);
1156 /* set the date if we're dirty */
1157 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1158 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1159 ofork->of_flags &= ~AFPFORK_DIRTY;
1163 /* flush the header */
1164 if (doflush && ad_flush(ofork->of_ad) < 0)
1167 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1171 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1172 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1178 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1180 char *ibuf, *rbuf _U_;
1181 int ibuflen _U_, *rbuflen;
1183 struct ofork *ofork;
1188 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1190 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1191 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1192 return( AFPERR_PARAM );
1194 if ( of_closefork( ofork ) < 0 ) {
1195 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1196 return( AFPERR_PARAM );
1203 static ssize_t write_file(struct ofork *ofork, int eid,
1204 off_t offset, char *rbuf,
1205 size_t rbuflen, const int xlate)
1211 * If this file is of type TEXT, swap \015 to \012.
1214 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1215 if ( *p == '\015' ) {
1217 } else if ( *p == '\012' ) {
1223 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1224 rbuf, rbuflen)) < 0 ) {
1229 return( AFPERR_DFULL );
1231 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1232 return( AFPERR_PARAM );
1240 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1241 * the client may have sent us a bunch of data that's not reflected
1242 * in reqcount et al. */
1243 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1246 int ibuflen _U_, *rbuflen;
1249 struct ofork *ofork;
1250 off_t offset, saveoff, reqcount;
1251 int endflag, eid, xlate = 0, err = AFP_OK;
1255 /* figure out parameters */
1257 endflag = ENDBIT(*ibuf);
1259 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1260 ibuf += sizeof( ofrefnum );
1262 offset = get_off_t(&ibuf, is64);
1263 reqcount = get_off_t(&ibuf, is64);
1265 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1266 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1271 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1272 err = AFPERR_ACCESS;
1277 writtenfork = ofork;
1280 if ( ofork->of_flags & AFPFORK_DATA) {
1282 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1283 } else if (ofork->of_flags & AFPFORK_RSRC) {
1286 err = AFPERR_ACCESS; /* should never happen */
1291 offset += ad_size(ofork->of_ad, eid);
1293 /* handle bogus parameters */
1294 if (reqcount < 0 || offset < 0) {
1299 /* offset can overflow on 64-bit capable filesystems.
1300 * report disk full if that's going to happen. */
1301 if (sum_neg(is64, offset, reqcount)) {
1306 if (!reqcount) { /* handle request counts of 0 */
1308 *rbuflen = set_off_t (offset, rbuf, is64);
1313 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1314 reqcount, ofork->of_refnum) < 0) {
1319 /* this is yucky, but dsi can stream i/o and asp can't */
1320 switch (obj->proto) {
1323 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1325 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1326 return( AFPERR_PARAM );
1330 if (obj->options.flags & OPTION_DEBUG) {
1331 printf("(write) len: %d\n", *rbuflen);
1332 bprint(rbuf, *rbuflen);
1335 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1338 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1343 #endif /* no afp/asp */
1347 DSI *dsi = obj->handle;
1349 /* find out what we have already and write it out. */
1350 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1351 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1352 dsi_writeflush(dsi);
1354 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1359 #if 0 /*def HAVE_SENDFILE_WRITE*/
1360 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1361 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1362 offset, dsi->datasize)) < 0) {
1370 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1371 goto afp_write_loop;
1373 dsi_writeflush(dsi);
1375 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1376 reqcount, ofork->of_refnum);
1381 goto afp_write_done;
1383 #endif /* 0, was HAVE_SENDFILE_WRITE */
1385 /* loop until everything gets written. currently
1386 * dsi_write handles the end case by itself. */
1387 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1389 if ( obj->options.flags & OPTION_DEBUG ) {
1390 printf("(write) command cont'd: %d\n", cc);
1394 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1395 dsi_writeflush(dsi);
1397 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1398 reqcount, ofork->of_refnum);
1407 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1408 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1409 ofork->of_flags |= AFPFORK_DIRTY;
1411 *rbuflen = set_off_t (offset, rbuf, is64);
1415 if (obj->proto == AFPPROTO_DSI) {
1416 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1417 dsi_writeflush(obj->handle);
1419 if (err != AFP_OK) {
1425 /* ---------------------------- */
1426 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1429 int ibuflen, *rbuflen;
1431 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1434 /* ----------------------------
1435 * FIXME need to deal with SIGXFSZ signal
1437 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1440 int ibuflen, *rbuflen;
1442 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1445 /* ---------------------------- */
1446 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1449 int ibuflen _U_, *rbuflen;
1451 struct ofork *ofork;
1453 u_int16_t ofrefnum, bitmap;
1456 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1457 ibuf += sizeof( ofrefnum );
1458 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1459 bitmap = ntohs( bitmap );
1460 ibuf += sizeof( bitmap );
1463 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1464 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1465 return( AFPERR_PARAM );
1468 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1469 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1470 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1471 return( AFPERR_PARAM );
1475 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1476 rbuf + sizeof( u_short ), &buflen ))) {
1480 *rbuflen = buflen + sizeof( u_short );
1481 bitmap = htons( bitmap );
1482 memcpy(rbuf, &bitmap, sizeof( bitmap ));