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>
31 #include "directory.h"
36 struct ofork *writtenfork;
39 static int getforkparams(const AFPObj *obj, struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen)
49 /* can only get the length of the opened fork */
50 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
51 && (ofork->of_flags & AFPFORK_RSRC))
53 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
54 && (ofork->of_flags & AFPFORK_DATA))) {
55 return( AFPERR_BITMAP );
58 if (! AD_META_OPEN(ofork->of_ad)) {
65 dir = dirlookup(vol, ofork->of_did);
67 if (NULL == (path.m_name = utompath(vol, of_name(ofork), dir->d_did, utf8_encoding(obj)))) {
68 return( AFPERR_MISC );
70 path.u_name = of_name(ofork);
73 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
74 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
75 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
76 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
77 /* 0 is for symlink */
78 if (movecwd(vol, dir) < 0)
79 return( AFPERR_NOOBJ );
80 if ( lstat( path.u_name, st ) < 0 )
81 return( AFPERR_NOOBJ );
83 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
84 return( AFPERR_BITMAP );
88 return getmetadata(obj, vol, bitmap, &path, dir, buf, buflen, adp );
91 static off_t get_off_t(char **ibuf, int is64)
97 memcpy(&temp, *ibuf, sizeof( temp ));
98 ret = ntohl(temp); /* ntohl is unsigned */
99 *ibuf += sizeof(temp);
102 memcpy(&temp, *ibuf, sizeof( temp ));
103 *ibuf += sizeof(temp);
104 ret = ntohl(temp)| (ret << 32);
107 ret = (int)ret; /* sign extend */
112 static int set_off_t(off_t offset, char *rbuf, int is64)
119 temp = htonl(offset >> 32);
120 memcpy(rbuf, &temp, sizeof( temp ));
121 rbuf += sizeof(temp);
122 ret = sizeof( temp );
123 offset &= 0xffffffff;
125 temp = htonl(offset);
126 memcpy(rbuf, &temp, sizeof( temp ));
127 ret += sizeof( temp );
132 static int is_neg(int is64, off_t val)
134 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
139 static int sum_neg(int is64, off_t offset, off_t reqcount)
141 if (is_neg(is64, offset +reqcount) )
146 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
154 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
155 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
158 if ((access & (OPENACC_RD | OPENACC_DRD))) {
159 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
161 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
164 if ((access & OPENACC_RD) && denyreadset) {
168 if ((access & OPENACC_DRD) && readset) {
172 /* boolean logic is not enough, because getforkmode is not always telling the
175 if ((access & OPENACC_RD)) {
176 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
180 if ((access & OPENACC_DRD)) {
181 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
186 /* ------------same for writing -------------- */
187 if ((access & (OPENACC_WR | OPENACC_DWR))) {
188 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
190 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
193 if ((access & OPENACC_WR) && denywriteset) {
197 if ((access & OPENACC_DWR) && writeset) {
201 if ((access & OPENACC_WR)) {
202 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
206 if ((access & OPENACC_DWR)) {
207 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
216 /* ----------------------- */
217 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
221 struct ofork *ofork, *opened;
222 struct adouble *adsame = NULL;
224 int ret, adflags, eid;
226 uint16_t vid, bitmap, access, ofrefnum;
227 char fork, *path, *upath;
235 memcpy(&vid, ibuf, sizeof( vid ));
239 if (NULL == ( vol = getvolbyvid( vid ))) {
240 return( AFPERR_PARAM );
243 memcpy(&did, ibuf, sizeof( did ));
244 ibuf += sizeof( int );
246 if (NULL == ( dir = dirlookup( vol, did ))) {
250 memcpy(&bitmap, ibuf, sizeof( bitmap ));
251 bitmap = ntohs( bitmap );
252 ibuf += sizeof( bitmap );
253 memcpy(&access, ibuf, sizeof( access ));
254 access = ntohs( access );
255 ibuf += sizeof( access );
257 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
261 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
262 return get_afp_errno(AFPERR_PARAM);
265 if (*s_path->m_name == '\0') {
267 return AFPERR_BADTYPE;
270 /* stat() data fork st is set because it's not a dir */
271 switch ( s_path->st_errno ) {
277 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
279 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
282 /* FIXME should we check it first ? */
283 upath = s_path->u_name;
284 if (!vol_unix_priv(vol)) {
285 if (check_access(obj, vol, upath, access ) < 0) {
286 return AFPERR_ACCESS;
289 if (file_access(obj, vol, s_path, access ) < 0) {
290 return AFPERR_ACCESS;
295 /* XXX: this probably isn't the best way to do this. the already
296 open bits should really be set if the fork is opened by any
297 program, not just this one. however, that's problematic to do
298 if we can't write lock files somewhere. opened is also passed to
299 ad_open so that we can keep file locks together.
300 FIXME: add the fork we are opening?
302 if ((opened = of_findname(s_path))) {
303 adsame = opened->of_ad;
306 if ( fork == OPENFORK_DATA ) {
308 adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF;
311 adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF;
312 if (!(access & OPENACC_WR))
313 adflags |= ADFLAGS_NORF;
316 path = s_path->m_name;
317 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
318 adsame, st)) == NULL ) {
319 return( AFPERR_NFILE );
322 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
323 fullpathname(s_path->u_name),
324 (fork == OPENFORK_DATA) ? "data" : "reso",
325 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
328 if (access & OPENACC_WR) {
329 /* try opening in read-write mode */
330 if (ad_open(ofork->of_ad, upath,
331 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
338 if (fork == OPENFORK_DATA) {
339 /* try to open only the data fork */
340 if (ad_open(ofork->of_ad, upath,
341 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
344 adflags = ADFLAGS_DF;
346 /* here's the deal. we only try to create the resource
347 * fork if the user wants to open it for write acess. */
348 if (ad_open(ofork->of_ad, upath,
349 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
351 ofork->of_flags |= AFPFORK_META;
359 ret = AFPERR_BADTYPE;
362 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
368 /* the ressource fork is open too */
369 ofork->of_flags |= AFPFORK_META;
372 /* try opening in read-only mode */
374 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
382 /* see if client asked for a read only data fork */
383 if (fork == OPENFORK_DATA) {
384 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
387 adflags = ADFLAGS_DF;
389 /* else we don't set AFPFORK_META because there's no ressource fork file
390 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
391 * then create in open read-write.
392 * FIXME , it doesn't play well with byte locking example:
393 * ressource fork open read only
394 * locking set on it (no effect, there's no file!)
395 * ressource fork open read write now
403 ret = AFPERR_BADTYPE;
406 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
407 fullpathname(s_path->m_name), strerror(errno) );
411 ofork->of_flags |= AFPFORK_META;
415 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
416 if (ad_setname(ofork->of_ad, path)) {
417 ad_flush( ofork->of_ad );
421 if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
422 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
426 *rbuflen = buflen + 2 * sizeof( uint16_t );
427 bitmap = htons( bitmap );
428 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
429 rbuf += sizeof( uint16_t );
431 /* check WriteInhibit bit if we have a ressource fork
432 * the test is done here, after some Mac trafic capture
434 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
435 ad_getattr(ofork->of_ad, &bshort);
436 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
437 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
440 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
441 return(AFPERR_OLOCK);
446 * synchronization locks:
449 /* don't try to lock non-existent rforks. */
450 if ((eid == ADEID_DFORK)
451 || (ad_reso_fileno(ofork->of_ad) != -1)
452 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
453 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
454 /* can we access the fork? */
456 ofork->of_flags |= AFPFORK_ERROR;
458 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
461 case EAGAIN: /* return data anyway */
465 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
466 return( AFPERR_DENYCONF );
470 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
471 return( AFPERR_PARAM );
474 if ((access & OPENACC_WR))
475 ofork->of_flags |= AFPFORK_ACCWR;
477 /* the file may be open read only without ressource fork */
478 if ((access & OPENACC_RD))
479 ofork->of_flags |= AFPFORK_ACCRD;
481 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
487 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
491 int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
495 uint16_t ofrefnum, bitmap;
503 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
504 ibuf += sizeof( ofrefnum );
506 memcpy(&bitmap, ibuf, sizeof(bitmap));
507 bitmap = ntohs(bitmap);
508 ibuf += sizeof( bitmap );
511 if (NULL == ( ofork = of_find( ofrefnum )) ) {
512 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
513 return( AFPERR_PARAM );
516 if (ofork->of_vol->v_flags & AFPVOL_RO)
519 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
520 return AFPERR_ACCESS;
522 if ( ofork->of_flags & AFPFORK_DATA) {
524 } else if (ofork->of_flags & AFPFORK_RSRC) {
529 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
530 && eid == ADEID_RFORK
532 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
533 && eid == ADEID_DFORK)) {
534 return AFPERR_BITMAP;
538 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
539 if (obj->afp_version >= 30) {
543 return AFPERR_BITMAP;
546 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
547 return AFPERR_PARAM ;
549 size = get_off_t(&ibuf, is64);
552 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
555 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
556 st_size = ad_size(ofork->of_ad, eid);
558 if (st_size > size &&
559 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
560 goto afp_setfork_err;
562 err = ad_dtruncate( ofork->of_ad, size );
564 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
566 goto afp_setfork_err;
567 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
568 ad_refresh(NULL, ofork->of_ad );
570 st_size = ad_size(ofork->of_ad, eid);
572 if (st_size > size &&
573 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
574 goto afp_setfork_err;
576 if (ofork->of_ad->ad_vers == AD_VERSION_EA) {
578 err = sys_lremovexattr(of_name(ofork), AD_EA_RESO);
580 err = unlink(ofork->of_vol->ad_path(of_name(ofork), 0));
583 err = ad_rtruncate(ofork->of_ad, size);
586 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
588 goto afp_setfork_err;
590 if (ad_flush( ofork->of_ad ) < 0) {
591 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
595 return AFPERR_BITMAP;
598 if ( flushfork( ofork ) < 0 ) {
599 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
614 return AFPERR_ACCESS;
625 /* for this to work correctly, we need to check for locks before each
626 * read and write. that's most easily handled by always doing an
627 * appropriate check before each ad_read/ad_write. other things
628 * that can change files like truncate are handled internally to those
631 #define ENDBIT(a) ((a) & 0x80)
632 #define UNLOCKBIT(a) ((a) & 0x01)
635 /* ---------------------- */
636 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
639 off_t offset, length;
647 /* figure out parameters */
649 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
651 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
652 ibuf += sizeof(ofrefnum);
654 if (NULL == ( ofork = of_find( ofrefnum )) ) {
655 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
656 return( AFPERR_PARAM );
659 if ( ofork->of_flags & AFPFORK_DATA) {
661 } else if (ofork->of_flags & AFPFORK_RSRC) {
666 offset = get_off_t(&ibuf, is64);
667 length = get_off_t(&ibuf, is64);
670 length = BYTELOCK_MAX;
671 else if (!length || is_neg(is64, length)) {
673 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
678 offset += ad_size(ofork->of_ad, eid);
679 /* FIXME what do we do if file size > 2 GB and
680 it's not byte_lock_ext?
683 if (offset < 0) /* error if we have a negative offset */
686 /* if the file is a read-only file, we use read locks instead of
687 * write locks. that way, we can prevent anyone from initiating
689 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
690 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
691 ofork->of_refnum) < 0) {
695 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
701 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
709 *rbuflen = set_off_t (offset, rbuf, is64);
713 /* --------------------------- */
714 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
716 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
719 /* --------------------------- */
720 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
722 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
727 static ssize_t read_file(struct ofork *ofork, int eid,
728 off_t offset, u_char nlmask,
729 u_char nlchar, char *rbuf,
736 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
738 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
740 return( AFPERR_PARAM );
742 if ( (size_t)cc < *rbuflen ) {
750 for ( p = rbuf, q = p + cc; p < q; ) {
751 if (( *p++ & nlmask ) == nlchar ) {
763 return( AFPERR_EOF );
768 /* -----------------------------
769 * with ddp, afp_read can return fewer bytes than in reqcount
770 * so return EOF only if read actually past end of file not
771 * if offset +reqcount > size of file
773 * getfork size ==> 10430
774 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
775 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
776 * read fork offset 9248 size 1508 ==> 1182 (EOF)
777 * 10752 is a bug in Mac 7.5.x finder
779 * with dsi, should we check that reqcount < server quantum?
781 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
784 off_t offset, saveoff, reqcount, savereqcount;
788 u_char nlmask, nlchar;
791 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
792 ibuf += sizeof( u_short );
794 if (NULL == ( ofork = of_find( ofrefnum )) ) {
795 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
800 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
804 offset = get_off_t(&ibuf, is64);
805 reqcount = get_off_t(&ibuf, is64);
807 LOG(log_debug, logtype_afpd,
808 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
809 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
818 /* if we wanted to be picky, we could add in the following
819 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
821 if (reqcount < 0 || offset < 0) {
826 if ( ofork->of_flags & AFPFORK_DATA) {
828 } else if (ofork->of_flags & AFPFORK_RSRC) {
830 } else { /* fork wasn't opened. this should never really happen. */
835 /* zero request count */
841 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
842 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
844 savereqcount = reqcount;
846 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
851 *rbuflen = MIN(reqcount, *rbuflen);
852 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
853 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
855 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen);
858 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
859 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
861 /* dsi can stream requests. we can only do this if we're not checking
862 * for an end-of-line character. oh well. */
863 if ((*rbuflen < reqcount) && !nlmask) {
867 /* reqcount isn't always truthful. we need to deal with that. */
868 size = ad_size(ofork->of_ad, eid);
870 /* subtract off the offset */
872 if (reqcount > size) {
879 /* dsi_readinit() returns size of next read buffer. by this point,
880 * we know that we're sending some data. if we fail, something
881 * horrible happened. */
882 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
885 /* due to the nature of afp packets, we have to exit if we get
886 an error. we can't do this with translation on. */
890 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
892 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
893 if (errno == EINVAL || errno == ENOSYS)
896 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
907 /* fill up our buffer. */
908 while (*rbuflen > 0) {
909 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen);
914 /* dsi_read() also returns buffer size of next allocation */
915 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
924 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
926 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
927 obj->exit(EXITERR_CLNT);
931 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
939 /* ---------------------- */
940 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
942 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
945 /* ---------------------- */
946 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
948 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
951 /* ---------------------- */
952 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
960 memcpy(&vid, ibuf, sizeof(vid));
961 if (NULL == ( vol = getvolbyvid( vid )) ) {
962 return( AFPERR_PARAM );
969 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
976 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
978 if (NULL == ( ofork = of_find( ofrefnum )) ) {
979 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
980 return( AFPERR_PARAM );
983 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
984 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
986 if ( flushfork( ofork ) < 0 ) {
987 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
995 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
996 fsync(2) on OSX is implemented differently than on other platforms.
997 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
999 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1001 struct ofork *ofork;
1007 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1008 ibuf += sizeof( ofrefnum );
1010 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1011 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1012 return( AFPERR_PARAM );
1015 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1016 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1018 if ( flushfork( ofork ) < 0 ) {
1019 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1026 /* this is very similar to closefork */
1027 int flushfork(struct ofork *ofork)
1031 int err = 0, doflush = 0;
1033 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1034 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1035 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1036 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1040 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1041 (ofork->of_flags & AFPFORK_RSRC)) {
1043 /* read in the rfork length */
1044 ad_refresh(NULL, ofork->of_ad);
1046 /* set the date if we're dirty */
1047 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1048 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1049 ofork->of_flags &= ~AFPFORK_DIRTY;
1053 /* flush the header */
1054 if (doflush && ad_flush(ofork->of_ad) < 0)
1057 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1061 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1062 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1068 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1070 struct ofork *ofork;
1075 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1077 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1078 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1079 return( AFPERR_PARAM );
1082 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1083 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1085 if ( of_closefork( ofork ) < 0 ) {
1086 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1087 return( AFPERR_PARAM );
1094 static ssize_t write_file(struct ofork *ofork, int eid,
1095 off_t offset, char *rbuf,
1101 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1102 (uintmax_t)offset, rbuflen);
1104 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1105 rbuf, rbuflen)) < 0 ) {
1110 return( AFPERR_DFULL );
1112 return AFPERR_ACCESS;
1114 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1115 return( AFPERR_PARAM );
1123 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1124 * the client may have sent us a bunch of data that's not reflected
1125 * in reqcount et al. */
1126 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1128 struct ofork *ofork;
1129 off_t offset, saveoff, reqcount, oldsize, newsize;
1130 int endflag, eid, err = AFP_OK;
1134 /* figure out parameters */
1136 endflag = ENDBIT(*ibuf);
1138 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1139 ibuf += sizeof( ofrefnum );
1141 offset = get_off_t(&ibuf, is64);
1142 reqcount = get_off_t(&ibuf, is64);
1144 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1145 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1150 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1151 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1153 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1154 err = AFPERR_ACCESS;
1159 writtenfork = ofork;
1162 if ( ofork->of_flags & AFPFORK_DATA) {
1164 } else if (ofork->of_flags & AFPFORK_RSRC) {
1167 err = AFPERR_ACCESS; /* should never happen */
1171 oldsize = ad_size(ofork->of_ad, eid);
1175 /* handle bogus parameters */
1176 if (reqcount < 0 || offset < 0) {
1181 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1183 /* offset can overflow on 64-bit capable filesystems.
1184 * report disk full if that's going to happen. */
1185 if (sum_neg(is64, offset, reqcount)) {
1190 if (!reqcount) { /* handle request counts of 0 */
1192 *rbuflen = set_off_t (offset, rbuf, is64);
1197 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1198 reqcount, ofork->of_refnum) < 0) {
1203 DSI *dsi = obj->dsi;
1204 /* find out what we have already and write it out. */
1205 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1207 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1208 dsi_writeflush(dsi);
1210 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1216 #if 0 /*def HAVE_SENDFILE_WRITE*/
1217 if (!(obj->options.flags & OPTION_DEBUG)) {
1218 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1219 offset, dsi->datasize)) < 0) {
1227 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1228 goto afp_write_loop;
1230 dsi_writeflush(dsi);
1232 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1233 reqcount, ofork->of_refnum);
1238 goto afp_write_done;
1240 #endif /* 0, was HAVE_SENDFILE_WRITE */
1242 /* loop until everything gets written. currently
1243 * dsi_write handles the end case by itself. */
1244 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1245 if ((cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1246 dsi_writeflush(dsi);
1248 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1249 reqcount, ofork->of_refnum);
1255 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1256 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1257 ofork->of_flags |= AFPFORK_DIRTY;
1259 /* we have modified any fork, remember until close_fork */
1260 ofork->of_flags |= AFPFORK_MODIFIED;
1262 /* update write count */
1263 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1265 *rbuflen = set_off_t (offset, rbuf, is64);
1269 dsi_writeinit(obj->dsi, rbuf, *rbuflen);
1270 dsi_writeflush(obj->dsi);
1272 if (err != AFP_OK) {
1278 /* ---------------------------- */
1279 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1281 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1284 /* ----------------------------
1285 * FIXME need to deal with SIGXFSZ signal
1287 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1289 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1292 /* ---------------------------- */
1293 int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1295 struct ofork *ofork;
1297 uint16_t ofrefnum, bitmap;
1300 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1301 ibuf += sizeof( ofrefnum );
1302 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1303 bitmap = ntohs( bitmap );
1304 ibuf += sizeof( bitmap );
1307 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1308 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1309 return( AFPERR_PARAM );
1312 if (AD_META_OPEN(ofork->of_ad)) {
1313 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1314 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1315 return( AFPERR_PARAM );
1319 if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1323 *rbuflen = buflen + sizeof( u_short );
1324 bitmap = htons( bitmap );
1325 memcpy(rbuf, &bitmap, sizeof( bitmap ));