2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * Copyright (c) 2010 Frank Lahm
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
15 #include <sys/param.h>
16 #include <sys/socket.h>
19 #include <atalk/dsi.h>
20 #include <atalk/afp.h>
21 #include <atalk/adouble.h>
22 #include <atalk/logger.h>
23 #include <atalk/util.h>
24 #include <atalk/cnid.h>
25 #include <atalk/bstradd.h>
26 #include <atalk/globals.h>
30 #include "directory.h"
35 struct ofork *writtenfork;
38 static int getforkparams(struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen)
48 /* can only get the length of the opened fork */
49 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
50 && (ofork->of_flags & AFPFORK_RSRC))
52 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
53 && (ofork->of_flags & AFPFORK_DATA))) {
54 return( AFPERR_BITMAP );
57 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
64 dir = dirlookup(vol, ofork->of_did);
66 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
67 return( AFPERR_MISC );
69 path.m_name = of_name(ofork);
72 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
73 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
74 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
75 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
76 /* 0 is for symlink */
77 if (movecwd(vol, dir) < 0)
78 return( AFPERR_NOOBJ );
79 if ( lstat( path.u_name, st ) < 0 )
80 return( AFPERR_NOOBJ );
82 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
83 return( AFPERR_BITMAP );
87 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
90 static off_t get_off_t(char **ibuf, int is64)
96 memcpy(&temp, *ibuf, sizeof( temp ));
97 ret = ntohl(temp); /* ntohl is unsigned */
98 *ibuf += sizeof(temp);
101 memcpy(&temp, *ibuf, sizeof( temp ));
102 *ibuf += sizeof(temp);
103 ret = ntohl(temp)| (ret << 32);
106 ret = (int)ret; /* sign extend */
111 static int set_off_t(off_t offset, char *rbuf, int is64)
118 temp = htonl(offset >> 32);
119 memcpy(rbuf, &temp, sizeof( temp ));
120 rbuf += sizeof(temp);
121 ret = sizeof( temp );
122 offset &= 0xffffffff;
124 temp = htonl(offset);
125 memcpy(rbuf, &temp, sizeof( temp ));
126 ret += sizeof( temp );
131 static int is_neg(int is64, off_t val)
133 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
138 static int sum_neg(int is64, off_t offset, off_t reqcount)
140 if (is_neg(is64, offset +reqcount) )
145 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
153 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
154 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
157 if ((access & (OPENACC_RD | OPENACC_DRD))) {
158 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
160 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
163 if ((access & OPENACC_RD) && denyreadset) {
167 if ((access & OPENACC_DRD) && readset) {
171 /* boolean logic is not enough, because getforkmode is not always telling the
174 if ((access & OPENACC_RD)) {
175 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
179 if ((access & OPENACC_DRD)) {
180 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
185 /* ------------same for writing -------------- */
186 if ((access & (OPENACC_WR | OPENACC_DWR))) {
187 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
189 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
192 if ((access & OPENACC_WR) && denywriteset) {
196 if ((access & OPENACC_DWR) && writeset) {
200 if ((access & OPENACC_WR)) {
201 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
205 if ((access & OPENACC_DWR)) {
206 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
211 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
212 return ad_excl_lock(adp, eid);
217 /* ----------------------- */
218 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
222 struct ofork *ofork, *opened;
223 struct adouble *adsame = NULL;
225 int ret, adflags, eid;
227 uint16_t vid, bitmap, access, ofrefnum;
228 char fork, *path, *upath;
235 memcpy(&vid, ibuf, sizeof( vid ));
239 if (NULL == ( vol = getvolbyvid( vid ))) {
240 return( AFPERR_PARAM );
243 memcpy(&did, ibuf, sizeof( did ));
244 ibuf += sizeof( int );
246 if (NULL == ( dir = dirlookup( vol, did ))) {
250 memcpy(&bitmap, ibuf, sizeof( bitmap ));
251 bitmap = ntohs( bitmap );
252 ibuf += sizeof( bitmap );
253 memcpy(&access, ibuf, sizeof( access ));
254 access = ntohs( access );
255 ibuf += sizeof( access );
257 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
261 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
262 return get_afp_errno(AFPERR_PARAM);
265 if (*s_path->m_name == '\0') {
267 return AFPERR_BADTYPE;
270 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s)",
271 fullpathname(s_path->u_name), (fork & OPENFORK_RSCS) ? "RSRC" : "DATA");
273 /* stat() data fork st is set because it's not a dir */
274 switch ( s_path->st_errno ) {
280 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
282 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
285 /* FIXME should we check it first ? */
286 upath = s_path->u_name;
287 if (!vol_unix_priv(vol)) {
288 if (check_access(upath, access ) < 0) {
289 return AFPERR_ACCESS;
292 if (file_access(s_path, access ) < 0) {
293 return AFPERR_ACCESS;
298 /* XXX: this probably isn't the best way to do this. the already
299 open bits should really be set if the fork is opened by any
300 program, not just this one. however, that's problematic to do
301 if we can't write lock files somewhere. opened is also passed to
302 ad_open so that we can keep file locks together.
303 FIXME: add the fork we are opening?
305 if ((opened = of_findname(s_path))) {
306 adsame = opened->of_ad;
309 if ( fork == OPENFORK_DATA ) {
311 adflags = ADFLAGS_DF | ADFLAGS_HF ;
314 adflags = ADFLAGS_RF | ADFLAGS_HF;
317 path = s_path->m_name;
318 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
319 adsame, st)) == NULL ) {
320 return( AFPERR_NFILE );
324 if (access & OPENACC_WR) {
325 /* try opening in read-write mode */
326 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDWR) < 0) {
334 if (fork == OPENFORK_DATA) {
335 /* try to open only the data fork */
336 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDWR) < 0) {
339 adflags = ADFLAGS_DF;
341 /* here's the deal. we only try to create the resource
342 * fork if the user wants to open it for write acess. */
343 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) < 0)
345 ofork->of_flags |= AFPFORK_OPEN;
354 ret = AFPERR_BADTYPE;
358 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
365 /* the ressource fork is open too */
366 ofork->of_flags |= AFPFORK_OPEN;
369 /* try opening in read-only mode */
371 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY) < 0) {
379 /* see if client asked for a read only data fork */
380 if (fork == OPENFORK_DATA) {
381 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY) < 0) {
384 adflags = ADFLAGS_DF;
386 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
387 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
388 * then create in open read-write.
389 * FIXME , it doesn't play well with byte locking example:
390 * ressource fork open read only
391 * locking set on it (no effect, there's no file!)
392 * ressource fork open read write now
401 ret = AFPERR_BADTYPE;
405 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
406 fullpathname(s_path->m_name), strerror(errno) );
412 /* the ressource fork is open too */
413 ofork->of_flags |= AFPFORK_OPEN;
417 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
418 if (ad_setname(ofork->of_ad, path)) {
419 ad_flush( ofork->of_ad );
423 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
424 ad_close( ofork->of_ad, adflags );
428 *rbuflen = buflen + 2 * sizeof( uint16_t );
429 bitmap = htons( bitmap );
430 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
431 rbuf += sizeof( uint16_t );
433 /* check WriteInhibit bit if we have a ressource fork
434 * the test is done here, after some Mac trafic capture
436 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
437 ad_getattr(ofork->of_ad, &bshort);
438 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
439 ad_close( ofork->of_ad, adflags );
442 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
443 return(AFPERR_OLOCK);
448 * synchronization locks:
451 /* don't try to lock non-existent rforks. */
452 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
454 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
455 /* can we access the fork? */
458 ad_close( ofork->of_ad, adflags );
461 case EAGAIN: /* return data anyway */
465 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
466 return( AFPERR_DENYCONF );
470 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
471 return( AFPERR_PARAM );
474 if ((access & OPENACC_WR))
475 ofork->of_flags |= AFPFORK_ACCWR;
477 /* the file may be open read only without ressource fork */
478 if ((access & OPENACC_RD))
479 ofork->of_flags |= AFPFORK_ACCRD;
481 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
487 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
491 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
495 uint16_t ofrefnum, bitmap;
503 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
504 ibuf += sizeof( ofrefnum );
506 memcpy(&bitmap, ibuf, sizeof(bitmap));
507 bitmap = ntohs(bitmap);
508 ibuf += sizeof( bitmap );
511 if (NULL == ( ofork = of_find( ofrefnum )) ) {
512 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
513 return( AFPERR_PARAM );
516 if (ofork->of_vol->v_flags & AFPVOL_RO)
519 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
520 return AFPERR_ACCESS;
522 if ( ofork->of_flags & AFPFORK_DATA) {
524 } else if (ofork->of_flags & AFPFORK_RSRC) {
529 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
530 && eid == ADEID_RFORK
532 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
533 && eid == ADEID_DFORK)) {
534 return AFPERR_BITMAP;
538 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
539 if (afp_version >= 30) {
543 return AFPERR_BITMAP;
546 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
547 return AFPERR_PARAM ;
549 size = get_off_t(&ibuf, is64);
552 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
555 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
556 st_size = ad_size(ofork->of_ad, eid);
558 if (st_size > size &&
559 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
560 goto afp_setfork_err;
562 err = ad_dtruncate( ofork->of_ad, size );
564 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
566 goto afp_setfork_err;
567 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
568 ad_refresh( ofork->of_ad );
570 st_size = ad_size(ofork->of_ad, eid);
572 if (st_size > size &&
573 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
574 goto afp_setfork_err;
576 err = ad_rtruncate(ofork->of_ad, size);
578 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
580 goto afp_setfork_err;
582 if (ad_flush( ofork->of_ad ) < 0) {
583 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
587 return AFPERR_BITMAP;
590 if ( flushfork( ofork ) < 0 ) {
591 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
606 return AFPERR_ACCESS;
617 /* for this to work correctly, we need to check for locks before each
618 * read and write. that's most easily handled by always doing an
619 * appropriate check before each ad_read/ad_write. other things
620 * that can change files like truncate are handled internally to those
623 #define ENDBIT(a) ((a) & 0x80)
624 #define UNLOCKBIT(a) ((a) & 0x01)
627 /* ---------------------- */
628 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
631 off_t offset, length;
639 /* figure out parameters */
641 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
643 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
644 ibuf += sizeof(ofrefnum);
646 if (NULL == ( ofork = of_find( ofrefnum )) ) {
647 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
648 return( AFPERR_PARAM );
651 if ( ofork->of_flags & AFPFORK_DATA) {
653 } else if (ofork->of_flags & AFPFORK_RSRC) {
658 offset = get_off_t(&ibuf, is64);
659 length = get_off_t(&ibuf, is64);
661 /* FIXME AD_FILELOCK test is surely wrong */
663 length = BYTELOCK_MAX;
664 else if (!length || is_neg(is64, length)) {
666 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
671 offset += ad_size(ofork->of_ad, eid);
672 /* FIXME what do we do if file size > 2 GB and
673 it's not byte_lock_ext?
676 if (offset < 0) /* error if we have a negative offset */
679 /* if the file is a read-only file, we use read locks instead of
680 * write locks. that way, we can prevent anyone from initiating
682 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
683 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
684 ofork->of_refnum) < 0) {
688 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
694 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
702 *rbuflen = set_off_t (offset, rbuf, is64);
706 /* --------------------------- */
707 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
709 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
712 /* --------------------------- */
713 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
715 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
720 /* --------------------------- */
721 static int crlf(struct ofork *of)
725 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
726 /* no resource fork or no finderinfo, use our files extension mapping */
727 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
730 /* file type is TEXT */
733 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
740 static ssize_t read_file(struct ofork *ofork, int eid,
741 off_t offset, u_char nlmask,
742 u_char nlchar, char *rbuf,
743 size_t *rbuflen, const int xlate)
749 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
751 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
753 return( AFPERR_PARAM );
755 if ( (size_t)cc < *rbuflen ) {
763 for ( p = rbuf, q = p + cc; p < q; ) {
764 if (( *p++ & nlmask ) == nlchar ) {
775 * If this file is of type TEXT, then swap \012 to \015.
778 for ( p = rbuf, q = p + cc; p < q; p++ ) {
779 if ( *p == '\012' ) {
781 } else if ( *p == '\015' ) {
790 return( AFPERR_EOF );
795 /* -----------------------------
796 * with ddp, afp_read can return fewer bytes than in reqcount
797 * so return EOF only if read actually past end of file not
798 * if offset +reqcount > size of file
800 * getfork size ==> 10430
801 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
802 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
803 * read fork offset 9248 size 1508 ==> 1182 (EOF)
804 * 10752 is a bug in Mac 7.5.x finder
806 * with dsi, should we check that reqcount < server quantum?
808 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
811 off_t offset, saveoff, reqcount, savereqcount;
815 u_char nlmask, nlchar;
818 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
819 ibuf += sizeof( u_short );
821 if (NULL == ( ofork = of_find( ofrefnum )) ) {
822 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
827 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
831 offset = get_off_t(&ibuf, is64);
832 reqcount = get_off_t(&ibuf, is64);
834 LOG(log_debug, logtype_afpd,
835 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
836 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
845 /* if we wanted to be picky, we could add in the following
846 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
848 if (reqcount < 0 || offset < 0) {
853 if ( ofork->of_flags & AFPFORK_DATA) {
855 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
856 } else if (ofork->of_flags & AFPFORK_RSRC) {
858 } else { /* fork wasn't opened. this should never really happen. */
863 /* zero request count */
869 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
870 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
872 savereqcount = reqcount;
874 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
879 *rbuflen = MIN(reqcount, *rbuflen);
880 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
881 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
883 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
886 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
887 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
889 /* dsi can stream requests. we can only do this if we're not checking
890 * for an end-of-line character. oh well. */
891 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
892 DSI *dsi = obj->handle;
895 /* reqcount isn't always truthful. we need to deal with that. */
896 size = ad_size(ofork->of_ad, eid);
898 /* subtract off the offset */
900 if (reqcount > size) {
907 /* dsi_readinit() returns size of next read buffer. by this point,
908 * we know that we're sending some data. if we fail, something
909 * horrible happened. */
910 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
913 /* due to the nature of afp packets, we have to exit if we get
914 an error. we can't do this with translation on. */
919 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
921 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
922 if (errno == EINVAL || errno == ENOSYS)
925 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
937 /* fill up our buffer. */
938 while (*rbuflen > 0) {
939 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
944 /* dsi_read() also returns buffer size of next allocation */
945 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
954 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
956 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
957 obj->exit(EXITERR_CLNT);
961 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
969 /* ---------------------- */
970 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
972 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
975 /* ---------------------- */
976 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
978 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
981 /* ---------------------- */
982 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
990 memcpy(&vid, ibuf, sizeof(vid));
991 if (NULL == ( vol = getvolbyvid( vid )) ) {
992 return( AFPERR_PARAM );
999 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1001 struct ofork *ofork;
1006 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1008 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1009 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1010 return( AFPERR_PARAM );
1013 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
1014 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1016 if ( flushfork( ofork ) < 0 ) {
1017 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1025 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1026 fsync(2) on OSX is implemented differently than on other platforms.
1027 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1029 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1031 struct ofork *ofork;
1037 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1038 ibuf += sizeof( ofrefnum );
1040 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1041 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1042 return( AFPERR_PARAM );
1045 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1046 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1048 if ( flushfork( ofork ) < 0 ) {
1049 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1056 /* this is very similar to closefork */
1057 int flushfork(struct ofork *ofork)
1061 int err = 0, doflush = 0;
1063 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1064 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1065 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1066 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1070 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1071 (ofork->of_flags & AFPFORK_RSRC)) {
1073 /* read in the rfork length */
1074 ad_refresh(ofork->of_ad);
1076 /* set the date if we're dirty */
1077 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1078 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1079 ofork->of_flags &= ~AFPFORK_DIRTY;
1083 /* flush the header */
1084 if (doflush && ad_flush(ofork->of_ad) < 0)
1087 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1091 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1092 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1098 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1100 struct ofork *ofork;
1105 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1107 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1108 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1109 return( AFPERR_PARAM );
1112 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1113 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1115 if ( of_closefork( ofork ) < 0 ) {
1116 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1117 return( AFPERR_PARAM );
1124 static ssize_t write_file(struct ofork *ofork, int eid,
1125 off_t offset, char *rbuf,
1126 size_t rbuflen, const int xlate)
1132 * If this file is of type TEXT, swap \015 to \012.
1135 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1136 if ( *p == '\015' ) {
1138 } else if ( *p == '\012' ) {
1144 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1145 rbuf, rbuflen)) < 0 ) {
1150 return( AFPERR_DFULL );
1152 return AFPERR_ACCESS;
1154 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1155 return( AFPERR_PARAM );
1163 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1164 * the client may have sent us a bunch of data that's not reflected
1165 * in reqcount et al. */
1166 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1168 struct ofork *ofork;
1169 off_t offset, saveoff, reqcount, oldsize, newsize;
1170 int endflag, eid, xlate = 0, err = AFP_OK;
1174 /* figure out parameters */
1176 endflag = ENDBIT(*ibuf);
1178 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1179 ibuf += sizeof( ofrefnum );
1181 offset = get_off_t(&ibuf, is64);
1182 reqcount = get_off_t(&ibuf, is64);
1184 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1185 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1190 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1191 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1193 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1194 err = AFPERR_ACCESS;
1199 writtenfork = ofork;
1202 if ( ofork->of_flags & AFPFORK_DATA) {
1204 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1205 } else if (ofork->of_flags & AFPFORK_RSRC) {
1208 err = AFPERR_ACCESS; /* should never happen */
1212 oldsize = ad_size(ofork->of_ad, eid);
1216 /* handle bogus parameters */
1217 if (reqcount < 0 || offset < 0) {
1222 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1224 /* offset can overflow on 64-bit capable filesystems.
1225 * report disk full if that's going to happen. */
1226 if (sum_neg(is64, offset, reqcount)) {
1231 if (!reqcount) { /* handle request counts of 0 */
1233 *rbuflen = set_off_t (offset, rbuf, is64);
1238 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1239 reqcount, ofork->of_refnum) < 0) {
1244 /* this is yucky, but dsi can stream i/o and asp can't */
1245 switch (obj->proto) {
1248 DSI *dsi = obj->handle;
1250 /* find out what we have already and write it out. */
1251 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1252 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1253 dsi_writeflush(dsi);
1255 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1260 #if 0 /*def HAVE_SENDFILE_WRITE*/
1261 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1262 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1263 offset, dsi->datasize)) < 0) {
1271 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1272 goto afp_write_loop;
1274 dsi_writeflush(dsi);
1276 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1277 reqcount, ofork->of_refnum);
1282 goto afp_write_done;
1284 #endif /* 0, was HAVE_SENDFILE_WRITE */
1286 /* loop until everything gets written. currently
1287 * dsi_write handles the end case by itself. */
1288 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1289 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1290 dsi_writeflush(dsi);
1292 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1293 reqcount, ofork->of_refnum);
1302 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1303 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1304 ofork->of_flags |= AFPFORK_DIRTY;
1306 /* we have modified any fork, remember until close_fork */
1307 ofork->of_flags |= AFPFORK_MODIFIED;
1309 /* update write count */
1310 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1312 *rbuflen = set_off_t (offset, rbuf, is64);
1316 if (obj->proto == AFPPROTO_DSI) {
1317 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1318 dsi_writeflush(obj->handle);
1320 if (err != AFP_OK) {
1326 /* ---------------------------- */
1327 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1329 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1332 /* ----------------------------
1333 * FIXME need to deal with SIGXFSZ signal
1335 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1337 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1340 /* ---------------------------- */
1341 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1343 struct ofork *ofork;
1345 uint16_t ofrefnum, bitmap;
1348 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1349 ibuf += sizeof( ofrefnum );
1350 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1351 bitmap = ntohs( bitmap );
1352 ibuf += sizeof( bitmap );
1355 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1356 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1357 return( AFPERR_PARAM );
1360 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1361 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1362 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1363 return( AFPERR_PARAM );
1367 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1368 rbuf + sizeof( u_short ), &buflen ))) {
1372 *rbuflen = buflen + sizeof( u_short );
1373 bitmap = htons( bitmap );
1374 memcpy(rbuf, &bitmap, sizeof( bitmap ));