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>
30 #include "directory.h"
35 struct ofork *writtenfork;
38 static int getforkparams(struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen)
48 /* can only get the length of the opened fork */
49 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
50 && (ofork->of_flags & AFPFORK_RSRC))
52 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
53 && (ofork->of_flags & AFPFORK_DATA))) {
54 return( AFPERR_BITMAP );
57 if (! AD_META_OPEN(ofork->of_ad)) {
64 dir = dirlookup(vol, ofork->of_did);
66 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
67 return( AFPERR_MISC );
69 path.m_name = of_name(ofork);
72 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
73 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
74 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
75 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
76 /* 0 is for symlink */
77 if (movecwd(vol, dir) < 0)
78 return( AFPERR_NOOBJ );
79 if ( lstat( path.u_name, st ) < 0 )
80 return( AFPERR_NOOBJ );
82 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
83 return( AFPERR_BITMAP );
87 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
90 static off_t get_off_t(char **ibuf, int is64)
96 memcpy(&temp, *ibuf, sizeof( temp ));
97 ret = ntohl(temp); /* ntohl is unsigned */
98 *ibuf += sizeof(temp);
101 memcpy(&temp, *ibuf, sizeof( temp ));
102 *ibuf += sizeof(temp);
103 ret = ntohl(temp)| (ret << 32);
106 ret = (int)ret; /* sign extend */
111 static int set_off_t(off_t offset, char *rbuf, int is64)
118 temp = htonl(offset >> 32);
119 memcpy(rbuf, &temp, sizeof( temp ));
120 rbuf += sizeof(temp);
121 ret = sizeof( temp );
122 offset &= 0xffffffff;
124 temp = htonl(offset);
125 memcpy(rbuf, &temp, sizeof( temp ));
126 ret += sizeof( temp );
131 static int is_neg(int is64, off_t val)
133 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
138 static int sum_neg(int is64, off_t offset, off_t reqcount)
140 if (is_neg(is64, offset +reqcount) )
145 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
153 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
154 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
157 if ((access & (OPENACC_RD | OPENACC_DRD))) {
158 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
160 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
163 if ((access & OPENACC_RD) && denyreadset) {
167 if ((access & OPENACC_DRD) && readset) {
171 /* boolean logic is not enough, because getforkmode is not always telling the
174 if ((access & OPENACC_RD)) {
175 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
179 if ((access & OPENACC_DRD)) {
180 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
185 /* ------------same for writing -------------- */
186 if ((access & (OPENACC_WR | OPENACC_DWR))) {
187 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
189 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
192 if ((access & OPENACC_WR) && denywriteset) {
196 if ((access & OPENACC_DWR) && writeset) {
200 if ((access & OPENACC_WR)) {
201 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
205 if ((access & OPENACC_DWR)) {
206 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
215 /* ----------------------- */
216 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
220 struct ofork *ofork, *opened;
221 struct adouble *adsame = NULL;
223 int ret, adflags, eid;
225 uint16_t vid, bitmap, access, ofrefnum;
226 char fork, *path, *upath;
234 memcpy(&vid, ibuf, sizeof( vid ));
238 if (NULL == ( vol = getvolbyvid( vid ))) {
239 return( AFPERR_PARAM );
242 memcpy(&did, ibuf, sizeof( did ));
243 ibuf += sizeof( int );
245 if (NULL == ( dir = dirlookup( vol, did ))) {
249 memcpy(&bitmap, ibuf, sizeof( bitmap ));
250 bitmap = ntohs( bitmap );
251 ibuf += sizeof( bitmap );
252 memcpy(&access, ibuf, sizeof( access ));
253 access = ntohs( access );
254 ibuf += sizeof( access );
256 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
260 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
261 return get_afp_errno(AFPERR_PARAM);
264 if (*s_path->m_name == '\0') {
266 return AFPERR_BADTYPE;
269 /* stat() data fork st is set because it's not a dir */
270 switch ( s_path->st_errno ) {
276 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
278 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
281 /* FIXME should we check it first ? */
282 upath = s_path->u_name;
283 if (!vol_unix_priv(vol)) {
284 if (check_access(upath, access ) < 0) {
285 return AFPERR_ACCESS;
288 if (file_access(s_path, access ) < 0) {
289 return AFPERR_ACCESS;
294 /* XXX: this probably isn't the best way to do this. the already
295 open bits should really be set if the fork is opened by any
296 program, not just this one. however, that's problematic to do
297 if we can't write lock files somewhere. opened is also passed to
298 ad_open so that we can keep file locks together.
299 FIXME: add the fork we are opening?
301 if ((opened = of_findname(s_path))) {
302 adsame = opened->of_ad;
305 if ( fork == OPENFORK_DATA ) {
307 adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF;
310 adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF;
311 if (!(access & OPENACC_WR))
312 adflags |= ADFLAGS_NORF;
315 path = s_path->m_name;
316 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
317 adsame, st)) == NULL ) {
318 return( AFPERR_NFILE );
321 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
322 fullpathname(s_path->u_name),
323 (fork == OPENFORK_DATA) ? "data" : "reso",
324 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
327 if (access & OPENACC_WR) {
328 /* try opening in read-write mode */
329 if (ad_open(ofork->of_ad, upath,
330 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
337 if (fork == OPENFORK_DATA) {
338 /* try to open only the data fork */
339 if (ad_open(ofork->of_ad, upath,
340 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
343 adflags = ADFLAGS_DF;
345 /* here's the deal. we only try to create the resource
346 * fork if the user wants to open it for write acess. */
347 if (ad_open(ofork->of_ad, upath,
348 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
350 ofork->of_flags |= AFPFORK_META;
358 ret = AFPERR_BADTYPE;
361 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
367 /* the ressource fork is open too */
368 ofork->of_flags |= AFPFORK_META;
371 /* try opening in read-only mode */
373 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
381 /* see if client asked for a read only data fork */
382 if (fork == OPENFORK_DATA) {
383 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
386 adflags = ADFLAGS_DF;
388 /* else we don't set AFPFORK_META because there's no ressource fork file
389 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
390 * then create in open read-write.
391 * FIXME , it doesn't play well with byte locking example:
392 * ressource fork open read only
393 * locking set on it (no effect, there's no file!)
394 * ressource fork open read write now
402 ret = AFPERR_BADTYPE;
405 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
406 fullpathname(s_path->m_name), strerror(errno) );
410 ofork->of_flags |= AFPFORK_META;
414 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
415 if (ad_setname(ofork->of_ad, path)) {
416 ad_flush( ofork->of_ad );
420 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
421 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
425 *rbuflen = buflen + 2 * sizeof( uint16_t );
426 bitmap = htons( bitmap );
427 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
428 rbuf += sizeof( uint16_t );
430 /* check WriteInhibit bit if we have a ressource fork
431 * the test is done here, after some Mac trafic capture
433 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
434 ad_getattr(ofork->of_ad, &bshort);
435 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
436 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
439 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
440 return(AFPERR_OLOCK);
445 * synchronization locks:
448 /* don't try to lock non-existent rforks. */
449 if ((eid == ADEID_DFORK)
450 || (ad_reso_fileno(ofork->of_ad) != -1)
451 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
452 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
453 /* can we access the fork? */
455 ofork->of_flags |= AFPFORK_ERROR;
457 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
460 case EAGAIN: /* return data anyway */
464 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
465 return( AFPERR_DENYCONF );
469 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
470 return( AFPERR_PARAM );
473 if ((access & OPENACC_WR))
474 ofork->of_flags |= AFPFORK_ACCWR;
476 /* the file may be open read only without ressource fork */
477 if ((access & OPENACC_RD))
478 ofork->of_flags |= AFPFORK_ACCRD;
480 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
486 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
490 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
494 uint16_t ofrefnum, bitmap;
502 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
503 ibuf += sizeof( ofrefnum );
505 memcpy(&bitmap, ibuf, sizeof(bitmap));
506 bitmap = ntohs(bitmap);
507 ibuf += sizeof( bitmap );
510 if (NULL == ( ofork = of_find( ofrefnum )) ) {
511 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
512 return( AFPERR_PARAM );
515 if (ofork->of_vol->v_flags & AFPVOL_RO)
518 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
519 return AFPERR_ACCESS;
521 if ( ofork->of_flags & AFPFORK_DATA) {
523 } else if (ofork->of_flags & AFPFORK_RSRC) {
528 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
529 && eid == ADEID_RFORK
531 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
532 && eid == ADEID_DFORK)) {
533 return AFPERR_BITMAP;
537 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
538 if (afp_version >= 30) {
542 return AFPERR_BITMAP;
545 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
546 return AFPERR_PARAM ;
548 size = get_off_t(&ibuf, is64);
551 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
554 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
555 st_size = ad_size(ofork->of_ad, eid);
557 if (st_size > size &&
558 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
559 goto afp_setfork_err;
561 err = ad_dtruncate( ofork->of_ad, size );
563 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
565 goto afp_setfork_err;
566 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
567 ad_refresh(NULL, ofork->of_ad );
569 st_size = ad_size(ofork->of_ad, eid);
571 if (st_size > size &&
572 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
573 goto afp_setfork_err;
575 err = ad_rtruncate(ofork->of_ad, size);
577 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
579 goto afp_setfork_err;
581 if (ad_flush( ofork->of_ad ) < 0) {
582 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
586 return AFPERR_BITMAP;
589 if ( flushfork( ofork ) < 0 ) {
590 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
605 return AFPERR_ACCESS;
616 /* for this to work correctly, we need to check for locks before each
617 * read and write. that's most easily handled by always doing an
618 * appropriate check before each ad_read/ad_write. other things
619 * that can change files like truncate are handled internally to those
622 #define ENDBIT(a) ((a) & 0x80)
623 #define UNLOCKBIT(a) ((a) & 0x01)
626 /* ---------------------- */
627 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
630 off_t offset, length;
638 /* figure out parameters */
640 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
642 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
643 ibuf += sizeof(ofrefnum);
645 if (NULL == ( ofork = of_find( ofrefnum )) ) {
646 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
647 return( AFPERR_PARAM );
650 if ( ofork->of_flags & AFPFORK_DATA) {
652 } else if (ofork->of_flags & AFPFORK_RSRC) {
657 offset = get_off_t(&ibuf, is64);
658 length = get_off_t(&ibuf, is64);
661 length = BYTELOCK_MAX;
662 else if (!length || is_neg(is64, length)) {
664 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
669 offset += ad_size(ofork->of_ad, eid);
670 /* FIXME what do we do if file size > 2 GB and
671 it's not byte_lock_ext?
674 if (offset < 0) /* error if we have a negative offset */
677 /* if the file is a read-only file, we use read locks instead of
678 * write locks. that way, we can prevent anyone from initiating
680 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
681 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
682 ofork->of_refnum) < 0) {
686 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
692 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
700 *rbuflen = set_off_t (offset, rbuf, is64);
704 /* --------------------------- */
705 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
707 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
710 /* --------------------------- */
711 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
713 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
718 static ssize_t read_file(struct ofork *ofork, int eid,
719 off_t offset, u_char nlmask,
720 u_char nlchar, char *rbuf,
727 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
729 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
731 return( AFPERR_PARAM );
733 if ( (size_t)cc < *rbuflen ) {
741 for ( p = rbuf, q = p + cc; p < q; ) {
742 if (( *p++ & nlmask ) == nlchar ) {
754 return( AFPERR_EOF );
759 /* -----------------------------
760 * with ddp, afp_read can return fewer bytes than in reqcount
761 * so return EOF only if read actually past end of file not
762 * if offset +reqcount > size of file
764 * getfork size ==> 10430
765 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
766 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
767 * read fork offset 9248 size 1508 ==> 1182 (EOF)
768 * 10752 is a bug in Mac 7.5.x finder
770 * with dsi, should we check that reqcount < server quantum?
772 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
775 off_t offset, saveoff, reqcount, savereqcount;
779 u_char nlmask, nlchar;
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) {
795 offset = get_off_t(&ibuf, is64);
796 reqcount = get_off_t(&ibuf, is64);
798 LOG(log_debug, logtype_afpd,
799 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
800 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
809 /* if we wanted to be picky, we could add in the following
810 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
812 if (reqcount < 0 || offset < 0) {
817 if ( ofork->of_flags & AFPFORK_DATA) {
819 } else if (ofork->of_flags & AFPFORK_RSRC) {
821 } else { /* fork wasn't opened. this should never really happen. */
826 /* zero request count */
832 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
833 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
835 savereqcount = reqcount;
837 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
842 *rbuflen = MIN(reqcount, *rbuflen);
843 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
844 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
846 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen);
849 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
850 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
852 /* dsi can stream requests. we can only do this if we're not checking
853 * for an end-of-line character. oh well. */
854 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
858 /* reqcount isn't always truthful. we need to deal with that. */
859 size = ad_size(ofork->of_ad, eid);
861 /* subtract off the offset */
863 if (reqcount > size) {
870 /* dsi_readinit() returns size of next read buffer. by this point,
871 * we know that we're sending some data. if we fail, something
872 * horrible happened. */
873 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
876 /* due to the nature of afp packets, we have to exit if we get
877 an error. we can't do this with translation on. */
881 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
883 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
884 if (errno == EINVAL || errno == ENOSYS)
887 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
898 /* fill up our buffer. */
899 while (*rbuflen > 0) {
900 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen);
905 /* dsi_read() also returns buffer size of next allocation */
906 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
915 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
917 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
918 obj->exit(EXITERR_CLNT);
922 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
930 /* ---------------------- */
931 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
933 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
936 /* ---------------------- */
937 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
939 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
942 /* ---------------------- */
943 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
951 memcpy(&vid, ibuf, sizeof(vid));
952 if (NULL == ( vol = getvolbyvid( vid )) ) {
953 return( AFPERR_PARAM );
960 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
967 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
969 if (NULL == ( ofork = of_find( ofrefnum )) ) {
970 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
971 return( AFPERR_PARAM );
974 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
975 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
977 if ( flushfork( ofork ) < 0 ) {
978 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
986 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
987 fsync(2) on OSX is implemented differently than on other platforms.
988 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
990 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
998 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
999 ibuf += sizeof( ofrefnum );
1001 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1002 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1003 return( AFPERR_PARAM );
1006 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1007 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1009 if ( flushfork( ofork ) < 0 ) {
1010 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1017 /* this is very similar to closefork */
1018 int flushfork(struct ofork *ofork)
1022 int err = 0, doflush = 0;
1024 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1025 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1026 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1027 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1031 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1032 (ofork->of_flags & AFPFORK_RSRC)) {
1034 /* read in the rfork length */
1035 ad_refresh(NULL, ofork->of_ad);
1037 /* set the date if we're dirty */
1038 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1039 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1040 ofork->of_flags &= ~AFPFORK_DIRTY;
1044 /* flush the header */
1045 if (doflush && ad_flush(ofork->of_ad) < 0)
1048 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1052 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1053 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1059 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1061 struct ofork *ofork;
1066 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1068 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1069 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1070 return( AFPERR_PARAM );
1073 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1074 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1076 if ( of_closefork( ofork ) < 0 ) {
1077 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1078 return( AFPERR_PARAM );
1085 static ssize_t write_file(struct ofork *ofork, int eid,
1086 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 return( AFPERR_DFULL );
1103 return AFPERR_ACCESS;
1105 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1106 return( AFPERR_PARAM );
1114 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1115 * the client may have sent us a bunch of data that's not reflected
1116 * in reqcount et al. */
1117 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1119 struct ofork *ofork;
1120 off_t offset, saveoff, reqcount, oldsize, newsize;
1121 int endflag, eid, err = AFP_OK;
1125 /* figure out parameters */
1127 endflag = ENDBIT(*ibuf);
1129 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1130 ibuf += sizeof( ofrefnum );
1132 offset = get_off_t(&ibuf, is64);
1133 reqcount = get_off_t(&ibuf, is64);
1135 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1136 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1141 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1142 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1144 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1145 err = AFPERR_ACCESS;
1150 writtenfork = ofork;
1153 if ( ofork->of_flags & AFPFORK_DATA) {
1155 } else if (ofork->of_flags & AFPFORK_RSRC) {
1158 err = AFPERR_ACCESS; /* should never happen */
1162 oldsize = ad_size(ofork->of_ad, eid);
1166 /* handle bogus parameters */
1167 if (reqcount < 0 || offset < 0) {
1172 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1174 /* offset can overflow on 64-bit capable filesystems.
1175 * report disk full if that's going to happen. */
1176 if (sum_neg(is64, offset, reqcount)) {
1181 if (!reqcount) { /* handle request counts of 0 */
1183 *rbuflen = set_off_t (offset, rbuf, is64);
1188 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1189 reqcount, ofork->of_refnum) < 0) {
1194 /* this is yucky, but dsi can stream i/o and asp can't */
1195 switch (obj->proto) {
1198 DSI *dsi = obj->dsi;
1199 /* find out what we have already and write it out. */
1200 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1202 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1203 dsi_writeflush(dsi);
1205 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1211 #if 0 /*def HAVE_SENDFILE_WRITE*/
1212 if (!(obj->options.flags & OPTION_DEBUG)) {
1213 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1214 offset, dsi->datasize)) < 0) {
1222 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1223 goto afp_write_loop;
1225 dsi_writeflush(dsi);
1227 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1228 reqcount, ofork->of_refnum);
1233 goto afp_write_done;
1235 #endif /* 0, was HAVE_SENDFILE_WRITE */
1237 /* loop until everything gets written. currently
1238 * dsi_write handles the end case by itself. */
1239 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1240 if ((cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1241 dsi_writeflush(dsi);
1243 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1244 reqcount, ofork->of_refnum);
1253 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1254 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1255 ofork->of_flags |= AFPFORK_DIRTY;
1257 /* we have modified any fork, remember until close_fork */
1258 ofork->of_flags |= AFPFORK_MODIFIED;
1260 /* update write count */
1261 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1263 *rbuflen = set_off_t (offset, rbuf, is64);
1267 if (obj->proto == AFPPROTO_DSI) {
1268 dsi_writeinit(obj->dsi, rbuf, *rbuflen);
1269 dsi_writeflush(obj->dsi);
1271 if (err != AFP_OK) {
1277 /* ---------------------------- */
1278 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1280 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1283 /* ----------------------------
1284 * FIXME need to deal with SIGXFSZ signal
1286 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1288 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1291 /* ---------------------------- */
1292 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1294 struct ofork *ofork;
1296 uint16_t ofrefnum, bitmap;
1299 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1300 ibuf += sizeof( ofrefnum );
1301 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1302 bitmap = ntohs( bitmap );
1303 ibuf += sizeof( bitmap );
1306 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1307 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1308 return( AFPERR_PARAM );
1311 if (AD_META_OPEN(ofork->of_ad)) {
1312 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1313 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1314 return( AFPERR_PARAM );
1318 if (AFP_OK != (ret = getforkparams(ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1322 *rbuflen = buflen + sizeof( u_short );
1323 bitmap = htons( bitmap );
1324 memcpy(rbuf, &bitmap, sizeof( bitmap ));