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)
155 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
156 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
159 if ((access & (OPENACC_RD | OPENACC_DRD))) {
160 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
162 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
165 if ((access & OPENACC_RD) && denyreadset) {
169 if ((access & OPENACC_DRD) && readset) {
173 /* boolean logic is not enough, because getforkmode is not always telling the
176 if ((access & OPENACC_RD)) {
177 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
181 if ((access & OPENACC_DRD)) {
182 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
187 /* ------------same for writing -------------- */
188 if ((access & (OPENACC_WR | OPENACC_DWR))) {
189 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
191 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
194 if ((access & OPENACC_WR) && denywriteset) {
198 if ((access & OPENACC_DWR) && writeset) {
202 if ((access & OPENACC_WR)) {
203 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
207 if ((access & OPENACC_DWR)) {
208 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
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;
236 memcpy(&vid, ibuf, sizeof( vid ));
240 if (NULL == ( vol = getvolbyvid( vid ))) {
241 return( AFPERR_PARAM );
244 memcpy(&did, ibuf, sizeof( did ));
245 ibuf += sizeof( int );
247 if (NULL == ( dir = dirlookup( vol, did ))) {
251 memcpy(&bitmap, ibuf, sizeof( bitmap ));
252 bitmap = ntohs( bitmap );
253 ibuf += sizeof( bitmap );
254 memcpy(&access, ibuf, sizeof( access ));
255 access = ntohs( access );
256 ibuf += sizeof( access );
258 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
262 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
263 return get_afp_errno(AFPERR_PARAM);
266 if (*s_path->m_name == '\0') {
268 return AFPERR_BADTYPE;
271 /* stat() data fork st is set because it's not a dir */
272 switch ( s_path->st_errno ) {
278 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
280 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
283 /* FIXME should we check it first ? */
284 upath = s_path->u_name;
285 if (!vol_unix_priv(vol)) {
286 if (check_access(obj, vol, upath, access ) < 0) {
287 return AFPERR_ACCESS;
290 if (file_access(obj, vol, s_path, access ) < 0) {
291 return AFPERR_ACCESS;
296 /* XXX: this probably isn't the best way to do this. the already
297 open bits should really be set if the fork is opened by any
298 program, not just this one. however, that's problematic to do
299 if we can't write lock files somewhere. opened is also passed to
300 ad_open so that we can keep file locks together.
301 FIXME: add the fork we are opening?
303 if ((opened = of_findname(s_path))) {
304 adsame = opened->of_ad;
307 if ( fork == OPENFORK_DATA ) {
309 adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF;
312 adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF;
313 if (!(access & OPENACC_WR))
314 adflags |= ADFLAGS_NORF;
317 path = s_path->m_name;
318 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
319 adsame, st)) == NULL ) {
320 return( AFPERR_NFILE );
323 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
324 fullpathname(s_path->u_name),
325 (fork == OPENFORK_DATA) ? "data" : "reso",
326 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
329 if (access & OPENACC_WR) {
330 /* try opening in read-write mode */
331 if (ad_open(ofork->of_ad, upath,
332 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
339 if (fork == OPENFORK_DATA) {
340 /* try to open only the data fork */
341 if (ad_open(ofork->of_ad, upath,
342 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
345 adflags = ADFLAGS_DF;
347 /* here's the deal. we only try to create the resource
348 * fork if the user wants to open it for write acess. */
349 if (ad_open(ofork->of_ad, upath,
350 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
352 ofork->of_flags |= AFPFORK_META;
360 ret = AFPERR_BADTYPE;
363 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
369 /* the ressource fork is open too */
370 ofork->of_flags |= AFPFORK_META;
373 /* try opening in read-only mode */
375 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
383 /* see if client asked for a read only data fork */
384 if (fork == OPENFORK_DATA) {
385 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
388 adflags = ADFLAGS_DF;
390 /* else we don't set AFPFORK_META because there's no ressource fork file
391 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
392 * then create in open read-write.
393 * FIXME , it doesn't play well with byte locking example:
394 * ressource fork open read only
395 * locking set on it (no effect, there's no file!)
396 * ressource fork open read write now
404 ret = AFPERR_BADTYPE;
407 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
408 fullpathname(s_path->m_name), strerror(errno) );
412 ofork->of_flags |= AFPFORK_META;
416 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
417 if (ad_setname(ofork->of_ad, path)) {
418 ad_flush( ofork->of_ad );
422 if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
423 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
427 *rbuflen = buflen + 2 * sizeof( uint16_t );
428 bitmap = htons( bitmap );
429 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
430 rbuf += sizeof( uint16_t );
432 /* check WriteInhibit bit if we have a ressource fork
433 * the test is done here, after some Mac trafic capture
435 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
436 ad_getattr(ofork->of_ad, &bshort);
437 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
438 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
441 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
442 return(AFPERR_OLOCK);
447 * synchronization locks:
450 /* don't try to lock non-existent rforks. */
451 if ((eid == ADEID_DFORK)
452 || (ad_reso_fileno(ofork->of_ad) != -1)
453 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
454 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
455 /* can we access the fork? */
457 ofork->of_flags |= AFPFORK_ERROR;
459 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
462 case EAGAIN: /* return data anyway */
466 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
467 return( AFPERR_DENYCONF );
471 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
472 return( AFPERR_PARAM );
475 if ((access & OPENACC_WR))
476 ofork->of_flags |= AFPFORK_ACCWR;
478 /* the file may be open read only without ressource fork */
479 if ((access & OPENACC_RD))
480 ofork->of_flags |= AFPFORK_ACCRD;
482 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
488 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
492 int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
496 uint16_t ofrefnum, bitmap;
504 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
505 ibuf += sizeof( ofrefnum );
507 memcpy(&bitmap, ibuf, sizeof(bitmap));
508 bitmap = ntohs(bitmap);
509 ibuf += sizeof( bitmap );
512 if (NULL == ( ofork = of_find( ofrefnum )) ) {
513 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
514 return( AFPERR_PARAM );
517 if (ofork->of_vol->v_flags & AFPVOL_RO)
520 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
521 return AFPERR_ACCESS;
523 if ( ofork->of_flags & AFPFORK_DATA) {
525 } else if (ofork->of_flags & AFPFORK_RSRC) {
530 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
531 && eid == ADEID_RFORK
533 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
534 && eid == ADEID_DFORK)) {
535 return AFPERR_BITMAP;
539 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
540 if (obj->afp_version >= 30) {
544 return AFPERR_BITMAP;
547 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
548 return AFPERR_PARAM ;
550 size = get_off_t(&ibuf, is64);
553 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
556 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
557 st_size = ad_size(ofork->of_ad, eid);
559 if (st_size > size &&
560 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
561 goto afp_setfork_err;
563 err = ad_dtruncate( ofork->of_ad, size );
565 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
567 goto afp_setfork_err;
568 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
569 ad_refresh(NULL, ofork->of_ad );
571 st_size = ad_size(ofork->of_ad, eid);
573 if (st_size > size &&
574 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
575 goto afp_setfork_err;
577 if (ofork->of_ad->ad_vers == AD_VERSION_EA) {
579 err = sys_lremovexattr(of_name(ofork), AD_EA_RESO);
581 err = unlink(ofork->of_vol->ad_path(of_name(ofork), 0));
584 err = ad_rtruncate(ofork->of_ad, size);
587 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
589 goto afp_setfork_err;
591 if (ad_flush( ofork->of_ad ) < 0) {
592 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
596 return AFPERR_BITMAP;
599 if ( flushfork( ofork ) < 0 ) {
600 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
615 return AFPERR_ACCESS;
626 /* for this to work correctly, we need to check for locks before each
627 * read and write. that's most easily handled by always doing an
628 * appropriate check before each ad_read/ad_write. other things
629 * that can change files like truncate are handled internally to those
632 #define ENDBIT(a) ((a) & 0x80)
633 #define UNLOCKBIT(a) ((a) & 0x01)
636 /* ---------------------- */
637 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
640 off_t offset, length;
648 /* figure out parameters */
650 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
652 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
653 ibuf += sizeof(ofrefnum);
655 if (NULL == ( ofork = of_find( ofrefnum )) ) {
656 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
657 return( AFPERR_PARAM );
660 if ( ofork->of_flags & AFPFORK_DATA) {
662 } else if (ofork->of_flags & AFPFORK_RSRC) {
667 offset = get_off_t(&ibuf, is64);
668 length = get_off_t(&ibuf, is64);
671 length = BYTELOCK_MAX;
672 else if (!length || is_neg(is64, length)) {
674 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
679 offset += ad_size(ofork->of_ad, eid);
680 /* FIXME what do we do if file size > 2 GB and
681 it's not byte_lock_ext?
684 if (offset < 0) /* error if we have a negative offset */
687 /* if the file is a read-only file, we use read locks instead of
688 * write locks. that way, we can prevent anyone from initiating
690 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
691 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
692 ofork->of_refnum) < 0) {
696 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
702 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
710 *rbuflen = set_off_t (offset, rbuf, is64);
714 /* --------------------------- */
715 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
717 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
720 /* --------------------------- */
721 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
723 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
728 static ssize_t read_file(struct ofork *ofork, int eid,
729 off_t offset, u_char nlmask,
730 u_char nlchar, char *rbuf,
737 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
739 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
741 return( AFPERR_PARAM );
743 if ( (size_t)cc < *rbuflen ) {
751 for ( p = rbuf, q = p + cc; p < q; ) {
752 if (( *p++ & nlmask ) == nlchar ) {
764 return( AFPERR_EOF );
769 /* -----------------------------
770 * with ddp, afp_read can return fewer bytes than in reqcount
771 * so return EOF only if read actually past end of file not
772 * if offset +reqcount > size of file
774 * getfork size ==> 10430
775 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
776 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
777 * read fork offset 9248 size 1508 ==> 1182 (EOF)
778 * 10752 is a bug in Mac 7.5.x finder
780 * with dsi, should we check that reqcount < server quantum?
782 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
785 off_t offset, saveoff, reqcount, savereqcount;
789 u_char nlmask, nlchar;
792 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
793 ibuf += sizeof( u_short );
795 if (NULL == ( ofork = of_find( ofrefnum )) ) {
796 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
801 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
805 offset = get_off_t(&ibuf, is64);
806 reqcount = get_off_t(&ibuf, is64);
808 LOG(log_debug, logtype_afpd,
809 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
810 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
819 /* if we wanted to be picky, we could add in the following
820 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
822 if (reqcount < 0 || offset < 0) {
827 if ( ofork->of_flags & AFPFORK_DATA) {
829 } else if (ofork->of_flags & AFPFORK_RSRC) {
831 } else { /* fork wasn't opened. this should never really happen. */
836 /* zero request count */
842 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
843 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
845 savereqcount = reqcount;
847 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
852 *rbuflen = MIN(reqcount, *rbuflen);
853 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
854 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
856 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen);
859 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
860 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
862 /* dsi can stream requests. we can only do this if we're not checking
863 * for an end-of-line character. oh well. */
864 if ((*rbuflen < reqcount) && !nlmask) {
868 /* reqcount isn't always truthful. we need to deal with that. */
869 size = ad_size(ofork->of_ad, eid);
871 /* subtract off the offset */
873 if (reqcount > size) {
880 /* dsi_readinit() returns size of next read buffer. by this point,
881 * we know that we're sending some data. if we fail, something
882 * horrible happened. */
883 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
886 /* due to the nature of afp packets, we have to exit if we get
887 an error. we can't do this with translation on. */
891 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
893 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
894 if (errno == EINVAL || errno == ENOSYS)
897 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
908 /* fill up our buffer. */
909 while (*rbuflen > 0) {
910 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen);
915 /* dsi_read() also returns buffer size of next allocation */
916 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
925 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
927 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
928 obj->exit(EXITERR_CLNT);
932 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
940 /* ---------------------- */
941 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
943 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
946 /* ---------------------- */
947 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
949 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
952 /* ---------------------- */
953 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
961 memcpy(&vid, ibuf, sizeof(vid));
962 if (NULL == ( vol = getvolbyvid( vid )) ) {
963 return( AFPERR_PARAM );
970 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
977 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
979 if (NULL == ( ofork = of_find( ofrefnum )) ) {
980 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
981 return( AFPERR_PARAM );
984 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
985 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
987 if ( flushfork( ofork ) < 0 ) {
988 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
996 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
997 fsync(2) on OSX is implemented differently than on other platforms.
998 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1000 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1002 struct ofork *ofork;
1008 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1009 ibuf += sizeof( ofrefnum );
1011 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1012 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1013 return( AFPERR_PARAM );
1016 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1017 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1019 if ( flushfork( ofork ) < 0 ) {
1020 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1027 /* this is very similar to closefork */
1028 int flushfork(struct ofork *ofork)
1032 int err = 0, doflush = 0;
1034 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1035 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1036 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1037 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1041 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1042 (ofork->of_flags & AFPFORK_RSRC)) {
1044 /* read in the rfork length */
1045 ad_refresh(NULL, ofork->of_ad);
1047 /* set the date if we're dirty */
1048 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1049 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1050 ofork->of_flags &= ~AFPFORK_DIRTY;
1054 /* flush the header */
1055 if (doflush && ad_flush(ofork->of_ad) < 0)
1058 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1062 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1063 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1069 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1071 struct ofork *ofork;
1076 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1078 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1079 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1080 return( AFPERR_PARAM );
1083 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1084 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1086 if ( of_closefork( ofork ) < 0 ) {
1087 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1088 return( AFPERR_PARAM );
1095 static ssize_t write_file(struct ofork *ofork, int eid,
1096 off_t offset, char *rbuf,
1102 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1103 (uintmax_t)offset, rbuflen);
1105 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1106 rbuf, rbuflen)) < 0 ) {
1111 return( AFPERR_DFULL );
1113 return AFPERR_ACCESS;
1115 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1116 return( AFPERR_PARAM );
1124 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1125 * the client may have sent us a bunch of data that's not reflected
1126 * in reqcount et al. */
1127 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1129 struct ofork *ofork;
1130 off_t offset, saveoff, reqcount, oldsize, newsize;
1131 int endflag, eid, err = AFP_OK;
1135 /* figure out parameters */
1137 endflag = ENDBIT(*ibuf);
1139 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1140 ibuf += sizeof( ofrefnum );
1142 offset = get_off_t(&ibuf, is64);
1143 reqcount = get_off_t(&ibuf, is64);
1145 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1146 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1151 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1152 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1154 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1155 err = AFPERR_ACCESS;
1160 writtenfork = ofork;
1163 if ( ofork->of_flags & AFPFORK_DATA) {
1165 } else if (ofork->of_flags & AFPFORK_RSRC) {
1168 err = AFPERR_ACCESS; /* should never happen */
1172 oldsize = ad_size(ofork->of_ad, eid);
1176 /* handle bogus parameters */
1177 if (reqcount < 0 || offset < 0) {
1182 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1184 /* offset can overflow on 64-bit capable filesystems.
1185 * report disk full if that's going to happen. */
1186 if (sum_neg(is64, offset, reqcount)) {
1191 if (!reqcount) { /* handle request counts of 0 */
1193 *rbuflen = set_off_t (offset, rbuf, is64);
1198 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1199 reqcount, ofork->of_refnum) < 0) {
1204 DSI *dsi = obj->dsi;
1205 /* find out what we have already and write it out. */
1206 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1208 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1209 dsi_writeflush(dsi);
1211 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1217 #if 0 /*def HAVE_SENDFILE_WRITE*/
1218 if (!(obj->options.flags & OPTION_DEBUG)) {
1219 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1220 offset, dsi->datasize)) < 0) {
1228 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1229 goto afp_write_loop;
1231 dsi_writeflush(dsi);
1233 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1234 reqcount, ofork->of_refnum);
1239 goto afp_write_done;
1241 #endif /* 0, was HAVE_SENDFILE_WRITE */
1243 /* loop until everything gets written. currently
1244 * dsi_write handles the end case by itself. */
1245 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1246 if ((cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1247 dsi_writeflush(dsi);
1249 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1250 reqcount, ofork->of_refnum);
1256 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1257 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1258 ofork->of_flags |= AFPFORK_DIRTY;
1260 /* we have modified any fork, remember until close_fork */
1261 ofork->of_flags |= AFPFORK_MODIFIED;
1263 /* update write count */
1264 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1266 *rbuflen = set_off_t (offset, rbuf, is64);
1270 dsi_writeinit(obj->dsi, rbuf, *rbuflen);
1271 dsi_writeflush(obj->dsi);
1273 if (err != AFP_OK) {
1279 /* ---------------------------- */
1280 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1282 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1285 /* ----------------------------
1286 * FIXME need to deal with SIGXFSZ signal
1288 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1290 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1293 /* ---------------------------- */
1294 int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1296 struct ofork *ofork;
1298 uint16_t ofrefnum, bitmap;
1301 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1302 ibuf += sizeof( ofrefnum );
1303 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1304 bitmap = ntohs( bitmap );
1305 ibuf += sizeof( bitmap );
1308 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1309 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1310 return( AFPERR_PARAM );
1313 if (AD_META_OPEN(ofork->of_ad)) {
1314 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1315 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1316 return( AFPERR_PARAM );
1320 if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1324 *rbuflen = buflen + sizeof( u_short );
1325 bitmap = htons( bitmap );
1326 memcpy(rbuf, &bitmap, sizeof( bitmap ));