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>
27 #include <atalk/netatalk_conf.h>
32 #include "directory.h"
37 struct ofork *writtenfork;
40 static int getforkparams(const AFPObj *obj, struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen)
50 /* can only get the length of the opened fork */
51 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
52 && (ofork->of_flags & AFPFORK_RSRC))
54 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
55 && (ofork->of_flags & AFPFORK_DATA))) {
56 return( AFPERR_BITMAP );
59 if (! AD_META_OPEN(ofork->of_ad)) {
66 dir = dirlookup(vol, ofork->of_did);
68 if (NULL == (path.m_name = utompath(vol, of_name(ofork), dir->d_did, utf8_encoding(obj)))) {
69 return( AFPERR_MISC );
71 path.u_name = of_name(ofork);
74 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
75 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
76 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
77 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
78 /* 0 is for symlink */
79 if (movecwd(vol, dir) < 0)
80 return( AFPERR_NOOBJ );
81 if ( lstat( path.u_name, st ) < 0 )
82 return( AFPERR_NOOBJ );
84 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
85 return( AFPERR_BITMAP );
89 return getmetadata(obj, vol, bitmap, &path, dir, buf, buflen, adp );
92 static off_t get_off_t(char **ibuf, int is64)
98 memcpy(&temp, *ibuf, sizeof( temp ));
99 ret = ntohl(temp); /* ntohl is unsigned */
100 *ibuf += sizeof(temp);
103 memcpy(&temp, *ibuf, sizeof( temp ));
104 *ibuf += sizeof(temp);
105 ret = ntohl(temp)| (ret << 32);
108 ret = (int)ret; /* sign extend */
113 static int set_off_t(off_t offset, char *rbuf, int is64)
120 temp = htonl(offset >> 32);
121 memcpy(rbuf, &temp, sizeof( temp ));
122 rbuf += sizeof(temp);
123 ret = sizeof( temp );
124 offset &= 0xffffffff;
126 temp = htonl(offset);
127 memcpy(rbuf, &temp, sizeof( temp ));
128 ret += sizeof( temp );
133 static int is_neg(int is64, off_t val)
135 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
140 static int sum_neg(int is64, off_t offset, off_t reqcount)
142 if (is_neg(is64, offset +reqcount) )
147 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
158 shmd.f_access = (access & OPENACC_RD ? F_RDACC : 0) | (access & OPENACC_WR ? F_WRACC : 0);
159 if (shmd.f_access == 0)
160 /* we must give an access mode, otherwise fcntl will complain */
161 shmd.f_access = F_RDACC;
162 shmd.f_deny = (access & OPENACC_DRD ? F_RDDNY : F_NODNY) | (access & OPENACC_DWR) ? F_WRDNY : 0;
163 shmd.f_id = ofrefnum;
165 int fd = (eid == ADEID_DFORK) ? ad_data_fileno(adp) : ad_reso_fileno(adp);
167 if (fd != -1 && fd != -2 && fcntl(fd, F_SHARE, &shmd) != 0) {
168 LOG(log_debug, logtype_afpd, "fork_setmode: fcntl: %s", strerror(errno));
174 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
175 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
178 if ((access & (OPENACC_RD | OPENACC_DRD))) {
179 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
181 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
184 if ((access & OPENACC_RD) && denyreadset) {
188 if ((access & OPENACC_DRD) && readset) {
192 /* boolean logic is not enough, because getforkmode is not always telling the
195 if ((access & OPENACC_RD)) {
196 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
200 if ((access & OPENACC_DRD)) {
201 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
206 /* ------------same for writing -------------- */
207 if ((access & (OPENACC_WR | OPENACC_DWR))) {
208 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
210 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
213 if ((access & OPENACC_WR) && denywriteset) {
217 if ((access & OPENACC_DWR) && writeset) {
221 if ((access & OPENACC_WR)) {
222 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
226 if ((access & OPENACC_DWR)) {
227 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
236 /* ----------------------- */
237 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
241 struct ofork *ofork, *opened;
242 struct adouble *adsame = NULL;
244 int ret, adflags, eid;
246 uint16_t vid, bitmap, access, ofrefnum;
247 char fork, *path, *upath;
255 memcpy(&vid, ibuf, sizeof( vid ));
259 if (NULL == ( vol = getvolbyvid( vid ))) {
260 return( AFPERR_PARAM );
263 memcpy(&did, ibuf, sizeof( did ));
264 ibuf += sizeof( int );
266 if (NULL == ( dir = dirlookup( vol, did ))) {
270 memcpy(&bitmap, ibuf, sizeof( bitmap ));
271 bitmap = ntohs( bitmap );
272 ibuf += sizeof( bitmap );
273 memcpy(&access, ibuf, sizeof( access ));
274 access = ntohs( access );
275 ibuf += sizeof( access );
277 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
281 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
282 return get_afp_errno(AFPERR_PARAM);
285 if (*s_path->m_name == '\0') {
287 return AFPERR_BADTYPE;
290 /* stat() data fork st is set because it's not a dir */
291 switch ( s_path->st_errno ) {
297 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
299 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
302 /* FIXME should we check it first ? */
303 upath = s_path->u_name;
304 if (!vol_unix_priv(vol)) {
305 if (check_access(obj, vol, upath, access ) < 0) {
306 return AFPERR_ACCESS;
309 if (file_access(obj, vol, s_path, access ) < 0) {
310 return AFPERR_ACCESS;
315 /* XXX: this probably isn't the best way to do this. the already
316 open bits should really be set if the fork is opened by any
317 program, not just this one. however, that's problematic to do
318 if we can't write lock files somewhere. opened is also passed to
319 ad_open so that we can keep file locks together.
320 FIXME: add the fork we are opening?
322 if ((opened = of_findname(s_path))) {
323 adsame = opened->of_ad;
326 if ( fork == OPENFORK_DATA ) {
328 adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF;
331 adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF;
332 if (!(access & OPENACC_WR))
333 adflags |= ADFLAGS_NORF;
336 path = s_path->m_name;
337 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
338 adsame, st)) == NULL ) {
339 return( AFPERR_NFILE );
342 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
343 fullpathname(s_path->u_name),
344 (fork == OPENFORK_DATA) ? "data" : "reso",
345 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
348 if (access & OPENACC_WR) {
349 /* try opening in read-write mode */
350 if (ad_open(ofork->of_ad, upath,
351 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
358 if (fork == OPENFORK_DATA) {
359 /* try to open only the data fork */
360 if (ad_open(ofork->of_ad, upath,
361 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
364 adflags = ADFLAGS_DF;
366 /* here's the deal. we only try to create the resource
367 * fork if the user wants to open it for write acess. */
368 if (ad_open(ofork->of_ad, upath,
369 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
371 ofork->of_flags |= AFPFORK_META;
379 ret = AFPERR_BADTYPE;
382 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
388 /* the ressource fork is open too */
389 ofork->of_flags |= AFPFORK_META;
392 /* try opening in read-only mode */
394 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
402 /* see if client asked for a read only data fork */
403 if (fork == OPENFORK_DATA) {
404 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
407 adflags = ADFLAGS_DF;
409 /* else we don't set AFPFORK_META because there's no ressource fork file
410 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
411 * then create in open read-write.
412 * FIXME , it doesn't play well with byte locking example:
413 * ressource fork open read only
414 * locking set on it (no effect, there's no file!)
415 * ressource fork open read write now
423 ret = AFPERR_BADTYPE;
426 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
427 fullpathname(s_path->m_name), strerror(errno) );
431 ofork->of_flags |= AFPFORK_META;
435 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
436 if (ad_setname(ofork->of_ad, path)) {
437 ad_flush( ofork->of_ad );
441 if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
442 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
446 *rbuflen = buflen + 2 * sizeof( uint16_t );
447 bitmap = htons( bitmap );
448 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
449 rbuf += sizeof( uint16_t );
451 /* check WriteInhibit bit if we have a ressource fork
452 * the test is done here, after some Mac trafic capture
454 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
455 ad_getattr(ofork->of_ad, &bshort);
456 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
457 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
460 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
461 return(AFPERR_OLOCK);
466 * synchronization locks:
469 /* don't try to lock non-existent rforks. */
470 if ((eid == ADEID_DFORK)
471 || (ad_reso_fileno(ofork->of_ad) != -1)
472 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
473 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
474 /* can we access the fork? */
476 ofork->of_flags |= AFPFORK_ERROR;
478 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
481 case EAGAIN: /* return data anyway */
485 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
486 return( AFPERR_DENYCONF );
490 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
491 return( AFPERR_PARAM );
494 if ((access & OPENACC_WR))
495 ofork->of_flags |= AFPFORK_ACCWR;
497 /* the file may be open read only without ressource fork */
498 if ((access & OPENACC_RD))
499 ofork->of_flags |= AFPFORK_ACCRD;
501 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
507 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
511 int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
515 uint16_t ofrefnum, bitmap;
523 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
524 ibuf += sizeof( ofrefnum );
526 memcpy(&bitmap, ibuf, sizeof(bitmap));
527 bitmap = ntohs(bitmap);
528 ibuf += sizeof( bitmap );
531 if (NULL == ( ofork = of_find( ofrefnum )) ) {
532 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
533 return( AFPERR_PARAM );
536 if (ofork->of_vol->v_flags & AFPVOL_RO)
539 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
540 return AFPERR_ACCESS;
542 if ( ofork->of_flags & AFPFORK_DATA) {
544 } else if (ofork->of_flags & AFPFORK_RSRC) {
549 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
550 && eid == ADEID_RFORK
552 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
553 && eid == ADEID_DFORK)) {
554 return AFPERR_BITMAP;
558 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
559 if (obj->afp_version >= 30) {
563 return AFPERR_BITMAP;
566 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
567 return AFPERR_PARAM ;
569 size = get_off_t(&ibuf, is64);
572 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
575 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
576 st_size = ad_size(ofork->of_ad, eid);
578 if (st_size > size &&
579 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
580 goto afp_setfork_err;
582 err = ad_dtruncate( ofork->of_ad, size );
584 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
586 goto afp_setfork_err;
587 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
588 ad_refresh(NULL, ofork->of_ad );
590 st_size = ad_size(ofork->of_ad, eid);
592 if (st_size > size &&
593 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
594 goto afp_setfork_err;
597 err = ad_rtruncate(ofork->of_ad, size);
599 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
601 goto afp_setfork_err;
603 if (ad_flush( ofork->of_ad ) < 0) {
604 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
608 return AFPERR_BITMAP;
611 if ( flushfork( ofork ) < 0 ) {
612 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
627 return AFPERR_ACCESS;
638 /* for this to work correctly, we need to check for locks before each
639 * read and write. that's most easily handled by always doing an
640 * appropriate check before each ad_read/ad_write. other things
641 * that can change files like truncate are handled internally to those
644 #define ENDBIT(a) ((a) & 0x80)
645 #define UNLOCKBIT(a) ((a) & 0x01)
648 /* ---------------------- */
649 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
652 off_t offset, length;
660 /* figure out parameters */
662 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
664 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
665 ibuf += sizeof(ofrefnum);
667 if (NULL == ( ofork = of_find( ofrefnum )) ) {
668 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
669 return( AFPERR_PARAM );
672 if ( ofork->of_flags & AFPFORK_DATA) {
674 } else if (ofork->of_flags & AFPFORK_RSRC) {
679 offset = get_off_t(&ibuf, is64);
680 length = get_off_t(&ibuf, is64);
683 length = BYTELOCK_MAX;
684 else if (!length || is_neg(is64, length)) {
686 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
691 offset += ad_size(ofork->of_ad, eid);
692 /* FIXME what do we do if file size > 2 GB and
693 it's not byte_lock_ext?
696 if (offset < 0) /* error if we have a negative offset */
699 /* if the file is a read-only file, we use read locks instead of
700 * write locks. that way, we can prevent anyone from initiating
702 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
703 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
704 ofork->of_refnum) < 0) {
708 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
714 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
722 *rbuflen = set_off_t (offset, rbuf, is64);
726 /* --------------------------- */
727 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
729 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
732 /* --------------------------- */
733 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
735 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
740 static ssize_t read_file(struct ofork *ofork, int eid,
741 off_t offset, u_char nlmask,
742 u_char nlchar, char *rbuf,
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 ) {
776 return( AFPERR_EOF );
781 /* -----------------------------
782 * with ddp, afp_read can return fewer bytes than in reqcount
783 * so return EOF only if read actually past end of file not
784 * if offset +reqcount > size of file
786 * getfork size ==> 10430
787 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
788 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
789 * read fork offset 9248 size 1508 ==> 1182 (EOF)
790 * 10752 is a bug in Mac 7.5.x finder
792 * with dsi, should we check that reqcount < server quantum?
794 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
797 off_t offset, saveoff, reqcount, savereqcount;
801 u_char nlmask, nlchar;
804 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
805 ibuf += sizeof( u_short );
807 if (NULL == ( ofork = of_find( ofrefnum )) ) {
808 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
813 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
817 offset = get_off_t(&ibuf, is64);
818 reqcount = get_off_t(&ibuf, is64);
820 LOG(log_debug, logtype_afpd,
821 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
822 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
831 /* if we wanted to be picky, we could add in the following
832 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
834 if (reqcount < 0 || offset < 0) {
839 if ( ofork->of_flags & AFPFORK_DATA) {
841 } else if (ofork->of_flags & AFPFORK_RSRC) {
843 } else { /* fork wasn't opened. this should never really happen. */
848 /* zero request count */
854 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
855 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
857 savereqcount = reqcount;
859 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
864 *rbuflen = MIN(reqcount, *rbuflen);
865 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
866 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
868 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen);
871 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
872 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
874 /* dsi can stream requests. we can only do this if we're not checking
875 * for an end-of-line character. oh well. */
876 if ((*rbuflen < reqcount) && !nlmask) {
880 /* reqcount isn't always truthful. we need to deal with that. */
881 size = ad_size(ofork->of_ad, eid);
883 /* subtract off the offset */
885 if (reqcount > size) {
892 /* dsi_readinit() returns size of next read buffer. by this point,
893 * we know that we're sending some data. if we fail, something
894 * horrible happened. */
895 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
898 /* due to the nature of afp packets, we have to exit if we get
899 an error. we can't do this with translation on. */
901 if (!(obj->options.flags & OPTION_NOSENDFILE)) {
902 int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
903 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
909 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
920 /* fill up our buffer. */
921 while (*rbuflen > 0) {
922 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen);
927 /* dsi_read() also returns buffer size of next allocation */
928 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
937 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
939 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
940 obj->exit(EXITERR_CLNT);
944 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
952 /* ---------------------- */
953 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
955 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
958 /* ---------------------- */
959 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
961 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
964 /* ---------------------- */
965 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
973 memcpy(&vid, ibuf, sizeof(vid));
974 if (NULL == ( vol = getvolbyvid( vid )) ) {
975 return( AFPERR_PARAM );
982 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
989 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
991 if (NULL == ( ofork = of_find( ofrefnum )) ) {
992 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
993 return( AFPERR_PARAM );
996 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
997 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
999 if ( flushfork( ofork ) < 0 ) {
1000 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1008 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1009 fsync(2) on OSX is implemented differently than on other platforms.
1010 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1012 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1014 struct ofork *ofork;
1020 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1021 ibuf += sizeof( ofrefnum );
1023 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1024 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1025 return( AFPERR_PARAM );
1028 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1029 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1031 if ( flushfork( ofork ) < 0 ) {
1032 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1039 /* this is very similar to closefork */
1040 int flushfork(struct ofork *ofork)
1044 int err = 0, doflush = 0;
1046 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1047 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1048 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1049 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1053 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1054 (ofork->of_flags & AFPFORK_RSRC)) {
1056 /* read in the rfork length */
1057 ad_refresh(NULL, ofork->of_ad);
1059 /* set the date if we're dirty */
1060 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1061 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1062 ofork->of_flags &= ~AFPFORK_DIRTY;
1066 /* flush the header */
1067 if (doflush && ad_flush(ofork->of_ad) < 0)
1070 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1074 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1075 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1081 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1083 struct ofork *ofork;
1088 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1090 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1091 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1092 return( AFPERR_PARAM );
1095 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1096 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1098 #ifdef HAVE_FSHARE_T
1100 shmd.f_id = ofork->of_refnum;
1101 if (AD_DATA_OPEN(ofork->of_ad))
1102 fcntl(ad_data_fileno(ofork->of_ad), F_UNSHARE, &shmd);
1103 if (AD_RSRC_OPEN(ofork->of_ad))
1104 fcntl(ad_reso_fileno(ofork->of_ad), F_UNSHARE, &shmd);
1107 if ( of_closefork( ofork ) < 0 ) {
1108 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1109 return( AFPERR_PARAM );
1116 static ssize_t write_file(struct ofork *ofork, int eid,
1117 off_t offset, char *rbuf,
1123 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1124 (uintmax_t)offset, rbuflen);
1126 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1127 rbuf, rbuflen)) < 0 ) {
1132 return( AFPERR_DFULL );
1134 return AFPERR_ACCESS;
1136 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1137 return( AFPERR_PARAM );
1145 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1146 * the client may have sent us a bunch of data that's not reflected
1147 * in reqcount et al. */
1148 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1150 struct ofork *ofork;
1151 off_t offset, saveoff, reqcount, oldsize, newsize;
1152 int endflag, eid, err = AFP_OK;
1156 /* figure out parameters */
1158 endflag = ENDBIT(*ibuf);
1160 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1161 ibuf += sizeof( ofrefnum );
1163 offset = get_off_t(&ibuf, is64);
1164 reqcount = get_off_t(&ibuf, is64);
1166 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1167 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1172 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1173 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1175 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1176 err = AFPERR_ACCESS;
1181 writtenfork = ofork;
1184 if ( ofork->of_flags & AFPFORK_DATA) {
1186 } else if (ofork->of_flags & AFPFORK_RSRC) {
1189 err = AFPERR_ACCESS; /* should never happen */
1193 oldsize = ad_size(ofork->of_ad, eid);
1197 /* handle bogus parameters */
1198 if (reqcount < 0 || offset < 0) {
1203 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1205 /* offset can overflow on 64-bit capable filesystems.
1206 * report disk full if that's going to happen. */
1207 if (sum_neg(is64, offset, reqcount)) {
1212 if (!reqcount) { /* handle request counts of 0 */
1214 *rbuflen = set_off_t (offset, rbuf, is64);
1219 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1220 reqcount, ofork->of_refnum) < 0) {
1225 DSI *dsi = obj->dsi;
1226 /* find out what we have already and write it out. */
1227 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1229 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1230 dsi_writeflush(dsi);
1232 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1238 #if 0 /*def HAVE_SENDFILE_WRITE*/
1239 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1240 offset, dsi->datasize)) < 0) {
1248 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1249 goto afp_write_loop;
1251 dsi_writeflush(dsi);
1253 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1254 reqcount, ofork->of_refnum);
1259 goto afp_write_done;
1260 #endif /* 0, was HAVE_SENDFILE_WRITE */
1262 /* loop until everything gets written. currently
1263 * dsi_write handles the end case by itself. */
1264 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1265 if ((cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1266 dsi_writeflush(dsi);
1268 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1269 reqcount, ofork->of_refnum);
1275 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1276 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1277 ofork->of_flags |= AFPFORK_DIRTY;
1279 /* we have modified any fork, remember until close_fork */
1280 ofork->of_flags |= AFPFORK_MODIFIED;
1282 /* update write count */
1283 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1285 *rbuflen = set_off_t (offset, rbuf, is64);
1289 dsi_writeinit(obj->dsi, rbuf, *rbuflen);
1290 dsi_writeflush(obj->dsi);
1292 if (err != AFP_OK) {
1298 /* ---------------------------- */
1299 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1301 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1304 /* ----------------------------
1305 * FIXME need to deal with SIGXFSZ signal
1307 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1309 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1312 /* ---------------------------- */
1313 int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1315 struct ofork *ofork;
1317 uint16_t ofrefnum, bitmap;
1320 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1321 ibuf += sizeof( ofrefnum );
1322 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1323 bitmap = ntohs( bitmap );
1324 ibuf += sizeof( bitmap );
1327 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1328 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1329 return( AFPERR_PARAM );
1332 if (AD_META_OPEN(ofork->of_ad)) {
1333 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1334 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1335 return( AFPERR_PARAM );
1339 if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1343 *rbuflen = buflen + sizeof( u_short );
1344 bitmap = htons( bitmap );
1345 memcpy(rbuf, &bitmap, sizeof( bitmap ));