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>
32 #include "directory.h"
37 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
43 struct ofork *writtenfork;
46 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
56 /* can only get the length of the opened fork */
57 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
58 && (ofork->of_flags & AFPFORK_RSRC))
60 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
61 && (ofork->of_flags & AFPFORK_DATA))) {
62 return( AFPERR_BITMAP );
65 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
72 dir = dirlookup(vol, ofork->of_did);
74 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
75 return( AFPERR_MISC );
77 path.m_name = of_name(ofork);
80 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
81 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
82 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
83 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
84 /* 0 is for symlink */
85 if (movecwd(vol, dir) < 0)
86 return( AFPERR_NOOBJ );
87 if ( lstat( path.u_name, st ) < 0 )
88 return( AFPERR_NOOBJ );
90 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
91 return( AFPERR_BITMAP );
95 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
98 /* ---------------------------- */
99 static off_t get_off_t(char **ibuf, int is64)
105 memcpy(&temp, *ibuf, sizeof( temp ));
106 ret = ntohl(temp); /* ntohl is unsigned */
107 *ibuf += sizeof(temp);
110 memcpy(&temp, *ibuf, sizeof( temp ));
111 *ibuf += sizeof(temp);
112 ret = ntohl(temp)| (ret << 32);
115 ret = (int)ret; /* sign extend */
120 /* ---------------------- */
121 static int set_off_t(off_t offset, char *rbuf, int is64)
128 temp = htonl(offset >> 32);
129 memcpy(rbuf, &temp, sizeof( temp ));
130 rbuf += sizeof(temp);
131 ret = sizeof( temp );
132 offset &= 0xffffffff;
134 temp = htonl(offset);
135 memcpy(rbuf, &temp, sizeof( temp ));
136 ret += sizeof( temp );
141 /* ------------------------
143 static int is_neg(int is64, off_t val)
145 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
150 static int sum_neg(int is64, off_t offset, off_t reqcount)
152 if (is_neg(is64, offset +reqcount) )
157 /* -------------------------
159 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
161 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
164 /* -------------------------
166 int getforkmode(struct adouble *adp, int eid, int what)
168 return ad_testlock(adp, eid, what);
171 /* -------------------------
173 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
181 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
182 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
185 if ((access & (OPENACC_RD | OPENACC_DRD))) {
186 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
188 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
191 if ((access & OPENACC_RD) && denyreadset) {
195 if ((access & OPENACC_DRD) && readset) {
199 /* boolean logic is not enough, because getforkmode is not always telling the
202 if ((access & OPENACC_RD)) {
203 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
207 if ((access & OPENACC_DRD)) {
208 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
213 /* ------------same for writing -------------- */
214 if ((access & (OPENACC_WR | OPENACC_DWR))) {
215 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
217 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
220 if ((access & OPENACC_WR) && denywriteset) {
224 if ((access & OPENACC_DWR) && writeset) {
228 if ((access & OPENACC_WR)) {
229 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
233 if ((access & OPENACC_DWR)) {
234 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
239 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
240 return ad_excl_lock(adp, eid);
245 /* ----------------------- */
246 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
250 struct ofork *ofork, *opened;
251 struct adouble *adsame = NULL;
253 int ret, adflags, eid;
255 uint16_t vid, bitmap, access, ofrefnum;
256 char fork, *path, *upath;
263 memcpy(&vid, ibuf, sizeof( vid ));
267 if (NULL == ( vol = getvolbyvid( vid ))) {
268 return( AFPERR_PARAM );
271 memcpy(&did, ibuf, sizeof( did ));
272 ibuf += sizeof( int );
274 if (NULL == ( dir = dirlookup( vol, did ))) {
278 memcpy(&bitmap, ibuf, sizeof( bitmap ));
279 bitmap = ntohs( bitmap );
280 ibuf += sizeof( bitmap );
281 memcpy(&access, ibuf, sizeof( access ));
282 access = ntohs( access );
283 ibuf += sizeof( access );
285 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
289 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
290 return get_afp_errno(AFPERR_PARAM);
293 if (*s_path->m_name == '\0') {
295 return AFPERR_BADTYPE;
298 /* stat() data fork st is set because it's not a dir */
299 switch ( s_path->st_errno ) {
305 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
307 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
310 /* FIXME should we check it first ? */
311 upath = s_path->u_name;
312 if (!vol_unix_priv(vol)) {
313 if (check_access(upath, access ) < 0) {
314 return AFPERR_ACCESS;
317 if (file_access(s_path, access ) < 0) {
318 return AFPERR_ACCESS;
323 /* XXX: this probably isn't the best way to do this. the already
324 open bits should really be set if the fork is opened by any
325 program, not just this one. however, that's problematic to do
326 if we can't write lock files somewhere. opened is also passed to
327 ad_open so that we can keep file locks together.
328 FIXME: add the fork we are opening?
330 if ((opened = of_findname(s_path))) {
331 adsame = opened->of_ad;
334 if ( fork == OPENFORK_DATA ) {
336 adflags = ADFLAGS_DF | ADFLAGS_HF;
339 adflags = ADFLAGS_RF | ADFLAGS_HF;
342 path = s_path->m_name;
343 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
344 adsame, st)) == NULL ) {
345 return( AFPERR_NFILE );
349 if (access & OPENACC_WR) {
350 /* try opening in read-write mode */
351 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
359 if (fork == OPENFORK_DATA) {
360 /* try to open only the data fork */
361 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
364 adflags = ADFLAGS_DF;
366 /* here's the deal. we only try to create the resource
367 * fork if the user wants to open it for write acess. */
368 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
370 ofork->of_flags |= AFPFORK_OPEN;
379 ret = AFPERR_BADTYPE;
383 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
390 /* the ressource fork is open too */
391 ofork->of_flags |= AFPFORK_OPEN;
394 /* try opening in read-only mode */
396 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
404 /* see if client asked for a read only data fork */
405 if (fork == OPENFORK_DATA) {
406 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
409 adflags = ADFLAGS_DF;
411 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
412 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
413 * then create in open read-write.
414 * FIXME , it doesn't play well with byte locking example:
415 * ressource fork open read only
416 * locking set on it (no effect, there's no file!)
417 * ressource fork open read write now
426 ret = AFPERR_BADTYPE;
430 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
431 abspath(s_path->m_name), strerror(errno) );
437 /* the ressource fork is open too */
438 ofork->of_flags |= AFPFORK_OPEN;
442 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
443 if (ad_setname(ofork->of_ad, path)) {
444 ad_flush( ofork->of_ad );
448 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
449 &buflen )) != AFP_OK ) {
450 ad_close( ofork->of_ad, adflags );
454 *rbuflen = buflen + 2 * sizeof( u_int16_t );
455 bitmap = htons( bitmap );
456 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
457 rbuf += sizeof( u_int16_t );
459 /* check WriteInhibit bit if we have a ressource fork
460 * the test is done here, after some Mac trafic capture
462 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
463 ad_getattr(ofork->of_ad, &bshort);
464 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
465 ad_close( ofork->of_ad, adflags );
468 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
469 return(AFPERR_OLOCK);
474 * synchronization locks:
477 /* don't try to lock non-existent rforks. */
478 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
480 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
481 /* can we access the fork? */
484 ad_close( ofork->of_ad, adflags );
487 case EAGAIN: /* return data anyway */
491 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
492 return( AFPERR_DENYCONF );
496 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
497 return( AFPERR_PARAM );
500 if ((access & OPENACC_WR))
501 ofork->of_flags |= AFPFORK_ACCWR;
503 /* the file may be open read only without ressource fork */
504 if ((access & OPENACC_RD))
505 ofork->of_flags |= AFPFORK_ACCRD;
507 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
513 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
517 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
521 u_int16_t ofrefnum, bitmap;
529 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
530 ibuf += sizeof( ofrefnum );
532 memcpy(&bitmap, ibuf, sizeof(bitmap));
533 bitmap = ntohs(bitmap);
534 ibuf += sizeof( bitmap );
537 if (NULL == ( ofork = of_find( ofrefnum )) ) {
538 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
539 return( AFPERR_PARAM );
542 if (ofork->of_vol->v_flags & AFPVOL_RO)
545 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
546 return AFPERR_ACCESS;
548 if ( ofork->of_flags & AFPFORK_DATA) {
550 } else if (ofork->of_flags & AFPFORK_RSRC) {
555 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
556 && eid == ADEID_RFORK
558 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
559 && eid == ADEID_DFORK)) {
560 return AFPERR_BITMAP;
564 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
565 if (afp_version >= 30) {
569 return AFPERR_BITMAP;
572 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
573 return AFPERR_PARAM ;
575 size = get_off_t(&ibuf, is64);
578 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
581 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
582 st_size = ad_size(ofork->of_ad, eid);
584 if (st_size > size &&
585 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
586 goto afp_setfork_err;
588 err = ad_dtruncate( ofork->of_ad, size );
590 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
592 goto afp_setfork_err;
593 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
594 ad_refresh( ofork->of_ad );
596 st_size = ad_size(ofork->of_ad, eid);
598 if (st_size > size &&
599 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
600 goto afp_setfork_err;
602 err = ad_rtruncate(ofork->of_ad, size);
604 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
606 goto afp_setfork_err;
608 if (ad_flush( ofork->of_ad ) < 0) {
609 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
613 return AFPERR_BITMAP;
616 if ( flushfork( ofork ) < 0 ) {
617 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
632 return AFPERR_ACCESS;
643 /* for this to work correctly, we need to check for locks before each
644 * read and write. that's most easily handled by always doing an
645 * appropriate check before each ad_read/ad_write. other things
646 * that can change files like truncate are handled internally to those
649 #define ENDBIT(a) ((a) & 0x80)
650 #define UNLOCKBIT(a) ((a) & 0x01)
653 /* ---------------------- */
654 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
657 off_t offset, length;
665 /* figure out parameters */
667 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
669 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
670 ibuf += sizeof(ofrefnum);
672 if (NULL == ( ofork = of_find( ofrefnum )) ) {
673 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
674 return( AFPERR_PARAM );
677 if ( ofork->of_flags & AFPFORK_DATA) {
679 } else if (ofork->of_flags & AFPFORK_RSRC) {
684 offset = get_off_t(&ibuf, is64);
685 length = get_off_t(&ibuf, is64);
687 /* FIXME AD_FILELOCK test is surely wrong */
689 length = BYTELOCK_MAX;
690 else if (!length || is_neg(is64, length)) {
692 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
697 offset += ad_size(ofork->of_ad, eid);
698 /* FIXME what do we do if file size > 2 GB and
699 it's not byte_lock_ext?
702 if (offset < 0) /* error if we have a negative offset */
705 /* if the file is a read-only file, we use read locks instead of
706 * write locks. that way, we can prevent anyone from initiating
708 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
709 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
710 ofork->of_refnum) < 0) {
714 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
720 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
728 *rbuflen = set_off_t (offset, rbuf, is64);
732 /* --------------------------- */
733 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
735 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
738 /* --------------------------- */
739 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
741 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
746 /* --------------------------- */
747 static int crlf(struct ofork *of)
751 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
752 /* no resource fork or no finderinfo, use our files extension mapping */
753 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
756 /* file type is TEXT */
759 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
766 static ssize_t read_file(struct ofork *ofork, int eid,
767 off_t offset, u_char nlmask,
768 u_char nlchar, char *rbuf,
769 size_t *rbuflen, const int xlate)
775 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
777 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
779 return( AFPERR_PARAM );
781 if ( (size_t)cc < *rbuflen ) {
789 for ( p = rbuf, q = p + cc; p < q; ) {
790 if (( *p++ & nlmask ) == nlchar ) {
801 * If this file is of type TEXT, then swap \012 to \015.
804 for ( p = rbuf, q = p + cc; p < q; p++ ) {
805 if ( *p == '\012' ) {
807 } else if ( *p == '\015' ) {
816 return( AFPERR_EOF );
821 /* -----------------------------
822 * with ddp, afp_read can return fewer bytes than in reqcount
823 * so return EOF only if read actually past end of file not
824 * if offset +reqcount > size of file
826 * getfork size ==> 10430
827 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
828 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
829 * read fork offset 9248 size 1508 ==> 1182 (EOF)
830 * 10752 is a bug in Mac 7.5.x finder
832 * with dsi, should we check that reqcount < server quantum?
834 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
837 off_t offset, saveoff, reqcount, savereqcount;
841 u_char nlmask, nlchar;
844 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
845 ibuf += sizeof( u_short );
847 if (NULL == ( ofork = of_find( ofrefnum )) ) {
848 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
853 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
857 offset = get_off_t(&ibuf, is64);
858 reqcount = get_off_t(&ibuf, is64);
867 /* if we wanted to be picky, we could add in the following
868 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
870 if (reqcount < 0 || offset < 0) {
875 if ( ofork->of_flags & AFPFORK_DATA) {
877 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
878 } else if (ofork->of_flags & AFPFORK_RSRC) {
880 } else { /* fork wasn't opened. this should never really happen. */
885 /* zero request count */
891 savereqcount = reqcount;
893 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
898 #define min(a,b) ((a)<(b)?(a):(b))
899 *rbuflen = min( reqcount, *rbuflen );
900 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
904 /* dsi can stream requests. we can only do this if we're not checking
905 * for an end-of-line character. oh well. */
906 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
907 DSI *dsi = obj->handle;
910 /* reqcount isn't always truthful. we need to deal with that. */
911 size = ad_size(ofork->of_ad, eid);
913 /* subtract off the offset */
915 if (reqcount > size) {
922 /* dsi_readinit() returns size of next read buffer. by this point,
923 * we know that we're sending some data. if we fail, something
924 * horrible happened. */
925 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
928 /* due to the nature of afp packets, we have to exit if we get
929 an error. we can't do this with translation on. */
931 if (!(xlate || Debug(obj) )) {
934 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
935 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
936 if (errno == EINVAL || errno == ENOSYS)
939 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
951 /* fill up our buffer. */
952 while (*rbuflen > 0) {
953 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
959 if (obj->options.flags & OPTION_DEBUG) {
960 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
961 bprint(rbuf, *rbuflen);
964 /* dsi_read() also returns buffer size of next allocation */
965 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
974 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
976 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
977 obj->exit(EXITERR_CLNT);
981 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
989 /* ---------------------- */
990 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
992 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
995 /* ---------------------- */
996 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
998 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1001 /* ---------------------- */
1002 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1010 memcpy(&vid, ibuf, sizeof(vid));
1011 if (NULL == ( vol = getvolbyvid( vid )) ) {
1012 return( AFPERR_PARAM );
1019 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1021 struct ofork *ofork;
1026 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1028 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1029 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1030 return( AFPERR_PARAM );
1033 if ( flushfork( ofork ) < 0 ) {
1034 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1042 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1043 fsync(2) on OSX is implemented differently than on other platforms.
1044 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1046 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1048 struct ofork *ofork;
1054 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1055 ibuf += sizeof( ofrefnum );
1057 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1058 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1059 return( AFPERR_PARAM );
1062 if ( flushfork( ofork ) < 0 ) {
1063 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1070 /* this is very similar to closefork */
1071 int flushfork(struct ofork *ofork)
1075 int err = 0, doflush = 0;
1077 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1078 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1079 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1080 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1084 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1085 (ofork->of_flags & AFPFORK_RSRC)) {
1087 /* read in the rfork length */
1088 ad_refresh(ofork->of_ad);
1090 /* set the date if we're dirty */
1091 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1092 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1093 ofork->of_flags &= ~AFPFORK_DIRTY;
1097 /* flush the header */
1098 if (doflush && ad_flush(ofork->of_ad) < 0)
1101 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1105 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1106 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1112 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1114 struct ofork *ofork;
1119 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1121 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1122 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1123 return( AFPERR_PARAM );
1125 if ( of_closefork( ofork ) < 0 ) {
1126 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1127 return( AFPERR_PARAM );
1134 static ssize_t write_file(struct ofork *ofork, int eid,
1135 off_t offset, char *rbuf,
1136 size_t rbuflen, const int xlate)
1142 * If this file is of type TEXT, swap \015 to \012.
1145 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1146 if ( *p == '\015' ) {
1148 } else if ( *p == '\012' ) {
1154 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1155 rbuf, rbuflen)) < 0 ) {
1160 return( AFPERR_DFULL );
1162 return AFPERR_ACCESS;
1164 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1165 return( AFPERR_PARAM );
1173 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1174 * the client may have sent us a bunch of data that's not reflected
1175 * in reqcount et al. */
1176 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1178 struct ofork *ofork;
1179 off_t offset, saveoff, reqcount;
1180 int endflag, eid, xlate = 0, err = AFP_OK;
1184 /* figure out parameters */
1186 endflag = ENDBIT(*ibuf);
1188 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1189 ibuf += sizeof( ofrefnum );
1191 offset = get_off_t(&ibuf, is64);
1192 reqcount = get_off_t(&ibuf, is64);
1194 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1195 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1200 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1201 err = AFPERR_ACCESS;
1206 writtenfork = ofork;
1209 if ( ofork->of_flags & AFPFORK_DATA) {
1211 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1212 } else if (ofork->of_flags & AFPFORK_RSRC) {
1215 err = AFPERR_ACCESS; /* should never happen */
1220 offset += ad_size(ofork->of_ad, eid);
1222 /* handle bogus parameters */
1223 if (reqcount < 0 || offset < 0) {
1228 /* offset can overflow on 64-bit capable filesystems.
1229 * report disk full if that's going to happen. */
1230 if (sum_neg(is64, offset, reqcount)) {
1235 if (!reqcount) { /* handle request counts of 0 */
1237 *rbuflen = set_off_t (offset, rbuf, is64);
1242 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1243 reqcount, ofork->of_refnum) < 0) {
1248 /* this is yucky, but dsi can stream i/o and asp can't */
1249 switch (obj->proto) {
1252 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1254 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1255 return( AFPERR_PARAM );
1259 if (obj->options.flags & OPTION_DEBUG) {
1260 printf("(write) len: %d\n", *rbuflen);
1261 bprint(rbuf, *rbuflen);
1264 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1267 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1272 #endif /* no afp/asp */
1276 DSI *dsi = obj->handle;
1278 /* find out what we have already and write it out. */
1279 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1280 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1281 dsi_writeflush(dsi);
1283 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1288 #if 0 /*def HAVE_SENDFILE_WRITE*/
1289 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1290 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1291 offset, dsi->datasize)) < 0) {
1299 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1300 goto afp_write_loop;
1302 dsi_writeflush(dsi);
1304 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1305 reqcount, ofork->of_refnum);
1310 goto afp_write_done;
1312 #endif /* 0, was HAVE_SENDFILE_WRITE */
1314 /* loop until everything gets written. currently
1315 * dsi_write handles the end case by itself. */
1316 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1317 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1318 dsi_writeflush(dsi);
1320 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1321 reqcount, ofork->of_refnum);
1330 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1331 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1332 ofork->of_flags |= AFPFORK_DIRTY;
1334 *rbuflen = set_off_t (offset, rbuf, is64);
1338 if (obj->proto == AFPPROTO_DSI) {
1339 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1340 dsi_writeflush(obj->handle);
1342 if (err != AFP_OK) {
1348 /* ---------------------------- */
1349 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1351 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1354 /* ----------------------------
1355 * FIXME need to deal with SIGXFSZ signal
1357 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1359 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1362 /* ---------------------------- */
1363 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1365 struct ofork *ofork;
1367 u_int16_t ofrefnum, bitmap;
1370 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1371 ibuf += sizeof( ofrefnum );
1372 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1373 bitmap = ntohs( bitmap );
1374 ibuf += sizeof( bitmap );
1377 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1378 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1379 return( AFPERR_PARAM );
1382 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1383 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1384 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1385 return( AFPERR_PARAM );
1389 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1390 rbuf + sizeof( u_short ), &buflen ))) {
1394 *rbuflen = buflen + sizeof( u_short );
1395 bitmap = htons( bitmap );
1396 memcpy(rbuf, &bitmap, sizeof( bitmap ));