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)
159 if (obj->options.flags & OPTION_SHARE_RESERV) {
160 shmd.f_access = (access & OPENACC_RD ? F_RDACC : 0) | (access & OPENACC_WR ? F_WRACC : 0);
161 if (shmd.f_access == 0)
162 /* we must give an access mode, otherwise fcntl will complain */
163 shmd.f_access = F_RDACC;
164 shmd.f_deny = (access & OPENACC_DRD ? F_RDDNY : F_NODNY) | (access & OPENACC_DWR) ? F_WRDNY : 0;
165 shmd.f_id = ofrefnum;
167 int fd = (eid == ADEID_DFORK) ? ad_data_fileno(adp) : ad_reso_fileno(adp);
169 if (fd != -1 && fd != AD_SYMLINK && fcntl(fd, F_SHARE, &shmd) != 0) {
170 LOG(log_debug, logtype_afpd, "fork_setmode: fcntl: %s", strerror(errno));
177 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
178 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
181 if ((access & (OPENACC_RD | OPENACC_DRD))) {
182 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
184 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
187 if ((access & OPENACC_RD) && denyreadset) {
191 if ((access & OPENACC_DRD) && readset) {
195 /* boolean logic is not enough, because getforkmode is not always telling the
198 if ((access & OPENACC_RD)) {
199 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
203 if ((access & OPENACC_DRD)) {
204 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
209 /* ------------same for writing -------------- */
210 if ((access & (OPENACC_WR | OPENACC_DWR))) {
211 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
213 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
216 if ((access & OPENACC_WR) && denywriteset) {
220 if ((access & OPENACC_DWR) && writeset) {
224 if ((access & OPENACC_WR)) {
225 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
229 if ((access & OPENACC_DWR)) {
230 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
239 /* ----------------------- */
240 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
244 struct ofork *ofork, *opened;
245 struct adouble *adsame = NULL;
247 int ret, adflags, eid;
249 uint16_t vid, bitmap, access, ofrefnum;
250 char fork, *path, *upath;
257 memcpy(&vid, ibuf, sizeof( vid ));
261 if (NULL == ( vol = getvolbyvid( vid ))) {
262 return( AFPERR_PARAM );
265 memcpy(&did, ibuf, sizeof( did ));
266 ibuf += sizeof( int );
268 if (NULL == ( dir = dirlookup( vol, did ))) {
272 memcpy(&bitmap, ibuf, sizeof( bitmap ));
273 bitmap = ntohs( bitmap );
274 ibuf += sizeof( bitmap );
275 memcpy(&access, ibuf, sizeof( access ));
276 access = ntohs( access );
277 ibuf += sizeof( access );
279 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
283 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
284 return get_afp_errno(AFPERR_PARAM);
287 if (*s_path->m_name == '\0') {
289 return AFPERR_BADTYPE;
292 /* stat() data fork st is set because it's not a dir */
293 switch ( s_path->st_errno ) {
299 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
301 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
305 upath = s_path->u_name;
306 path = s_path->m_name;
309 if (!vol_unix_priv(vol)) {
310 if (check_access(obj, vol, upath, access ) < 0) {
311 return AFPERR_ACCESS;
314 if (file_access(obj, vol, s_path, access ) < 0) {
315 return AFPERR_ACCESS;
319 if ((opened = of_findname(vol, s_path))) {
320 adsame = opened->of_ad;
323 adflags = ADFLAGS_SETSHRMD;
325 if (fork == OPENFORK_DATA) {
327 adflags |= ADFLAGS_DF;
330 adflags |= ADFLAGS_RF;
333 if (access & OPENACC_WR) {
334 adflags |= ADFLAGS_RDWR;
335 if (fork != OPENFORK_DATA)
337 * We only try to create the resource
338 * fork if the user wants to open it for write acess.
340 adflags |= ADFLAGS_CREATE;
342 adflags |= ADFLAGS_RDONLY;
345 if ((ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, adsame, st)) == NULL)
348 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
349 fullpathname(s_path->u_name),
350 (fork == OPENFORK_DATA) ? "data" : "reso",
351 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
355 /* First ad_open(), opens data or ressource fork */
356 if (ad_open(ofork->of_ad, upath, adflags, 0666) < 0) {
369 ret = AFPERR_BADTYPE;
372 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
379 * Create metadata if we open rw, otherwise only open existing metadata
381 if (access & OPENACC_WR) {
382 adflags = ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE;
384 adflags = ADFLAGS_HF | ADFLAGS_RDONLY;
387 if (ad_open(ofork->of_ad, upath, adflags, 0666) == 0) {
388 ofork->of_flags |= AFPFORK_META;
389 if (ad_get_MD_flags(ofork->of_ad) & O_CREAT) {
390 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): setting CNID", upath);
392 if ((id = get_id(vol, ofork->of_ad, st, dir->d_did, upath, strlen(upath))) == CNID_INVALID) {
393 LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): CNID error", upath);
396 (void)ad_setid(ofork->of_ad, st->st_dev, st->st_ino, id, dir->d_did, vol->v_stamp);
397 ad_flush(ofork->of_ad);
403 /* no metadata? We don't care! */
412 ret = AFPERR_BADTYPE;
415 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
421 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
422 if (ad_setname(ofork->of_ad, path)) {
423 ad_flush( ofork->of_ad );
427 if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
428 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
432 *rbuflen = buflen + 2 * sizeof( uint16_t );
433 bitmap = htons( bitmap );
434 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
435 rbuf += sizeof( uint16_t );
437 /* check WriteInhibit bit if we have a ressource fork
438 * the test is done here, after some Mac trafic capture
440 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
441 ad_getattr(ofork->of_ad, &bshort);
442 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
443 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
446 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
447 return(AFPERR_OLOCK);
452 * synchronization locks:
455 /* don't try to lock non-existent rforks. */
456 if ((eid == ADEID_DFORK)
457 || (ad_reso_fileno(ofork->of_ad) != -1)
458 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
459 ret = fork_setmode(obj, ofork->of_ad, eid, access, ofrefnum);
460 /* can we access the fork? */
462 ofork->of_flags |= AFPFORK_ERROR;
464 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
467 case EAGAIN: /* return data anyway */
471 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
472 return( AFPERR_DENYCONF );
476 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
477 return( AFPERR_PARAM );
480 if ((access & OPENACC_WR))
481 ofork->of_flags |= AFPFORK_ACCWR;
483 /* the file may be open read only without ressource fork */
484 if ((access & OPENACC_RD))
485 ofork->of_flags |= AFPFORK_ACCRD;
487 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): fork: %" PRIu16,
488 fullpathname(s_path->m_name), ofork->of_refnum);
490 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
496 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
500 int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
506 uint16_t ofrefnum, bitmap;
514 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
515 ibuf += sizeof( ofrefnum );
517 memcpy(&bitmap, ibuf, sizeof(bitmap));
518 bitmap = ntohs(bitmap);
519 ibuf += sizeof( bitmap );
522 if (NULL == ( ofork = of_find( ofrefnum )) ) {
523 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
524 return( AFPERR_PARAM );
528 if ((dir = dirlookup(vol, ofork->of_did)) == NULL) {
529 LOG(log_error, logtype_afpd, "%s: bad fork did", of_name(ofork));
532 if (movecwd(vol, dir) != 0) {
533 LOG(log_error, logtype_afpd, "%s: bad fork directory", dir->d_fullpath);
537 if (ofork->of_vol->v_flags & AFPVOL_RO)
540 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
541 return AFPERR_ACCESS;
543 if ( ofork->of_flags & AFPFORK_DATA) {
545 } else if (ofork->of_flags & AFPFORK_RSRC) {
550 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
551 && eid == ADEID_RFORK
553 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
554 && eid == ADEID_DFORK)) {
555 return AFPERR_BITMAP;
559 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
560 if (obj->afp_version >= 30) {
564 return AFPERR_BITMAP;
567 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
568 return AFPERR_PARAM ;
570 size = get_off_t(&ibuf, is64);
573 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
576 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
577 st_size = ad_size(ofork->of_ad, eid);
579 if (st_size > size &&
580 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
581 goto afp_setfork_err;
583 err = ad_dtruncate( ofork->of_ad, size );
585 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
587 goto afp_setfork_err;
588 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
589 ad_refresh(NULL, ofork->of_ad );
591 st_size = ad_size(ofork->of_ad, eid);
593 if (st_size > size &&
594 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
595 goto afp_setfork_err;
598 err = ad_rtruncate(ofork->of_ad, mtoupath(ofork->of_vol, of_name(ofork), ofork->of_did, utf8_encoding(obj)), size);
600 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
602 goto afp_setfork_err;
604 if (ad_flush( ofork->of_ad ) < 0) {
605 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
609 return AFPERR_BITMAP;
612 if ( flushfork( ofork ) < 0 ) {
613 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
628 return AFPERR_ACCESS;
632 LOG(log_error, logtype_afpd, "afp_setforkparams: DISK FULL");
640 /* for this to work correctly, we need to check for locks before each
641 * read and write. that's most easily handled by always doing an
642 * appropriate check before each ad_read/ad_write. other things
643 * that can change files like truncate are handled internally to those
646 #define ENDBIT(a) ((a) & 0x80)
647 #define UNLOCKBIT(a) ((a) & 0x01)
650 /* ---------------------- */
651 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
654 off_t offset, length;
662 /* figure out parameters */
664 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
666 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
667 ibuf += sizeof(ofrefnum);
669 if (NULL == ( ofork = of_find( ofrefnum )) ) {
670 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
671 return( AFPERR_PARAM );
674 if ( ofork->of_flags & AFPFORK_DATA) {
676 } else if (ofork->of_flags & AFPFORK_RSRC) {
681 offset = get_off_t(&ibuf, is64);
682 length = get_off_t(&ibuf, is64);
685 length = BYTELOCK_MAX;
686 else if (!length || is_neg(is64, length)) {
688 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
693 offset += ad_size(ofork->of_ad, eid);
694 /* FIXME what do we do if file size > 2 GB and
695 it's not byte_lock_ext?
698 if (offset < 0) /* error if we have a negative offset */
701 /* if the file is a read-only file, we use read locks instead of
702 * write locks. that way, we can prevent anyone from initiating
704 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
705 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
706 ofork->of_refnum) < 0) {
710 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
716 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
724 *rbuflen = set_off_t (offset, rbuf, is64);
728 /* --------------------------- */
729 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
731 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
734 /* --------------------------- */
735 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
737 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
743 * Read *rbuflen bytes from fork at offset
745 * @param ofork (r) fork handle
746 * @param eid (r) data fork or ressource fork entry id
747 * @param offset (r) offset
748 * @param rbuf (r) data buffer
749 * @param rbuflen (rw) in: number of bytes to read, out: bytes read
751 * @return AFP status code
753 static int read_file(const struct ofork *ofork, int eid, off_t offset, char *rbuf, size_t *rbuflen)
757 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
759 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
761 return( AFPERR_PARAM );
765 if ((size_t)cc < *rbuflen)
770 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
774 off_t offset, saveoff, reqcount, savereqcount, size;
779 /* we break the AFP spec here by not supporting nlmask and nlchar anymore */
782 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
783 ibuf += sizeof( u_short );
785 if (NULL == ( ofork = of_find( ofrefnum )) ) {
786 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
791 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
796 if ( ofork->of_flags & AFPFORK_DATA) {
798 } else if (ofork->of_flags & AFPFORK_RSRC) {
800 } else { /* fork wasn't opened. this should never really happen. */
805 offset = get_off_t(&ibuf, is64);
806 reqcount = get_off_t(&ibuf, is64);
808 /* zero request count */
814 AFP_READ_START((long)reqcount);
816 /* reqcount isn't always truthful. we need to deal with that. */
817 size = ad_size(ofork->of_ad, eid);
819 LOG(log_debug, logtype_afpd,
820 "afp_read(fork: %" PRIu16 " [%s], off: %" PRIu64 ", len: %" PRIu64 ", size: %" PRIu64 ")",
821 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount, size);
823 if (offset >= size) {
828 /* subtract off the offset */
829 if (reqcount + offset > size) {
830 reqcount = size - offset;
834 savereqcount = reqcount;
837 if (reqcount < 0 || offset < 0) {
842 if (obj->options.flags & OPTION_AFP_READ_LOCK) {
843 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) {
850 if (!(eid == ADEID_DFORK && ad_data_fileno(ofork->of_ad) == AD_SYMLINK) &&
851 !(obj->options.flags & OPTION_NOSENDFILE)) {
852 int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
853 if (dsi_stream_read_file(dsi, fd, offset, reqcount, err) < 0) {
854 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s",
855 of_name(ofork), strerror(errno));
862 *rbuflen = MIN(reqcount, dsi->server_quantum);
864 cc = read_file(ofork, eid, offset, ibuf, rbuflen);
870 LOG(log_debug, logtype_afpd,
871 "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);
877 * dsi_readinit() returns size of next read buffer. by this point,
878 * we know that we're sending some data. if we fail, something
881 if ((cc = dsi_readinit(dsi, ibuf, *rbuflen, reqcount, err)) < 0)
885 while (*rbuflen > 0) {
887 * This loop isn't really entered anymore, we've already
888 * sent the whole requested block in dsi_readinit().
890 cc = read_file(ofork, eid, offset, ibuf, rbuflen);
895 /* dsi_read() also returns buffer size of next allocation */
896 cc = dsi_read(dsi, ibuf, *rbuflen); /* send it off */
905 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
907 if (obj->options.flags & OPTION_AFP_READ_LOCK)
908 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
909 obj->exit(EXITERR_CLNT);
912 if (obj->options.flags & OPTION_AFP_READ_LOCK)
913 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
923 /* ---------------------- */
924 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
926 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
929 /* ---------------------- */
930 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
932 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
935 /* ---------------------- */
936 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
944 memcpy(&vid, ibuf, sizeof(vid));
945 if (NULL == ( vol = getvolbyvid( vid )) ) {
946 return( AFPERR_PARAM );
953 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
960 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
962 if (NULL == ( ofork = of_find( ofrefnum )) ) {
963 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
964 return( AFPERR_PARAM );
967 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
968 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
970 if ( flushfork( ofork ) < 0 ) {
971 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
979 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
980 fsync(2) on OSX is implemented differently than on other platforms.
981 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
983 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
991 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
992 ibuf += sizeof( ofrefnum );
994 if (NULL == ( ofork = of_find( ofrefnum )) ) {
995 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
996 return( AFPERR_PARAM );
999 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1000 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1002 if ( flushfork( ofork ) < 0 ) {
1003 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1010 /* this is very similar to closefork */
1011 int flushfork(struct ofork *ofork)
1015 int err = 0, doflush = 0;
1017 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1018 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1019 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1020 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1024 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1025 (ofork->of_flags & AFPFORK_RSRC)) {
1027 /* read in the rfork length */
1028 ad_refresh(NULL, ofork->of_ad);
1030 /* set the date if we're dirty */
1031 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1032 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1033 ofork->of_flags &= ~AFPFORK_DIRTY;
1037 /* flush the header */
1038 if (doflush && ad_flush(ofork->of_ad) < 0)
1041 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1045 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1046 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1052 int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1054 struct ofork *ofork;
1059 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1061 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1062 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1063 return( AFPERR_PARAM );
1066 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %" PRIu16 " [%s])",
1067 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "rsrc");
1069 if (of_closefork(obj, ofork) < 0 ) {
1070 LOG(log_error, logtype_afpd, "afp_closefork: of_closefork: %s", strerror(errno) );
1071 return( AFPERR_PARAM );
1078 static ssize_t write_file(struct ofork *ofork, int eid,
1079 off_t offset, char *rbuf,
1084 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1085 (uintmax_t)offset, rbuflen);
1087 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1088 rbuf, rbuflen)) < 0 ) {
1093 LOG(log_error, logtype_afpd, "write_file: DISK FULL");
1094 return( AFPERR_DFULL );
1096 return AFPERR_ACCESS;
1098 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1099 return( AFPERR_PARAM );
1108 * FPWrite. NOTE: on an error, we always use afp_write_err as
1109 * the client may have sent us a bunch of data that's not reflected
1110 * in reqcount et al.
1112 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1114 struct ofork *ofork;
1115 off_t offset, saveoff, reqcount, oldsize, newsize;
1116 int endflag, eid, err = AFP_OK;
1119 DSI *dsi = obj->dsi;
1120 char *rcvbuf = (char *)dsi->commands;
1121 size_t rcvbuflen = dsi->server_quantum;
1123 /* figure out parameters */
1125 endflag = ENDBIT(*ibuf);
1127 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1128 ibuf += sizeof( ofrefnum );
1130 offset = get_off_t(&ibuf, is64);
1131 reqcount = get_off_t(&ibuf, is64);
1133 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1134 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1139 LOG(log_debug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu64 ")",
1140 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount);
1142 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1143 err = AFPERR_ACCESS;
1148 writtenfork = ofork;
1151 if ( ofork->of_flags & AFPFORK_DATA) {
1153 } else if (ofork->of_flags & AFPFORK_RSRC) {
1156 err = AFPERR_ACCESS; /* should never happen */
1160 oldsize = ad_size(ofork->of_ad, eid);
1164 /* handle bogus parameters */
1165 if (reqcount < 0 || offset < 0) {
1170 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1172 /* offset can overflow on 64-bit capable filesystems.
1173 * report disk full if that's going to happen. */
1174 if (sum_neg(is64, offset, reqcount)) {
1175 LOG(log_error, logtype_afpd, "write_fork: DISK FULL");
1180 if (!reqcount) { /* handle request counts of 0 */
1182 *rbuflen = set_off_t (offset, rbuf, is64);
1186 AFP_WRITE_START((long)reqcount);
1189 if (obj->options.flags & OPTION_AFP_READ_LOCK) {
1190 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, reqcount, ofork->of_refnum) < 0) {
1196 /* find out what we have already */
1197 if ((cc = dsi_writeinit(dsi, rcvbuf, rcvbuflen)) > 0) {
1199 if ((written = write_file(ofork, eid, offset, rcvbuf, cc)) != cc) {
1200 dsi_writeflush(dsi);
1202 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1203 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1205 /* It's used for the read size and as error code in write_file(), ugh */
1206 written = AFPERR_MISC;
1213 #ifdef WITH_RECVFILE
1214 if (obj->options.flags & OPTION_RECVFILE) {
1215 LOG(log_maxdebug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu32 ")",
1216 ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, dsi->datasize);
1218 if ((cc = ad_recvfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize, obj->options.splice_size)) < dsi->datasize) {
1224 dsi_writeflush(dsi);
1227 goto afp_write_loop;
1229 /* Low level error, can't do much to back up */
1231 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno));
1234 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1235 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1240 goto afp_write_done;
1245 /* loop until everything gets written. currently
1246 * dsi_write handles the end case by itself. */
1247 while ((cc = dsi_write(dsi, rcvbuf, rcvbuflen))) {
1249 if ((cc = write_file(ofork, eid, offset, rcvbuf, cc)) < 0) {
1250 dsi_writeflush(dsi);
1252 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1253 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1257 LOG(log_debug, logtype_afpd, "afp_write: wrote: %jd, offset: %jd",
1258 (intmax_t)cc, (intmax_t)offset);
1264 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1265 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1266 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1267 ofork->of_flags |= AFPFORK_DIRTY;
1269 /* we have modified any fork, remember until close_fork */
1270 ofork->of_flags |= AFPFORK_MODIFIED;
1272 /* update write count */
1273 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1275 *rbuflen = set_off_t (offset, rbuf, is64);
1280 dsi_writeinit(dsi, rcvbuf, rcvbuflen);
1281 dsi_writeflush(dsi);
1283 if (err != AFP_OK) {
1289 /* ---------------------------- */
1290 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1292 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1295 /* ----------------------------
1296 * FIXME need to deal with SIGXFSZ signal
1298 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1300 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1303 /* ---------------------------- */
1304 int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1306 struct ofork *ofork;
1308 uint16_t ofrefnum, bitmap;
1311 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1312 ibuf += sizeof( ofrefnum );
1313 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1314 bitmap = ntohs( bitmap );
1315 ibuf += sizeof( bitmap );
1318 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1319 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1320 return( AFPERR_PARAM );
1323 if (AD_META_OPEN(ofork->of_ad)) {
1324 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1325 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1326 return( AFPERR_PARAM );
1330 if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1334 *rbuflen = buflen + sizeof( u_short );
1335 bitmap = htons( bitmap );
1336 memcpy(rbuf, &bitmap, sizeof( bitmap ));