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 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s)",
270 fullpathname(s_path->u_name), (fork & OPENFORK_RSCS) ? "RSRC" : "DATA");
272 /* stat() data fork st is set because it's not a dir */
273 switch ( s_path->st_errno ) {
279 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
281 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
284 /* FIXME should we check it first ? */
285 upath = s_path->u_name;
286 if (!vol_unix_priv(vol)) {
287 if (check_access(upath, access ) < 0) {
288 return AFPERR_ACCESS;
291 if (file_access(s_path, access ) < 0) {
292 return AFPERR_ACCESS;
297 /* XXX: this probably isn't the best way to do this. the already
298 open bits should really be set if the fork is opened by any
299 program, not just this one. however, that's problematic to do
300 if we can't write lock files somewhere. opened is also passed to
301 ad_open so that we can keep file locks together.
302 FIXME: add the fork we are opening?
304 if ((opened = of_findname(s_path))) {
305 adsame = opened->of_ad;
308 if ( fork == OPENFORK_DATA ) {
310 adflags = ADFLAGS_DF | ADFLAGS_HF ;
313 adflags = ADFLAGS_RF | ADFLAGS_HF;
316 path = s_path->m_name;
317 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
318 adsame, st)) == NULL ) {
319 return( AFPERR_NFILE );
323 if (access & OPENACC_WR) {
324 /* try opening in read-write mode */
325 if (ad_open(ofork->of_ad, upath,
326 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
333 if (fork == OPENFORK_DATA) {
334 /* try to open only the data fork */
335 if (ad_open(ofork->of_ad, upath,
336 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
339 adflags = ADFLAGS_DF;
341 /* here's the deal. we only try to create the resource
342 * fork if the user wants to open it for write acess. */
343 if (ad_open(ofork->of_ad, upath,
344 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
346 ofork->of_flags |= AFPFORK_META;
354 ret = AFPERR_BADTYPE;
357 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
363 /* the ressource fork is open too */
364 ofork->of_flags |= AFPFORK_META;
367 /* try opening in read-only mode */
369 /* we need w access for setting deny mode fcntl excl lock */
370 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
378 /* see if client asked for a read only data fork */
379 if (fork == OPENFORK_DATA) {
380 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
383 adflags = ADFLAGS_DF;
385 /* else we don't set AFPFORK_META because there's no ressource fork file
386 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
387 * then create in open read-write.
388 * FIXME , it doesn't play well with byte locking example:
389 * ressource fork open read only
390 * locking set on it (no effect, there's no file!)
391 * ressource fork open read write now
399 ret = AFPERR_BADTYPE;
402 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
403 fullpathname(s_path->m_name), strerror(errno) );
407 ofork->of_flags |= AFPFORK_META;
411 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
412 if (ad_setname(ofork->of_ad, path)) {
413 ad_flush( ofork->of_ad );
417 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
418 ad_close( ofork->of_ad, adflags );
422 *rbuflen = buflen + 2 * sizeof( uint16_t );
423 bitmap = htons( bitmap );
424 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
425 rbuf += sizeof( uint16_t );
427 /* check WriteInhibit bit if we have a ressource fork
428 * the test is done here, after some Mac trafic capture
430 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
431 ad_getattr(ofork->of_ad, &bshort);
432 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
433 ad_close( ofork->of_ad, adflags );
436 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
437 return(AFPERR_OLOCK);
442 * synchronization locks:
445 /* don't try to lock non-existent rforks. */
446 if ((eid == ADEID_DFORK) || (ad_reso_fileno(ofork->of_ad) != -1)) {
448 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
449 /* can we access the fork? */
452 ad_close( ofork->of_ad, adflags );
455 case EAGAIN: /* return data anyway */
459 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
460 return( AFPERR_DENYCONF );
464 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
465 return( AFPERR_PARAM );
468 if ((access & OPENACC_WR))
469 ofork->of_flags |= AFPFORK_ACCWR;
471 /* the file may be open read only without ressource fork */
472 if ((access & OPENACC_RD))
473 ofork->of_flags |= AFPFORK_ACCRD;
475 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
481 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
485 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
489 uint16_t ofrefnum, bitmap;
497 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
498 ibuf += sizeof( ofrefnum );
500 memcpy(&bitmap, ibuf, sizeof(bitmap));
501 bitmap = ntohs(bitmap);
502 ibuf += sizeof( bitmap );
505 if (NULL == ( ofork = of_find( ofrefnum )) ) {
506 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
507 return( AFPERR_PARAM );
510 if (ofork->of_vol->v_flags & AFPVOL_RO)
513 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
514 return AFPERR_ACCESS;
516 if ( ofork->of_flags & AFPFORK_DATA) {
518 } else if (ofork->of_flags & AFPFORK_RSRC) {
523 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
524 && eid == ADEID_RFORK
526 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
527 && eid == ADEID_DFORK)) {
528 return AFPERR_BITMAP;
532 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
533 if (afp_version >= 30) {
537 return AFPERR_BITMAP;
540 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
541 return AFPERR_PARAM ;
543 size = get_off_t(&ibuf, is64);
546 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
549 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
550 st_size = ad_size(ofork->of_ad, eid);
552 if (st_size > size &&
553 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
554 goto afp_setfork_err;
556 err = ad_dtruncate( ofork->of_ad, size );
558 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
560 goto afp_setfork_err;
561 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
562 ad_refresh(NULL, ofork->of_ad );
564 st_size = ad_size(ofork->of_ad, eid);
566 if (st_size > size &&
567 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
568 goto afp_setfork_err;
570 err = ad_rtruncate(ofork->of_ad, size);
572 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
574 goto afp_setfork_err;
576 if (ad_flush( ofork->of_ad ) < 0) {
577 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
581 return AFPERR_BITMAP;
584 if ( flushfork( ofork ) < 0 ) {
585 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
600 return AFPERR_ACCESS;
611 /* for this to work correctly, we need to check for locks before each
612 * read and write. that's most easily handled by always doing an
613 * appropriate check before each ad_read/ad_write. other things
614 * that can change files like truncate are handled internally to those
617 #define ENDBIT(a) ((a) & 0x80)
618 #define UNLOCKBIT(a) ((a) & 0x01)
621 /* ---------------------- */
622 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
625 off_t offset, length;
633 /* figure out parameters */
635 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
637 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
638 ibuf += sizeof(ofrefnum);
640 if (NULL == ( ofork = of_find( ofrefnum )) ) {
641 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
642 return( AFPERR_PARAM );
645 if ( ofork->of_flags & AFPFORK_DATA) {
647 } else if (ofork->of_flags & AFPFORK_RSRC) {
652 offset = get_off_t(&ibuf, is64);
653 length = get_off_t(&ibuf, is64);
655 /* FIXME AD_FILELOCK test is surely wrong */
657 length = BYTELOCK_MAX;
658 else if (!length || is_neg(is64, length)) {
660 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
665 offset += ad_size(ofork->of_ad, eid);
666 /* FIXME what do we do if file size > 2 GB and
667 it's not byte_lock_ext?
670 if (offset < 0) /* error if we have a negative offset */
673 /* if the file is a read-only file, we use read locks instead of
674 * write locks. that way, we can prevent anyone from initiating
676 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
677 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
678 ofork->of_refnum) < 0) {
682 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
688 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
696 *rbuflen = set_off_t (offset, rbuf, is64);
700 /* --------------------------- */
701 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
703 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
706 /* --------------------------- */
707 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
709 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
714 /* --------------------------- */
715 static int crlf(struct ofork *of)
719 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
720 /* no resource fork or no finderinfo, use our files extension mapping */
721 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
724 /* file type is TEXT */
727 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
734 static ssize_t read_file(struct ofork *ofork, int eid,
735 off_t offset, u_char nlmask,
736 u_char nlchar, char *rbuf,
737 size_t *rbuflen, const int xlate)
743 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
745 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
747 return( AFPERR_PARAM );
749 if ( (size_t)cc < *rbuflen ) {
757 for ( p = rbuf, q = p + cc; p < q; ) {
758 if (( *p++ & nlmask ) == nlchar ) {
769 * If this file is of type TEXT, then swap \012 to \015.
772 for ( p = rbuf, q = p + cc; p < q; p++ ) {
773 if ( *p == '\012' ) {
775 } else if ( *p == '\015' ) {
784 return( AFPERR_EOF );
789 /* -----------------------------
790 * with ddp, afp_read can return fewer bytes than in reqcount
791 * so return EOF only if read actually past end of file not
792 * if offset +reqcount > size of file
794 * getfork size ==> 10430
795 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
796 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
797 * read fork offset 9248 size 1508 ==> 1182 (EOF)
798 * 10752 is a bug in Mac 7.5.x finder
800 * with dsi, should we check that reqcount < server quantum?
802 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
805 off_t offset, saveoff, reqcount, savereqcount;
809 u_char nlmask, nlchar;
812 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
813 ibuf += sizeof( u_short );
815 if (NULL == ( ofork = of_find( ofrefnum )) ) {
816 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
821 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
825 offset = get_off_t(&ibuf, is64);
826 reqcount = get_off_t(&ibuf, is64);
828 LOG(log_debug, logtype_afpd,
829 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
830 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
839 /* if we wanted to be picky, we could add in the following
840 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
842 if (reqcount < 0 || offset < 0) {
847 if ( ofork->of_flags & AFPFORK_DATA) {
849 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
850 } else if (ofork->of_flags & AFPFORK_RSRC) {
852 } else { /* fork wasn't opened. this should never really happen. */
857 /* zero request count */
863 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
864 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
866 savereqcount = reqcount;
868 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
873 *rbuflen = MIN(reqcount, *rbuflen);
874 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
875 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
877 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
880 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
881 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
883 /* dsi can stream requests. we can only do this if we're not checking
884 * for an end-of-line character. oh well. */
885 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
886 DSI *dsi = obj->handle;
889 /* reqcount isn't always truthful. we need to deal with that. */
890 size = ad_size(ofork->of_ad, eid);
892 /* subtract off the offset */
894 if (reqcount > size) {
901 /* dsi_readinit() returns size of next read buffer. by this point,
902 * we know that we're sending some data. if we fail, something
903 * horrible happened. */
904 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
907 /* due to the nature of afp packets, we have to exit if we get
908 an error. we can't do this with translation on. */
913 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
915 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
916 if (errno == EINVAL || errno == ENOSYS)
919 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
931 /* fill up our buffer. */
932 while (*rbuflen > 0) {
933 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
938 /* dsi_read() also returns buffer size of next allocation */
939 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
948 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
950 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
951 obj->exit(EXITERR_CLNT);
955 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
963 /* ---------------------- */
964 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
966 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
969 /* ---------------------- */
970 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
972 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
975 /* ---------------------- */
976 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
984 memcpy(&vid, ibuf, sizeof(vid));
985 if (NULL == ( vol = getvolbyvid( vid )) ) {
986 return( AFPERR_PARAM );
993 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1000 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1002 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1003 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1004 return( AFPERR_PARAM );
1007 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
1008 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1010 if ( flushfork( ofork ) < 0 ) {
1011 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1019 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1020 fsync(2) on OSX is implemented differently than on other platforms.
1021 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1023 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1025 struct ofork *ofork;
1031 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1032 ibuf += sizeof( ofrefnum );
1034 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1035 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1036 return( AFPERR_PARAM );
1039 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1040 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1042 if ( flushfork( ofork ) < 0 ) {
1043 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1050 /* this is very similar to closefork */
1051 int flushfork(struct ofork *ofork)
1055 int err = 0, doflush = 0;
1057 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1058 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1059 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1060 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1064 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1065 (ofork->of_flags & AFPFORK_RSRC)) {
1067 /* read in the rfork length */
1068 ad_refresh(NULL, ofork->of_ad);
1070 /* set the date if we're dirty */
1071 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1072 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1073 ofork->of_flags &= ~AFPFORK_DIRTY;
1077 /* flush the header */
1078 if (doflush && ad_flush(ofork->of_ad) < 0)
1081 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1085 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1086 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1092 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1094 struct ofork *ofork;
1099 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1101 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1102 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1103 return( AFPERR_PARAM );
1106 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1107 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1109 if ( of_closefork( ofork ) < 0 ) {
1110 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1111 return( AFPERR_PARAM );
1118 static ssize_t write_file(struct ofork *ofork, int eid,
1119 off_t offset, char *rbuf,
1120 size_t rbuflen, const int xlate)
1126 * If this file is of type TEXT, swap \015 to \012.
1129 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1130 if ( *p == '\015' ) {
1132 } else if ( *p == '\012' ) {
1138 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1139 (uintmax_t)offset, rbuflen);
1141 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1142 rbuf, rbuflen)) < 0 ) {
1147 return( AFPERR_DFULL );
1149 return AFPERR_ACCESS;
1151 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1152 return( AFPERR_PARAM );
1160 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1161 * the client may have sent us a bunch of data that's not reflected
1162 * in reqcount et al. */
1163 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1165 struct ofork *ofork;
1166 off_t offset, saveoff, reqcount, oldsize, newsize;
1167 int endflag, eid, xlate = 0, err = AFP_OK;
1171 /* figure out parameters */
1173 endflag = ENDBIT(*ibuf);
1175 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1176 ibuf += sizeof( ofrefnum );
1178 offset = get_off_t(&ibuf, is64);
1179 reqcount = get_off_t(&ibuf, is64);
1181 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1182 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1187 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1188 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1190 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1191 err = AFPERR_ACCESS;
1196 writtenfork = ofork;
1199 if ( ofork->of_flags & AFPFORK_DATA) {
1201 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1202 } else if (ofork->of_flags & AFPFORK_RSRC) {
1205 err = AFPERR_ACCESS; /* should never happen */
1209 oldsize = ad_size(ofork->of_ad, eid);
1213 /* handle bogus parameters */
1214 if (reqcount < 0 || offset < 0) {
1219 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1221 /* offset can overflow on 64-bit capable filesystems.
1222 * report disk full if that's going to happen. */
1223 if (sum_neg(is64, offset, reqcount)) {
1228 if (!reqcount) { /* handle request counts of 0 */
1230 *rbuflen = set_off_t (offset, rbuf, is64);
1235 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1236 reqcount, ofork->of_refnum) < 0) {
1241 /* this is yucky, but dsi can stream i/o and asp can't */
1242 switch (obj->proto) {
1245 DSI *dsi = obj->handle;
1246 /* find out what we have already and write it out. */
1247 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1249 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1250 dsi_writeflush(dsi);
1252 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1258 #if 0 /*def HAVE_SENDFILE_WRITE*/
1259 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1260 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1261 offset, dsi->datasize)) < 0) {
1269 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1270 goto afp_write_loop;
1272 dsi_writeflush(dsi);
1274 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1275 reqcount, ofork->of_refnum);
1280 goto afp_write_done;
1282 #endif /* 0, was HAVE_SENDFILE_WRITE */
1284 /* loop until everything gets written. currently
1285 * dsi_write handles the end case by itself. */
1286 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1287 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1288 dsi_writeflush(dsi);
1290 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1291 reqcount, ofork->of_refnum);
1300 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1301 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1302 ofork->of_flags |= AFPFORK_DIRTY;
1304 /* we have modified any fork, remember until close_fork */
1305 ofork->of_flags |= AFPFORK_MODIFIED;
1307 /* update write count */
1308 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1310 *rbuflen = set_off_t (offset, rbuf, is64);
1314 if (obj->proto == AFPPROTO_DSI) {
1315 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1316 dsi_writeflush(obj->handle);
1318 if (err != AFP_OK) {
1324 /* ---------------------------- */
1325 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1327 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1330 /* ----------------------------
1331 * FIXME need to deal with SIGXFSZ signal
1333 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1335 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1338 /* ---------------------------- */
1339 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1341 struct ofork *ofork;
1343 uint16_t ofrefnum, bitmap;
1346 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1347 ibuf += sizeof( ofrefnum );
1348 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1349 bitmap = ntohs( bitmap );
1350 ibuf += sizeof( bitmap );
1353 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1354 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1355 return( AFPERR_PARAM );
1358 if (AD_META_OPEN(ofork->of_ad)) {
1359 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1360 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1361 return( AFPERR_PARAM );
1365 if (AFP_OK != (ret = getforkparams(ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1369 *rbuflen = buflen + sizeof( u_short );
1370 bitmap = htons( bitmap );
1371 memcpy(rbuf, &bitmap, sizeof( bitmap ));