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/bstrlib.h>
26 #include <atalk/bstradd.h>
27 #include <atalk/globals.h>
28 #include <atalk/netatalk_conf.h>
33 #include "directory.h"
38 struct ofork *writtenfork;
41 static int getforkparams(const AFPObj *obj, struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen)
51 /* can only get the length of the opened fork */
52 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
53 && (ofork->of_flags & AFPFORK_RSRC))
55 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
56 && (ofork->of_flags & AFPFORK_DATA))) {
57 return( AFPERR_BITMAP );
60 if (! AD_META_OPEN(ofork->of_ad)) {
67 dir = dirlookup(vol, ofork->of_did);
69 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding(obj)))) {
70 return( AFPERR_MISC );
72 path.m_name = of_name(ofork);
75 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
76 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
77 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
78 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
79 /* 0 is for symlink */
80 if (movecwd(vol, dir) < 0)
81 return( AFPERR_NOOBJ );
82 if ( lstat( path.u_name, st ) < 0 )
83 return( AFPERR_NOOBJ );
85 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
86 return( AFPERR_BITMAP );
90 return getmetadata(obj, vol, bitmap, &path, dir, buf, buflen, adp );
93 static off_t get_off_t(char **ibuf, int is64)
99 memcpy(&temp, *ibuf, sizeof( temp ));
100 ret = ntohl(temp); /* ntohl is unsigned */
101 *ibuf += sizeof(temp);
104 memcpy(&temp, *ibuf, sizeof( temp ));
105 *ibuf += sizeof(temp);
106 ret = ntohl(temp)| (ret << 32);
109 ret = (int)ret; /* sign extend */
114 static int set_off_t(off_t offset, char *rbuf, int is64)
121 temp = htonl(offset >> 32);
122 memcpy(rbuf, &temp, sizeof( temp ));
123 rbuf += sizeof(temp);
124 ret = sizeof( temp );
125 offset &= 0xffffffff;
127 temp = htonl(offset);
128 memcpy(rbuf, &temp, sizeof( temp ));
129 ret += sizeof( temp );
134 static int is_neg(int is64, off_t val)
136 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
141 static int sum_neg(int is64, off_t offset, off_t reqcount)
143 if (is_neg(is64, offset +reqcount) )
148 static int fork_setmode(const AFPObj *obj, struct adouble *adp, int eid, int access, int ofrefnum)
156 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
157 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
160 if ((access & (OPENACC_RD | OPENACC_DRD))) {
161 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
163 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
166 if ((access & OPENACC_RD) && denyreadset) {
170 if ((access & OPENACC_DRD) && readset) {
174 /* boolean logic is not enough, because getforkmode is not always telling the
177 if ((access & OPENACC_RD)) {
178 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
182 if ((access & OPENACC_DRD)) {
183 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
188 /* ------------same for writing -------------- */
189 if ((access & (OPENACC_WR | OPENACC_DWR))) {
190 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
192 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
195 if ((access & OPENACC_WR) && denywriteset) {
199 if ((access & OPENACC_DWR) && writeset) {
203 if ((access & OPENACC_WR)) {
204 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
208 if ((access & OPENACC_DWR)) {
209 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
216 * Fix for Bug 560: put the Solaris share reservation after our locking stuff.
217 * Note that this still leaves room for a race condition where between placing our own
218 * locks above and putting the Solaris share move below another client puts a lock.
219 * We then end up with set locks from above and return with an error code, the proper
220 * fix requires a sane cleanup function for the error path in this function.
226 if (obj->options.flags & OPTION_SHARE_RESERV) {
227 shmd.f_access = (access & OPENACC_RD ? F_RDACC : 0) | (access & OPENACC_WR ? F_WRACC : 0);
228 if (shmd.f_access == 0)
229 /* we must give an access mode, otherwise fcntl will complain */
230 shmd.f_access = F_RDACC;
231 shmd.f_deny = (access & OPENACC_DRD ? F_RDDNY : F_NODNY) | (access & OPENACC_DWR) ? F_WRDNY : 0;
232 shmd.f_id = ofrefnum;
234 int fd = (eid == ADEID_DFORK) ? ad_data_fileno(adp) : ad_reso_fileno(adp);
236 if (fd != -1 && fd != AD_SYMLINK && fcntl(fd, F_SHARE, &shmd) != 0) {
237 LOG(log_debug, logtype_afpd, "fork_setmode: fcntl: %s", strerror(errno));
247 /* ----------------------- */
248 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
252 struct ofork *ofork, *opened;
253 struct adouble *adsame = NULL;
255 int ret, adflags, eid;
257 uint16_t vid, bitmap, access, ofrefnum;
258 char fork, *path, *upath;
265 memcpy(&vid, ibuf, sizeof( vid ));
269 if (NULL == ( vol = getvolbyvid( vid ))) {
270 return( AFPERR_PARAM );
273 memcpy(&did, ibuf, sizeof( did ));
274 ibuf += sizeof( int );
276 if (NULL == ( dir = dirlookup( vol, did ))) {
280 memcpy(&bitmap, ibuf, sizeof( bitmap ));
281 bitmap = ntohs( bitmap );
282 ibuf += sizeof( bitmap );
283 memcpy(&access, ibuf, sizeof( access ));
284 access = ntohs( access );
285 ibuf += sizeof( access );
287 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
291 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
292 return get_afp_errno(AFPERR_PARAM);
295 if (*s_path->m_name == '\0') {
297 return AFPERR_BADTYPE;
300 /* stat() data fork st is set because it's not a dir */
301 switch ( s_path->st_errno ) {
307 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
309 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
313 upath = s_path->u_name;
314 path = s_path->m_name;
317 if (!vol_unix_priv(vol)) {
318 if (check_access(obj, vol, upath, access ) < 0) {
319 return AFPERR_ACCESS;
322 if (file_access(obj, vol, s_path, access ) < 0) {
323 return AFPERR_ACCESS;
327 if ((opened = of_findname(vol, s_path))) {
328 adsame = opened->of_ad;
331 adflags = ADFLAGS_SETSHRMD;
333 if (fork == OPENFORK_DATA) {
335 adflags |= ADFLAGS_DF;
338 adflags |= ADFLAGS_RF;
341 if (access & OPENACC_WR) {
342 adflags |= ADFLAGS_RDWR;
343 if (fork != OPENFORK_DATA)
345 * We only try to create the resource
346 * fork if the user wants to open it for write acess.
348 adflags |= ADFLAGS_CREATE;
350 adflags |= ADFLAGS_RDONLY;
353 if ((ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, adsame, st)) == NULL)
356 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
357 fullpathname(s_path->u_name),
358 (fork == OPENFORK_DATA) ? "data" : "reso",
359 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
363 /* First ad_open(), opens data or ressource fork */
364 if (ad_open(ofork->of_ad, upath, adflags, 0666) < 0) {
377 ret = AFPERR_BADTYPE;
380 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
387 * Create metadata if we open rw, otherwise only open existing metadata
389 if (access & OPENACC_WR) {
390 adflags = ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE;
392 adflags = ADFLAGS_HF | ADFLAGS_RDONLY;
395 if (ad_open(ofork->of_ad, upath, adflags, 0666) == 0) {
396 ofork->of_flags |= AFPFORK_META;
397 if (ad_get_MD_flags(ofork->of_ad) & O_CREAT) {
398 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): setting CNID", upath);
400 if ((id = get_id(vol, ofork->of_ad, st, dir->d_did, upath, strlen(upath))) == CNID_INVALID) {
401 LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): CNID error", upath);
404 (void)ad_setid(ofork->of_ad, st->st_dev, st->st_ino, id, dir->d_did, vol->v_stamp);
405 ad_flush(ofork->of_ad);
411 /* no metadata? We don't care! */
420 ret = AFPERR_BADTYPE;
423 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
429 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
430 if (ad_setname(ofork->of_ad, path)) {
431 ad_flush( ofork->of_ad );
435 if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
436 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
440 *rbuflen = buflen + 2 * sizeof( uint16_t );
441 bitmap = htons( bitmap );
442 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
443 rbuf += sizeof( uint16_t );
445 /* check WriteInhibit bit if we have a ressource fork
446 * the test is done here, after some Mac trafic capture
448 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
449 ad_getattr(ofork->of_ad, &bshort);
450 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
451 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
454 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
455 return(AFPERR_OLOCK);
460 * synchronization locks:
463 /* don't try to lock non-existent rforks. */
464 if ((eid == ADEID_DFORK)
465 || (ad_reso_fileno(ofork->of_ad) != -1)
466 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
467 ret = fork_setmode(obj, ofork->of_ad, eid, access, ofrefnum);
468 /* can we access the fork? */
470 ofork->of_flags |= AFPFORK_ERROR;
472 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
475 case EAGAIN: /* return data anyway */
479 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
480 return( AFPERR_DENYCONF );
484 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
485 return( AFPERR_PARAM );
488 if ((access & OPENACC_WR))
489 ofork->of_flags |= AFPFORK_ACCWR;
491 /* the file may be open read only without ressource fork */
492 if ((access & OPENACC_RD))
493 ofork->of_flags |= AFPFORK_ACCRD;
495 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): fork: %" PRIu16,
496 fullpathname(s_path->m_name), ofork->of_refnum);
498 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
504 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
508 int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
514 uint16_t ofrefnum, bitmap;
522 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
523 ibuf += sizeof( ofrefnum );
525 memcpy(&bitmap, ibuf, sizeof(bitmap));
526 bitmap = ntohs(bitmap);
527 ibuf += sizeof( bitmap );
530 if (NULL == ( ofork = of_find( ofrefnum )) ) {
531 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
532 return( AFPERR_PARAM );
536 if ((dir = dirlookup(vol, ofork->of_did)) == NULL) {
537 LOG(log_error, logtype_afpd, "%s: bad fork did", of_name(ofork));
540 if (movecwd(vol, dir) != 0) {
541 LOG(log_error, logtype_afpd, "%s: bad fork directory", dir->d_fullpath);
545 if (ofork->of_vol->v_flags & AFPVOL_RO)
548 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
549 return AFPERR_ACCESS;
551 if ( ofork->of_flags & AFPFORK_DATA) {
553 } else if (ofork->of_flags & AFPFORK_RSRC) {
558 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
559 && eid == ADEID_RFORK
561 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
562 && eid == ADEID_DFORK)) {
563 return AFPERR_BITMAP;
567 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
568 if (obj->afp_version >= 30) {
572 return AFPERR_BITMAP;
575 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
576 return AFPERR_PARAM ;
578 size = get_off_t(&ibuf, is64);
581 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
584 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
585 st_size = ad_size(ofork->of_ad, eid);
587 if (st_size > size &&
588 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
589 goto afp_setfork_err;
591 err = ad_dtruncate( ofork->of_ad, size );
593 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
595 goto afp_setfork_err;
596 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
597 ad_refresh(NULL, ofork->of_ad );
599 st_size = ad_size(ofork->of_ad, eid);
601 if (st_size > size &&
602 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
603 goto afp_setfork_err;
606 err = ad_rtruncate(ofork->of_ad, mtoupath(ofork->of_vol, of_name(ofork), ofork->of_did, utf8_encoding(obj)), size);
608 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
610 goto afp_setfork_err;
612 if (ad_flush( ofork->of_ad ) < 0) {
613 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
617 return AFPERR_BITMAP;
620 if ( flushfork( ofork ) < 0 ) {
621 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
636 return AFPERR_ACCESS;
640 LOG(log_error, logtype_afpd, "afp_setforkparams: DISK FULL");
648 /* for this to work correctly, we need to check for locks before each
649 * read and write. that's most easily handled by always doing an
650 * appropriate check before each ad_read/ad_write. other things
651 * that can change files like truncate are handled internally to those
654 #define ENDBIT(a) ((a) & 0x80)
655 #define UNLOCKBIT(a) ((a) & 0x01)
658 /* ---------------------- */
659 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
662 off_t offset, length;
670 /* figure out parameters */
672 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
674 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
675 ibuf += sizeof(ofrefnum);
677 if (NULL == ( ofork = of_find( ofrefnum )) ) {
678 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
679 return( AFPERR_PARAM );
682 if ( ofork->of_flags & AFPFORK_DATA) {
684 } else if (ofork->of_flags & AFPFORK_RSRC) {
689 offset = get_off_t(&ibuf, is64);
690 length = get_off_t(&ibuf, is64);
693 length = BYTELOCK_MAX;
694 else if (!length || is_neg(is64, length)) {
696 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
701 offset += ad_size(ofork->of_ad, eid);
702 /* FIXME what do we do if file size > 2 GB and
703 it's not byte_lock_ext?
706 if (offset < 0) /* error if we have a negative offset */
709 /* if the file is a read-only file, we use read locks instead of
710 * write locks. that way, we can prevent anyone from initiating
712 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
713 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
714 ofork->of_refnum) < 0) {
718 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
724 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
732 *rbuflen = set_off_t (offset, rbuf, is64);
736 /* --------------------------- */
737 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
739 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
742 /* --------------------------- */
743 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
745 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
751 * Read *rbuflen bytes from fork at offset
753 * @param ofork (r) fork handle
754 * @param eid (r) data fork or ressource fork entry id
755 * @param offset (r) offset
756 * @param rbuf (r) data buffer
757 * @param rbuflen (rw) in: number of bytes to read, out: bytes read
759 * @return AFP status code
761 static int read_file(const struct ofork *ofork, int eid, off_t offset, char *rbuf, size_t *rbuflen)
765 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
767 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
769 return( AFPERR_PARAM );
773 if ((size_t)cc < *rbuflen)
778 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
782 off_t offset, saveoff, reqcount, savereqcount, size;
787 /* we break the AFP spec here by not supporting nlmask and nlchar anymore */
790 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
791 ibuf += sizeof( u_short );
793 if (NULL == ( ofork = of_find( ofrefnum )) ) {
794 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
799 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
804 if ( ofork->of_flags & AFPFORK_DATA) {
806 } else if (ofork->of_flags & AFPFORK_RSRC) {
808 } else { /* fork wasn't opened. this should never really happen. */
813 offset = get_off_t(&ibuf, is64);
814 reqcount = get_off_t(&ibuf, is64);
816 /* zero request count */
822 AFP_READ_START((long)reqcount);
824 /* reqcount isn't always truthful. we need to deal with that. */
825 size = ad_size(ofork->of_ad, eid);
827 LOG(log_debug, logtype_afpd,
828 "afp_read(fork: %" PRIu16 " [%s], off: %" PRIu64 ", len: %" PRIu64 ", size: %" PRIu64 ")",
829 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount, size);
831 if (offset >= size) {
836 /* subtract off the offset */
837 if (reqcount + offset > size) {
838 reqcount = size - offset;
842 savereqcount = reqcount;
845 if (reqcount < 0 || offset < 0) {
850 if (obj->options.flags & OPTION_AFP_READ_LOCK) {
851 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) {
858 if (!(eid == ADEID_DFORK && ad_data_fileno(ofork->of_ad) == AD_SYMLINK) &&
859 !(obj->options.flags & OPTION_NOSENDFILE)) {
860 int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
861 if (dsi_stream_read_file(dsi, fd, offset, reqcount, err) < 0) {
862 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s",
863 of_name(ofork), strerror(errno));
870 *rbuflen = MIN(reqcount, dsi->server_quantum);
872 cc = read_file(ofork, eid, offset, ibuf, rbuflen);
878 LOG(log_debug, logtype_afpd,
879 "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
880 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
885 * dsi_readinit() returns size of next read buffer. by this point,
886 * we know that we're sending some data. if we fail, something
889 if ((cc = dsi_readinit(dsi, ibuf, *rbuflen, reqcount, err)) < 0)
893 while (*rbuflen > 0) {
895 * This loop isn't really entered anymore, we've already
896 * sent the whole requested block in dsi_readinit().
898 cc = read_file(ofork, eid, offset, ibuf, rbuflen);
903 /* dsi_read() also returns buffer size of next allocation */
904 cc = dsi_read(dsi, ibuf, *rbuflen); /* send it off */
913 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
915 if (obj->options.flags & OPTION_AFP_READ_LOCK)
916 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
917 obj->exit(EXITERR_CLNT);
920 if (obj->options.flags & OPTION_AFP_READ_LOCK)
921 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
931 /* ---------------------- */
932 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
934 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
937 /* ---------------------- */
938 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
940 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
943 /* ---------------------- */
944 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
952 memcpy(&vid, ibuf, sizeof(vid));
953 if (NULL == ( vol = getvolbyvid( vid )) ) {
954 return( AFPERR_PARAM );
961 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
968 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
970 if (NULL == ( ofork = of_find( ofrefnum )) ) {
971 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
972 return( AFPERR_PARAM );
975 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
976 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
978 if ( flushfork( ofork ) < 0 ) {
979 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
987 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
988 fsync(2) on OSX is implemented differently than on other platforms.
989 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
991 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
999 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1000 ibuf += sizeof( ofrefnum );
1002 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1003 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1004 return( AFPERR_PARAM );
1007 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1008 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1010 if ( flushfork( ofork ) < 0 ) {
1011 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1018 /* this is very similar to closefork */
1019 int flushfork(struct ofork *ofork)
1023 int err = 0, doflush = 0;
1025 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1026 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1027 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1028 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1032 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1033 (ofork->of_flags & AFPFORK_RSRC)) {
1035 /* read in the rfork length */
1036 ad_refresh(NULL, ofork->of_ad);
1038 /* set the date if we're dirty */
1039 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1040 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1041 ofork->of_flags &= ~AFPFORK_DIRTY;
1045 /* flush the header */
1046 if (doflush && ad_flush(ofork->of_ad) < 0)
1049 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1053 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1054 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1060 int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1062 struct ofork *ofork;
1067 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1069 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1070 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1071 return( AFPERR_PARAM );
1074 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %" PRIu16 " [%s])",
1075 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "rsrc");
1077 if (of_closefork(obj, ofork) < 0 ) {
1078 LOG(log_error, logtype_afpd, "afp_closefork: of_closefork: %s", strerror(errno) );
1079 return( AFPERR_PARAM );
1086 static ssize_t write_file(struct ofork *ofork, int eid,
1087 off_t offset, char *rbuf,
1092 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1093 (uintmax_t)offset, rbuflen);
1095 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1096 rbuf, rbuflen)) < 0 ) {
1101 LOG(log_error, logtype_afpd, "write_file: DISK FULL");
1102 return( AFPERR_DFULL );
1104 return AFPERR_ACCESS;
1106 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1107 return( AFPERR_PARAM );
1116 * FPWrite. NOTE: on an error, we always use afp_write_err as
1117 * the client may have sent us a bunch of data that's not reflected
1118 * in reqcount et al.
1120 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1122 struct ofork *ofork;
1123 off_t offset, saveoff, reqcount, oldsize, newsize;
1124 int endflag, eid, err = AFP_OK;
1127 DSI *dsi = obj->dsi;
1128 char *rcvbuf = (char *)dsi->commands;
1129 size_t rcvbuflen = dsi->server_quantum;
1131 /* figure out parameters */
1133 endflag = ENDBIT(*ibuf);
1135 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1136 ibuf += sizeof( ofrefnum );
1138 offset = get_off_t(&ibuf, is64);
1139 reqcount = get_off_t(&ibuf, is64);
1141 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1142 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1147 LOG(log_debug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu64 ")",
1148 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount);
1150 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1151 err = AFPERR_ACCESS;
1156 writtenfork = ofork;
1159 if ( ofork->of_flags & AFPFORK_DATA) {
1161 } else if (ofork->of_flags & AFPFORK_RSRC) {
1164 err = AFPERR_ACCESS; /* should never happen */
1168 oldsize = ad_size(ofork->of_ad, eid);
1172 /* handle bogus parameters */
1173 if (reqcount < 0 || offset < 0) {
1178 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1180 /* offset can overflow on 64-bit capable filesystems.
1181 * report disk full if that's going to happen. */
1182 if (sum_neg(is64, offset, reqcount)) {
1183 LOG(log_error, logtype_afpd, "write_fork: DISK FULL");
1188 if (!reqcount) { /* handle request counts of 0 */
1190 *rbuflen = set_off_t (offset, rbuf, is64);
1194 AFP_WRITE_START((long)reqcount);
1197 if (obj->options.flags & OPTION_AFP_READ_LOCK) {
1198 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, reqcount, ofork->of_refnum) < 0) {
1204 /* find out what we have already */
1205 if ((cc = dsi_writeinit(dsi, rcvbuf, rcvbuflen)) > 0) {
1207 if ((written = write_file(ofork, eid, offset, rcvbuf, cc)) != cc) {
1208 dsi_writeflush(dsi);
1210 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1211 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1213 /* It's used for the read size and as error code in write_file(), ugh */
1214 written = AFPERR_MISC;
1221 #ifdef WITH_RECVFILE
1222 if (obj->options.flags & OPTION_RECVFILE) {
1223 LOG(log_maxdebug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu32 ")",
1224 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, dsi->datasize);
1226 if ((cc = ad_recvfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize, obj->options.splice_size)) < dsi->datasize) {
1232 dsi_writeflush(dsi);
1235 goto afp_write_loop;
1237 /* Low level error, can't do much to back up */
1239 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno));
1242 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1243 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1248 goto afp_write_done;
1253 /* loop until everything gets written. currently
1254 * dsi_write handles the end case by itself. */
1255 while ((cc = dsi_write(dsi, rcvbuf, rcvbuflen))) {
1257 if ((cc = write_file(ofork, eid, offset, rcvbuf, cc)) < 0) {
1258 dsi_writeflush(dsi);
1260 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1261 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1265 LOG(log_debug, logtype_afpd, "afp_write: wrote: %jd, offset: %jd",
1266 (intmax_t)cc, (intmax_t)offset);
1272 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1273 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1274 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1275 ofork->of_flags |= AFPFORK_DIRTY;
1277 /* we have modified any fork, remember until close_fork */
1278 ofork->of_flags |= AFPFORK_MODIFIED;
1280 /* update write count */
1281 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1283 *rbuflen = set_off_t (offset, rbuf, is64);
1288 dsi_writeinit(dsi, rcvbuf, rcvbuflen);
1289 dsi_writeflush(dsi);
1291 if (err != AFP_OK) {
1297 /* ---------------------------- */
1298 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1300 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1303 /* ----------------------------
1304 * FIXME need to deal with SIGXFSZ signal
1306 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1308 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1311 /* ---------------------------- */
1312 int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1314 struct ofork *ofork;
1316 uint16_t ofrefnum, bitmap;
1319 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1320 ibuf += sizeof( ofrefnum );
1321 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1322 bitmap = ntohs( bitmap );
1323 ibuf += sizeof( bitmap );
1326 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1327 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1328 return( AFPERR_PARAM );
1331 if (AD_META_OPEN(ofork->of_ad)) {
1332 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1333 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1334 return( AFPERR_PARAM );
1338 if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1342 *rbuflen = buflen + sizeof( u_short );
1343 bitmap = htons( bitmap );
1344 memcpy(rbuf, &bitmap, sizeof( bitmap ));