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 <netatalk/at.h>
20 #include <atalk/dsi.h>
21 #include <atalk/atp.h>
22 #include <atalk/asp.h>
23 #include <atalk/afp.h>
24 #include <atalk/adouble.h>
25 #include <atalk/logger.h>
26 #include <atalk/util.h>
27 #include <atalk/cnid.h>
28 #include <atalk/bstradd.h>
33 #include "directory.h"
38 struct ofork *writtenfork;
41 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
51 /* can only get the length of the opened fork */
52 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
53 && (ofork->of_flags & AFPFORK_RSRC))
55 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
56 && (ofork->of_flags & AFPFORK_DATA))) {
57 return( AFPERR_BITMAP );
60 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
67 dir = dirlookup(vol, ofork->of_did);
69 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
70 return( AFPERR_MISC );
72 path.m_name = of_name(ofork);
75 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
76 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
77 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
78 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
79 /* 0 is for symlink */
80 if (movecwd(vol, dir) < 0)
81 return( AFPERR_NOOBJ );
82 if ( lstat( path.u_name, st ) < 0 )
83 return( AFPERR_NOOBJ );
85 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
86 return( AFPERR_BITMAP );
90 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
93 static off_t get_off_t(char **ibuf, int is64)
99 memcpy(&temp, *ibuf, sizeof( temp ));
100 ret = ntohl(temp); /* ntohl is unsigned */
101 *ibuf += sizeof(temp);
104 memcpy(&temp, *ibuf, sizeof( temp ));
105 *ibuf += sizeof(temp);
106 ret = ntohl(temp)| (ret << 32);
109 ret = (int)ret; /* sign extend */
114 static int set_off_t(off_t offset, char *rbuf, int is64)
121 temp = htonl(offset >> 32);
122 memcpy(rbuf, &temp, sizeof( temp ));
123 rbuf += sizeof(temp);
124 ret = sizeof( temp );
125 offset &= 0xffffffff;
127 temp = htonl(offset);
128 memcpy(rbuf, &temp, sizeof( temp ));
129 ret += sizeof( temp );
134 static int is_neg(int is64, off_t val)
136 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
141 static int sum_neg(int is64, off_t offset, off_t reqcount)
143 if (is_neg(is64, offset +reqcount) )
148 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
156 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
157 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
160 if ((access & (OPENACC_RD | OPENACC_DRD))) {
161 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
163 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
166 if ((access & OPENACC_RD) && denyreadset) {
170 if ((access & OPENACC_DRD) && readset) {
174 /* boolean logic is not enough, because getforkmode is not always telling the
177 if ((access & OPENACC_RD)) {
178 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
182 if ((access & OPENACC_DRD)) {
183 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
188 /* ------------same for writing -------------- */
189 if ((access & (OPENACC_WR | OPENACC_DWR))) {
190 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
192 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
195 if ((access & OPENACC_WR) && denywriteset) {
199 if ((access & OPENACC_DWR) && writeset) {
203 if ((access & OPENACC_WR)) {
204 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
208 if ((access & OPENACC_DWR)) {
209 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
214 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
215 return ad_excl_lock(adp, eid);
220 /* ----------------------- */
221 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
225 struct ofork *ofork, *opened;
226 struct adouble *adsame = NULL;
228 int ret, adflags, eid;
230 uint16_t vid, bitmap, access, ofrefnum;
231 char fork, *path, *upath;
238 memcpy(&vid, ibuf, sizeof( vid ));
242 if (NULL == ( vol = getvolbyvid( vid ))) {
243 return( AFPERR_PARAM );
246 memcpy(&did, ibuf, sizeof( did ));
247 ibuf += sizeof( int );
249 if (NULL == ( dir = dirlookup( vol, did ))) {
253 memcpy(&bitmap, ibuf, sizeof( bitmap ));
254 bitmap = ntohs( bitmap );
255 ibuf += sizeof( bitmap );
256 memcpy(&access, ibuf, sizeof( access ));
257 access = ntohs( access );
258 ibuf += sizeof( access );
260 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
264 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
265 return get_afp_errno(AFPERR_PARAM);
268 if (*s_path->m_name == '\0') {
270 return AFPERR_BADTYPE;
273 LOG(log_debug, logtype_afpd,
274 "afp_openfork(\"%s\", %s)",
275 abspath(s_path->u_name),
276 (fork & OPENFORK_RSCS) ? "OPENFORK_RSCS" : "OPENFORK_DATA");
278 /* stat() data fork st is set because it's not a dir */
279 switch ( s_path->st_errno ) {
285 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
287 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
290 /* FIXME should we check it first ? */
291 upath = s_path->u_name;
292 if (!vol_unix_priv(vol)) {
293 if (check_access(upath, access ) < 0) {
294 return AFPERR_ACCESS;
297 if (file_access(s_path, access ) < 0) {
298 return AFPERR_ACCESS;
303 /* XXX: this probably isn't the best way to do this. the already
304 open bits should really be set if the fork is opened by any
305 program, not just this one. however, that's problematic to do
306 if we can't write lock files somewhere. opened is also passed to
307 ad_open so that we can keep file locks together.
308 FIXME: add the fork we are opening?
310 if ((opened = of_findname(s_path))) {
311 adsame = opened->of_ad;
314 if ( fork == OPENFORK_DATA ) {
316 adflags = ADFLAGS_DF | ADFLAGS_HF ;
319 adflags = ADFLAGS_RF | ADFLAGS_HF;
322 path = s_path->m_name;
323 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
324 adsame, st)) == NULL ) {
325 return( AFPERR_NFILE );
329 if (access & OPENACC_WR) {
330 /* try opening in read-write mode */
331 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
339 if (fork == OPENFORK_DATA) {
340 /* try to open only the data fork */
341 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 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, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
350 ofork->of_flags |= AFPFORK_OPEN;
359 ret = AFPERR_BADTYPE;
363 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
370 /* the ressource fork is open too */
371 ofork->of_flags |= AFPFORK_OPEN;
374 /* try opening in read-only mode */
376 if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
384 /* see if client asked for a read only data fork */
385 if (fork == OPENFORK_DATA) {
386 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
389 adflags = ADFLAGS_DF;
391 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
392 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
393 * then create in open read-write.
394 * FIXME , it doesn't play well with byte locking example:
395 * ressource fork open read only
396 * locking set on it (no effect, there's no file!)
397 * ressource fork open read write now
406 ret = AFPERR_BADTYPE;
410 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
411 abspath(s_path->m_name), strerror(errno) );
417 /* the ressource fork is open too */
418 ofork->of_flags |= AFPFORK_OPEN;
422 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
423 if (ad_setname(ofork->of_ad, path)) {
424 ad_flush( ofork->of_ad );
428 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
429 ad_close( ofork->of_ad, adflags );
433 *rbuflen = buflen + 2 * sizeof( u_int16_t );
434 bitmap = htons( bitmap );
435 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
436 rbuf += sizeof( u_int16_t );
438 /* check WriteInhibit bit if we have a ressource fork
439 * the test is done here, after some Mac trafic capture
441 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
442 ad_getattr(ofork->of_ad, &bshort);
443 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
444 ad_close( ofork->of_ad, adflags );
447 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
448 return(AFPERR_OLOCK);
453 * synchronization locks:
456 /* don't try to lock non-existent rforks. */
457 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
459 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
460 /* can we access the fork? */
463 ad_close( ofork->of_ad, adflags );
466 case EAGAIN: /* return data anyway */
470 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
471 return( AFPERR_DENYCONF );
475 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
476 return( AFPERR_PARAM );
479 if ((access & OPENACC_WR))
480 ofork->of_flags |= AFPFORK_ACCWR;
482 /* the file may be open read only without ressource fork */
483 if ((access & OPENACC_RD))
484 ofork->of_flags |= AFPFORK_ACCRD;
486 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
492 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
496 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
500 u_int16_t ofrefnum, bitmap;
508 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
509 ibuf += sizeof( ofrefnum );
511 memcpy(&bitmap, ibuf, sizeof(bitmap));
512 bitmap = ntohs(bitmap);
513 ibuf += sizeof( bitmap );
516 if (NULL == ( ofork = of_find( ofrefnum )) ) {
517 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
518 return( AFPERR_PARAM );
521 if (ofork->of_vol->v_flags & AFPVOL_RO)
524 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
525 return AFPERR_ACCESS;
527 if ( ofork->of_flags & AFPFORK_DATA) {
529 } else if (ofork->of_flags & AFPFORK_RSRC) {
534 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
535 && eid == ADEID_RFORK
537 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
538 && eid == ADEID_DFORK)) {
539 return AFPERR_BITMAP;
543 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
544 if (afp_version >= 30) {
548 return AFPERR_BITMAP;
551 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
552 return AFPERR_PARAM ;
554 size = get_off_t(&ibuf, is64);
557 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
560 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
561 st_size = ad_size(ofork->of_ad, eid);
563 if (st_size > size &&
564 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
565 goto afp_setfork_err;
567 err = ad_dtruncate( ofork->of_ad, size );
569 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
571 goto afp_setfork_err;
572 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
573 ad_refresh( ofork->of_ad );
575 st_size = ad_size(ofork->of_ad, eid);
577 if (st_size > size &&
578 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
579 goto afp_setfork_err;
581 err = ad_rtruncate(ofork->of_ad, size);
583 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
585 goto afp_setfork_err;
587 if (ad_flush( ofork->of_ad ) < 0) {
588 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
592 return AFPERR_BITMAP;
595 if ( flushfork( ofork ) < 0 ) {
596 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
611 return AFPERR_ACCESS;
622 /* for this to work correctly, we need to check for locks before each
623 * read and write. that's most easily handled by always doing an
624 * appropriate check before each ad_read/ad_write. other things
625 * that can change files like truncate are handled internally to those
628 #define ENDBIT(a) ((a) & 0x80)
629 #define UNLOCKBIT(a) ((a) & 0x01)
632 /* ---------------------- */
633 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
636 off_t offset, length;
644 /* figure out parameters */
646 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
648 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
649 ibuf += sizeof(ofrefnum);
651 if (NULL == ( ofork = of_find( ofrefnum )) ) {
652 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
653 return( AFPERR_PARAM );
656 if ( ofork->of_flags & AFPFORK_DATA) {
658 } else if (ofork->of_flags & AFPFORK_RSRC) {
663 offset = get_off_t(&ibuf, is64);
664 length = get_off_t(&ibuf, is64);
666 /* FIXME AD_FILELOCK test is surely wrong */
668 length = BYTELOCK_MAX;
669 else if (!length || is_neg(is64, length)) {
671 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
676 offset += ad_size(ofork->of_ad, eid);
677 /* FIXME what do we do if file size > 2 GB and
678 it's not byte_lock_ext?
681 if (offset < 0) /* error if we have a negative offset */
684 /* if the file is a read-only file, we use read locks instead of
685 * write locks. that way, we can prevent anyone from initiating
687 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
688 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
689 ofork->of_refnum) < 0) {
693 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
699 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
707 *rbuflen = set_off_t (offset, rbuf, is64);
711 /* --------------------------- */
712 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
714 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
717 /* --------------------------- */
718 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
720 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
725 /* --------------------------- */
726 static int crlf(struct ofork *of)
730 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
731 /* no resource fork or no finderinfo, use our files extension mapping */
732 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
735 /* file type is TEXT */
738 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
745 static ssize_t read_file(struct ofork *ofork, int eid,
746 off_t offset, u_char nlmask,
747 u_char nlchar, char *rbuf,
748 size_t *rbuflen, const int xlate)
754 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
756 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
758 return( AFPERR_PARAM );
760 if ( (size_t)cc < *rbuflen ) {
768 for ( p = rbuf, q = p + cc; p < q; ) {
769 if (( *p++ & nlmask ) == nlchar ) {
780 * If this file is of type TEXT, then swap \012 to \015.
783 for ( p = rbuf, q = p + cc; p < q; p++ ) {
784 if ( *p == '\012' ) {
786 } else if ( *p == '\015' ) {
795 return( AFPERR_EOF );
800 /* -----------------------------
801 * with ddp, afp_read can return fewer bytes than in reqcount
802 * so return EOF only if read actually past end of file not
803 * if offset +reqcount > size of file
805 * getfork size ==> 10430
806 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
807 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
808 * read fork offset 9248 size 1508 ==> 1182 (EOF)
809 * 10752 is a bug in Mac 7.5.x finder
811 * with dsi, should we check that reqcount < server quantum?
813 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
816 off_t offset, saveoff, reqcount, savereqcount;
820 u_char nlmask, nlchar;
823 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
824 ibuf += sizeof( u_short );
826 if (NULL == ( ofork = of_find( ofrefnum )) ) {
827 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
832 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
836 offset = get_off_t(&ibuf, is64);
837 reqcount = get_off_t(&ibuf, is64);
839 LOG(log_debug, logtype_afpd,
840 "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
841 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
842 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
851 /* if we wanted to be picky, we could add in the following
852 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
854 if (reqcount < 0 || offset < 0) {
859 if ( ofork->of_flags & AFPFORK_DATA) {
861 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
862 } else if (ofork->of_flags & AFPFORK_RSRC) {
864 } else { /* fork wasn't opened. this should never really happen. */
869 /* zero request count */
875 savereqcount = reqcount;
877 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
882 #define min(a,b) ((a)<(b)?(a):(b))
883 *rbuflen = min( reqcount, *rbuflen );
884 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
888 /* dsi can stream requests. we can only do this if we're not checking
889 * for an end-of-line character. oh well. */
890 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
891 DSI *dsi = obj->handle;
894 /* reqcount isn't always truthful. we need to deal with that. */
895 size = ad_size(ofork->of_ad, eid);
897 /* subtract off the offset */
899 if (reqcount > size) {
906 /* dsi_readinit() returns size of next read buffer. by this point,
907 * we know that we're sending some data. if we fail, something
908 * horrible happened. */
909 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
912 /* due to the nature of afp packets, we have to exit if we get
913 an error. we can't do this with translation on. */
918 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
919 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
920 if (errno == EINVAL || errno == ENOSYS)
923 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
935 /* fill up our buffer. */
936 while (*rbuflen > 0) {
937 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
942 /* dsi_read() also returns buffer size of next allocation */
943 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
952 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
954 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
955 obj->exit(EXITERR_CLNT);
959 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
967 /* ---------------------- */
968 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
970 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
973 /* ---------------------- */
974 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
976 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
979 /* ---------------------- */
980 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
988 memcpy(&vid, ibuf, sizeof(vid));
989 if (NULL == ( vol = getvolbyvid( vid )) ) {
990 return( AFPERR_PARAM );
997 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1004 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1006 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1007 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1008 return( AFPERR_PARAM );
1011 LOG(log_debug, logtype_afpd,
1012 "afp_flushfork(\"%s\", fork: %s)",
1013 cfrombstr(ofork->of_ad->ad_fullpath),
1014 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1016 if ( flushfork( ofork ) < 0 ) {
1017 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1025 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1026 fsync(2) on OSX is implemented differently than on other platforms.
1027 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1029 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1031 struct ofork *ofork;
1037 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1038 ibuf += sizeof( ofrefnum );
1040 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1041 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1042 return( AFPERR_PARAM );
1045 LOG(log_debug, logtype_afpd,
1046 "afp_syncfork(\"%s\", fork: %s)",
1047 cfrombstr(ofork->of_ad->ad_fullpath),
1048 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1050 if ( flushfork( ofork ) < 0 ) {
1051 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1058 /* this is very similar to closefork */
1059 int flushfork(struct ofork *ofork)
1063 int err = 0, doflush = 0;
1065 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1066 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1067 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1068 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1072 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1073 (ofork->of_flags & AFPFORK_RSRC)) {
1075 /* read in the rfork length */
1076 ad_refresh(ofork->of_ad);
1078 /* set the date if we're dirty */
1079 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1080 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1081 ofork->of_flags &= ~AFPFORK_DIRTY;
1085 /* flush the header */
1086 if (doflush && ad_flush(ofork->of_ad) < 0)
1089 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1093 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1094 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1100 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1102 struct ofork *ofork;
1107 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1109 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1110 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1111 return( AFPERR_PARAM );
1114 LOG(log_debug, logtype_afpd,
1115 "afp_closefork(\"%s\", fork: %s)",
1116 cfrombstr(ofork->of_ad->ad_fullpath),
1117 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1119 if ( of_closefork( ofork ) < 0 ) {
1120 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1121 return( AFPERR_PARAM );
1128 static ssize_t write_file(struct ofork *ofork, int eid,
1129 off_t offset, char *rbuf,
1130 size_t rbuflen, const int xlate)
1136 * If this file is of type TEXT, swap \015 to \012.
1139 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1140 if ( *p == '\015' ) {
1142 } else if ( *p == '\012' ) {
1148 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1149 rbuf, rbuflen)) < 0 ) {
1154 return( AFPERR_DFULL );
1156 return AFPERR_ACCESS;
1158 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1159 return( AFPERR_PARAM );
1167 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1168 * the client may have sent us a bunch of data that's not reflected
1169 * in reqcount et al. */
1170 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1172 struct ofork *ofork;
1173 off_t offset, saveoff, reqcount;
1174 int endflag, eid, xlate = 0, err = AFP_OK;
1178 /* figure out parameters */
1180 endflag = ENDBIT(*ibuf);
1182 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1183 ibuf += sizeof( ofrefnum );
1185 offset = get_off_t(&ibuf, is64);
1186 reqcount = get_off_t(&ibuf, is64);
1188 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1189 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1194 LOG(log_debug, logtype_afpd,
1195 "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1196 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
1197 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1199 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1200 err = AFPERR_ACCESS;
1205 writtenfork = ofork;
1208 if ( ofork->of_flags & AFPFORK_DATA) {
1210 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1211 } else if (ofork->of_flags & AFPFORK_RSRC) {
1214 err = AFPERR_ACCESS; /* should never happen */
1219 offset += ad_size(ofork->of_ad, eid);
1221 /* handle bogus parameters */
1222 if (reqcount < 0 || offset < 0) {
1227 /* offset can overflow on 64-bit capable filesystems.
1228 * report disk full if that's going to happen. */
1229 if (sum_neg(is64, offset, reqcount)) {
1234 if (!reqcount) { /* handle request counts of 0 */
1236 *rbuflen = set_off_t (offset, rbuf, is64);
1241 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1242 reqcount, ofork->of_refnum) < 0) {
1247 /* this is yucky, but dsi can stream i/o and asp can't */
1248 switch (obj->proto) {
1251 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1253 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1254 return( AFPERR_PARAM );
1257 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1260 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1265 #endif /* no afp/asp */
1269 DSI *dsi = obj->handle;
1271 /* find out what we have already and write it out. */
1272 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1273 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1274 dsi_writeflush(dsi);
1276 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1281 #if 0 /*def HAVE_SENDFILE_WRITE*/
1282 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1283 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1284 offset, dsi->datasize)) < 0) {
1292 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1293 goto afp_write_loop;
1295 dsi_writeflush(dsi);
1297 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1298 reqcount, ofork->of_refnum);
1303 goto afp_write_done;
1305 #endif /* 0, was HAVE_SENDFILE_WRITE */
1307 /* loop until everything gets written. currently
1308 * dsi_write handles the end case by itself. */
1309 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1310 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1311 dsi_writeflush(dsi);
1313 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1314 reqcount, ofork->of_refnum);
1323 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1324 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1325 ofork->of_flags |= AFPFORK_DIRTY;
1327 *rbuflen = set_off_t (offset, rbuf, is64);
1331 if (obj->proto == AFPPROTO_DSI) {
1332 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1333 dsi_writeflush(obj->handle);
1335 if (err != AFP_OK) {
1341 /* ---------------------------- */
1342 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1344 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1347 /* ----------------------------
1348 * FIXME need to deal with SIGXFSZ signal
1350 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1352 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1355 /* ---------------------------- */
1356 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1358 struct ofork *ofork;
1360 u_int16_t ofrefnum, bitmap;
1363 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1364 ibuf += sizeof( ofrefnum );
1365 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1366 bitmap = ntohs( bitmap );
1367 ibuf += sizeof( bitmap );
1370 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1371 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1372 return( AFPERR_PARAM );
1375 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1376 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1377 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1378 return( AFPERR_PARAM );
1382 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1383 rbuf + sizeof( u_short ), &buflen ))) {
1387 *rbuflen = buflen + sizeof( u_short );
1388 bitmap = htons( bitmap );
1389 memcpy(rbuf, &bitmap, sizeof( bitmap ));