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)
447 || (ad_meta_fileno(ofork->of_ad) != -1)
448 || (vol->v_adouble & AD_VERSION_EA)) { /* META */
450 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
451 /* can we access the fork? */
454 ad_close( ofork->of_ad, adflags );
457 case EAGAIN: /* return data anyway */
461 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
462 return( AFPERR_DENYCONF );
466 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
467 return( AFPERR_PARAM );
470 if ((access & OPENACC_WR))
471 ofork->of_flags |= AFPFORK_ACCWR;
473 /* the file may be open read only without ressource fork */
474 if ((access & OPENACC_RD))
475 ofork->of_flags |= AFPFORK_ACCRD;
477 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
483 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
487 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
491 uint16_t ofrefnum, bitmap;
499 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
500 ibuf += sizeof( ofrefnum );
502 memcpy(&bitmap, ibuf, sizeof(bitmap));
503 bitmap = ntohs(bitmap);
504 ibuf += sizeof( bitmap );
507 if (NULL == ( ofork = of_find( ofrefnum )) ) {
508 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
509 return( AFPERR_PARAM );
512 if (ofork->of_vol->v_flags & AFPVOL_RO)
515 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
516 return AFPERR_ACCESS;
518 if ( ofork->of_flags & AFPFORK_DATA) {
520 } else if (ofork->of_flags & AFPFORK_RSRC) {
525 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
526 && eid == ADEID_RFORK
528 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
529 && eid == ADEID_DFORK)) {
530 return AFPERR_BITMAP;
534 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
535 if (afp_version >= 30) {
539 return AFPERR_BITMAP;
542 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
543 return AFPERR_PARAM ;
545 size = get_off_t(&ibuf, is64);
548 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
551 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
552 st_size = ad_size(ofork->of_ad, eid);
554 if (st_size > size &&
555 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
556 goto afp_setfork_err;
558 err = ad_dtruncate( ofork->of_ad, size );
560 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
562 goto afp_setfork_err;
563 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
564 ad_refresh( ofork->of_ad );
566 st_size = ad_size(ofork->of_ad, eid);
568 if (st_size > size &&
569 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
570 goto afp_setfork_err;
572 err = ad_rtruncate(ofork->of_ad, size);
574 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
576 goto afp_setfork_err;
578 if (ad_flush( ofork->of_ad ) < 0) {
579 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
583 return AFPERR_BITMAP;
586 if ( flushfork( ofork ) < 0 ) {
587 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
602 return AFPERR_ACCESS;
613 /* for this to work correctly, we need to check for locks before each
614 * read and write. that's most easily handled by always doing an
615 * appropriate check before each ad_read/ad_write. other things
616 * that can change files like truncate are handled internally to those
619 #define ENDBIT(a) ((a) & 0x80)
620 #define UNLOCKBIT(a) ((a) & 0x01)
623 /* ---------------------- */
624 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
627 off_t offset, length;
635 /* figure out parameters */
637 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
639 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
640 ibuf += sizeof(ofrefnum);
642 if (NULL == ( ofork = of_find( ofrefnum )) ) {
643 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
644 return( AFPERR_PARAM );
647 if ( ofork->of_flags & AFPFORK_DATA) {
649 } else if (ofork->of_flags & AFPFORK_RSRC) {
654 offset = get_off_t(&ibuf, is64);
655 length = get_off_t(&ibuf, is64);
657 /* FIXME AD_FILELOCK test is surely wrong */
659 length = BYTELOCK_MAX;
660 else if (!length || is_neg(is64, length)) {
662 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
667 offset += ad_size(ofork->of_ad, eid);
668 /* FIXME what do we do if file size > 2 GB and
669 it's not byte_lock_ext?
672 if (offset < 0) /* error if we have a negative offset */
675 /* if the file is a read-only file, we use read locks instead of
676 * write locks. that way, we can prevent anyone from initiating
678 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
679 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
680 ofork->of_refnum) < 0) {
684 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
690 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
698 *rbuflen = set_off_t (offset, rbuf, is64);
702 /* --------------------------- */
703 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
705 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
708 /* --------------------------- */
709 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
711 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
716 /* --------------------------- */
717 static int crlf(struct ofork *of)
721 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
722 /* no resource fork or no finderinfo, use our files extension mapping */
723 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
726 /* file type is TEXT */
729 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
736 static ssize_t read_file(struct ofork *ofork, int eid,
737 off_t offset, u_char nlmask,
738 u_char nlchar, char *rbuf,
739 size_t *rbuflen, const int xlate)
745 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
747 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
749 return( AFPERR_PARAM );
751 if ( (size_t)cc < *rbuflen ) {
759 for ( p = rbuf, q = p + cc; p < q; ) {
760 if (( *p++ & nlmask ) == nlchar ) {
771 * If this file is of type TEXT, then swap \012 to \015.
774 for ( p = rbuf, q = p + cc; p < q; p++ ) {
775 if ( *p == '\012' ) {
777 } else if ( *p == '\015' ) {
786 return( AFPERR_EOF );
791 /* -----------------------------
792 * with ddp, afp_read can return fewer bytes than in reqcount
793 * so return EOF only if read actually past end of file not
794 * if offset +reqcount > size of file
796 * getfork size ==> 10430
797 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
798 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
799 * read fork offset 9248 size 1508 ==> 1182 (EOF)
800 * 10752 is a bug in Mac 7.5.x finder
802 * with dsi, should we check that reqcount < server quantum?
804 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
807 off_t offset, saveoff, reqcount, savereqcount;
811 u_char nlmask, nlchar;
814 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
815 ibuf += sizeof( u_short );
817 if (NULL == ( ofork = of_find( ofrefnum )) ) {
818 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
823 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
827 offset = get_off_t(&ibuf, is64);
828 reqcount = get_off_t(&ibuf, is64);
830 LOG(log_debug, logtype_afpd,
831 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
832 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
841 /* if we wanted to be picky, we could add in the following
842 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
844 if (reqcount < 0 || offset < 0) {
849 if ( ofork->of_flags & AFPFORK_DATA) {
851 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
852 } else if (ofork->of_flags & AFPFORK_RSRC) {
854 } else { /* fork wasn't opened. this should never really happen. */
859 /* zero request count */
865 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
866 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
868 savereqcount = reqcount;
870 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
875 *rbuflen = MIN(reqcount, *rbuflen);
876 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
877 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
879 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
882 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
883 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
885 /* dsi can stream requests. we can only do this if we're not checking
886 * for an end-of-line character. oh well. */
887 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
888 DSI *dsi = obj->handle;
891 /* reqcount isn't always truthful. we need to deal with that. */
892 size = ad_size(ofork->of_ad, eid);
894 /* subtract off the offset */
896 if (reqcount > size) {
903 /* dsi_readinit() returns size of next read buffer. by this point,
904 * we know that we're sending some data. if we fail, something
905 * horrible happened. */
906 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
909 /* due to the nature of afp packets, we have to exit if we get
910 an error. we can't do this with translation on. */
915 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
917 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
918 if (errno == EINVAL || errno == ENOSYS)
921 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
933 /* fill up our buffer. */
934 while (*rbuflen > 0) {
935 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
940 /* dsi_read() also returns buffer size of next allocation */
941 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
950 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
952 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
953 obj->exit(EXITERR_CLNT);
957 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
965 /* ---------------------- */
966 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
968 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
971 /* ---------------------- */
972 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
974 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
977 /* ---------------------- */
978 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
986 memcpy(&vid, ibuf, sizeof(vid));
987 if (NULL == ( vol = getvolbyvid( vid )) ) {
988 return( AFPERR_PARAM );
995 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1002 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1004 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1005 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1006 return( AFPERR_PARAM );
1009 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
1010 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1012 if ( flushfork( ofork ) < 0 ) {
1013 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1021 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1022 fsync(2) on OSX is implemented differently than on other platforms.
1023 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1025 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1027 struct ofork *ofork;
1033 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1034 ibuf += sizeof( ofrefnum );
1036 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1037 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1038 return( AFPERR_PARAM );
1041 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1042 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1044 if ( flushfork( ofork ) < 0 ) {
1045 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1052 /* this is very similar to closefork */
1053 int flushfork(struct ofork *ofork)
1057 int err = 0, doflush = 0;
1059 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1060 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1061 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1062 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1066 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1067 (ofork->of_flags & AFPFORK_RSRC)) {
1069 /* read in the rfork length */
1070 ad_refresh(ofork->of_ad);
1072 /* set the date if we're dirty */
1073 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1074 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1075 ofork->of_flags &= ~AFPFORK_DIRTY;
1079 /* flush the header */
1080 if (doflush && ad_flush(ofork->of_ad) < 0)
1083 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1087 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1088 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1094 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1096 struct ofork *ofork;
1101 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1103 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1104 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1105 return( AFPERR_PARAM );
1108 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1109 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1111 if ( of_closefork( ofork ) < 0 ) {
1112 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1113 return( AFPERR_PARAM );
1120 static ssize_t write_file(struct ofork *ofork, int eid,
1121 off_t offset, char *rbuf,
1122 size_t rbuflen, const int xlate)
1128 * If this file is of type TEXT, swap \015 to \012.
1131 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1132 if ( *p == '\015' ) {
1134 } else if ( *p == '\012' ) {
1140 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1141 (uintmax_t)offset, rbuflen);
1143 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1144 rbuf, rbuflen)) < 0 ) {
1149 return( AFPERR_DFULL );
1151 return AFPERR_ACCESS;
1153 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1154 return( AFPERR_PARAM );
1162 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1163 * the client may have sent us a bunch of data that's not reflected
1164 * in reqcount et al. */
1165 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1167 struct ofork *ofork;
1168 off_t offset, saveoff, reqcount, oldsize, newsize;
1169 int endflag, eid, xlate = 0, err = AFP_OK;
1173 /* figure out parameters */
1175 endflag = ENDBIT(*ibuf);
1177 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1178 ibuf += sizeof( ofrefnum );
1180 offset = get_off_t(&ibuf, is64);
1181 reqcount = get_off_t(&ibuf, is64);
1183 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1184 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1189 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1190 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1192 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1193 err = AFPERR_ACCESS;
1198 writtenfork = ofork;
1201 if ( ofork->of_flags & AFPFORK_DATA) {
1203 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1204 } else if (ofork->of_flags & AFPFORK_RSRC) {
1207 err = AFPERR_ACCESS; /* should never happen */
1211 oldsize = ad_size(ofork->of_ad, eid);
1215 /* handle bogus parameters */
1216 if (reqcount < 0 || offset < 0) {
1221 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1223 /* offset can overflow on 64-bit capable filesystems.
1224 * report disk full if that's going to happen. */
1225 if (sum_neg(is64, offset, reqcount)) {
1230 if (!reqcount) { /* handle request counts of 0 */
1232 *rbuflen = set_off_t (offset, rbuf, is64);
1237 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1238 reqcount, ofork->of_refnum) < 0) {
1243 /* this is yucky, but dsi can stream i/o and asp can't */
1244 switch (obj->proto) {
1247 DSI *dsi = obj->handle;
1248 /* find out what we have already and write it out. */
1249 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1251 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1252 dsi_writeflush(dsi);
1254 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1260 #if 0 /*def HAVE_SENDFILE_WRITE*/
1261 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1262 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1263 offset, dsi->datasize)) < 0) {
1271 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1272 goto afp_write_loop;
1274 dsi_writeflush(dsi);
1276 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1277 reqcount, ofork->of_refnum);
1282 goto afp_write_done;
1284 #endif /* 0, was HAVE_SENDFILE_WRITE */
1286 /* loop until everything gets written. currently
1287 * dsi_write handles the end case by itself. */
1288 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1289 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1290 dsi_writeflush(dsi);
1292 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1293 reqcount, ofork->of_refnum);
1302 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1303 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1304 ofork->of_flags |= AFPFORK_DIRTY;
1306 /* we have modified any fork, remember until close_fork */
1307 ofork->of_flags |= AFPFORK_MODIFIED;
1309 /* update write count */
1310 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1312 *rbuflen = set_off_t (offset, rbuf, is64);
1316 if (obj->proto == AFPPROTO_DSI) {
1317 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1318 dsi_writeflush(obj->handle);
1320 if (err != AFP_OK) {
1326 /* ---------------------------- */
1327 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1329 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1332 /* ----------------------------
1333 * FIXME need to deal with SIGXFSZ signal
1335 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1337 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1340 /* ---------------------------- */
1341 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1343 struct ofork *ofork;
1345 uint16_t ofrefnum, bitmap;
1348 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1349 ibuf += sizeof( ofrefnum );
1350 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1351 bitmap = ntohs( bitmap );
1352 ibuf += sizeof( bitmap );
1355 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1356 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1357 return( AFPERR_PARAM );
1360 if (AD_META_OPEN(ofork->of_ad)) {
1361 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1362 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1363 return( AFPERR_PARAM );
1367 if (AFP_OK != (ret = getforkparams(ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1371 *rbuflen = buflen + sizeof( u_short );
1372 bitmap = htons( bitmap );
1373 memcpy(rbuf, &bitmap, sizeof( bitmap ));