2 * $Id: fork.c,v 1.73 2010-03-30 12:55:26 franklahm Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
17 #include <atalk/adouble.h>
18 #include <atalk/logger.h>
20 #include <sys/param.h>
21 #include <sys/socket.h>
23 #include <netatalk/at.h>
25 #include <atalk/dsi.h>
26 #include <atalk/atp.h>
27 #include <atalk/asp.h>
28 #include <atalk/afp.h>
30 #include <atalk/util.h>
31 #include <atalk/cnid.h>
36 #include "directory.h"
41 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
47 struct ofork *writtenfork;
50 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
60 /* can only get the length of the opened fork */
61 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
62 && (ofork->of_flags & AFPFORK_RSRC))
64 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
65 && (ofork->of_flags & AFPFORK_DATA))) {
66 return( AFPERR_BITMAP );
69 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
76 dir = dirlookup(vol, ofork->of_did);
78 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
79 return( AFPERR_MISC );
81 path.m_name = of_name(ofork);
84 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
85 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
86 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
87 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
88 /* 0 is for symlink */
89 if (movecwd(vol, dir) < 0)
90 return( AFPERR_NOOBJ );
91 if ( lstat( path.u_name, st ) < 0 )
92 return( AFPERR_NOOBJ );
94 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
95 return( AFPERR_BITMAP );
99 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
102 /* ---------------------------- */
103 static off_t get_off_t(char **ibuf, int is64)
109 memcpy(&temp, *ibuf, sizeof( temp ));
110 ret = ntohl(temp); /* ntohl is unsigned */
111 *ibuf += sizeof(temp);
114 memcpy(&temp, *ibuf, sizeof( temp ));
115 *ibuf += sizeof(temp);
116 ret = ntohl(temp)| (ret << 32);
119 ret = (int)ret; /* sign extend */
124 /* ---------------------- */
125 static int set_off_t(off_t offset, char *rbuf, int is64)
132 temp = htonl(offset >> 32);
133 memcpy(rbuf, &temp, sizeof( temp ));
134 rbuf += sizeof(temp);
135 ret = sizeof( temp );
136 offset &= 0xffffffff;
138 temp = htonl(offset);
139 memcpy(rbuf, &temp, sizeof( temp ));
140 ret += sizeof( temp );
145 /* ------------------------
147 static int is_neg(int is64, off_t val)
149 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
154 static int sum_neg(int is64, off_t offset, off_t reqcount)
156 if (is_neg(is64, offset +reqcount) )
161 /* -------------------------
163 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
165 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
168 /* -------------------------
170 int getforkmode(struct adouble *adp, int eid, int what)
172 return ad_testlock(adp, eid, what);
175 /* -------------------------
177 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
185 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
186 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
189 if ((access & (OPENACC_RD | OPENACC_DRD))) {
190 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
192 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
195 if ((access & OPENACC_RD) && denyreadset) {
199 if ((access & OPENACC_DRD) && readset) {
203 /* boolean logic is not enough, because getforkmode is not always telling the
206 if ((access & OPENACC_RD)) {
207 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
211 if ((access & OPENACC_DRD)) {
212 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
217 /* ------------same for writing -------------- */
218 if ((access & (OPENACC_WR | OPENACC_DWR))) {
219 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
221 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
224 if ((access & OPENACC_WR) && denywriteset) {
228 if ((access & OPENACC_DWR) && writeset) {
232 if ((access & OPENACC_WR)) {
233 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
237 if ((access & OPENACC_DWR)) {
238 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
243 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
244 return ad_excl_lock(adp, eid);
249 /* ----------------------- */
250 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
254 struct ofork *ofork, *opened;
255 struct adouble *adsame = NULL;
257 int ret, adflags, eid;
259 u_int16_t vid, bitmap, access, ofrefnum;
260 char fork, *path, *upath;
267 memcpy(&vid, ibuf, sizeof( vid ));
271 if (NULL == ( vol = getvolbyvid( vid ))) {
272 return( AFPERR_PARAM );
275 memcpy(&did, ibuf, sizeof( did ));
276 ibuf += sizeof( int );
278 if (NULL == ( dir = dirlookup( vol, did ))) {
282 memcpy(&bitmap, ibuf, sizeof( bitmap ));
283 bitmap = ntohs( bitmap );
284 ibuf += sizeof( bitmap );
285 memcpy(&access, ibuf, sizeof( access ));
286 access = ntohs( access );
287 ibuf += sizeof( access );
289 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
293 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
294 return get_afp_errno(AFPERR_PARAM);
297 if (*s_path->m_name == '\0') {
299 return AFPERR_BADTYPE;
302 /* stat() data fork st is set because it's not a dir */
303 switch ( s_path->st_errno ) {
309 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
311 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
314 /* FIXME should we check it first ? */
315 upath = s_path->u_name;
316 if (!vol_unix_priv(vol)) {
317 if (check_access(upath, access ) < 0) {
318 return AFPERR_ACCESS;
322 if (file_access(s_path, access ) < 0) {
323 return AFPERR_ACCESS;
328 /* XXX: this probably isn't the best way to do this. the already
329 open bits should really be set if the fork is opened by any
330 program, not just this one. however, that's problematic to do
331 if we can't write lock files somewhere. opened is also passed to
332 ad_open so that we can keep file locks together.
333 FIXME: add the fork we are opening?
335 if ((opened = of_findname(s_path))) {
336 adsame = opened->of_ad;
339 if ( fork == OPENFORK_DATA ) {
341 adflags = ADFLAGS_DF|ADFLAGS_HF;
344 adflags = ADFLAGS_HF;
347 path = s_path->m_name;
348 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
349 adsame, st)) == NULL ) {
350 return( AFPERR_NFILE );
354 if (access & OPENACC_WR) {
355 /* try opening in read-write mode */
356 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
364 if (fork == OPENFORK_DATA) {
365 /* try to open only the data fork */
366 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
369 adflags = ADFLAGS_DF;
372 /* here's the deal. we only try to create the resource
373 * fork if the user wants to open it for write acess. */
374 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
376 ofork->of_flags |= AFPFORK_OPEN;
385 ret = AFPERR_BADTYPE;
389 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
396 /* the ressource fork is open too */
397 ofork->of_flags |= AFPFORK_OPEN;
400 /* try opening in read-only mode */
402 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
410 /* see if client asked for a read only data fork */
411 if (fork == OPENFORK_DATA) {
412 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
415 adflags = ADFLAGS_DF;
417 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
418 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
419 * then create in open read-write.
420 * FIXME , it doesn't play well with byte locking example:
421 * ressource fork open read only
422 * locking set on it (no effect, there's no file!)
423 * ressource fork open read write now
432 ret = AFPERR_BADTYPE;
436 LOG(log_error, logtype_afpd, "afp_openfork('%s/%s'): ad_open: errno: %i (%s)",
437 getcwdpath, s_path->m_name, errno, strerror(errno) );
443 /* the ressource fork is open too */
444 ofork->of_flags |= AFPFORK_OPEN;
448 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
449 if (ad_setname(ofork->of_ad, path)) {
450 ad_flush( ofork->of_ad );
454 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
455 &buflen )) != AFP_OK ) {
456 ad_close( ofork->of_ad, adflags );
460 *rbuflen = buflen + 2 * sizeof( u_int16_t );
461 bitmap = htons( bitmap );
462 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
463 rbuf += sizeof( u_int16_t );
465 /* check WriteInhibit bit if we have a ressource fork
466 * the test is done here, after some Mac trafic capture
468 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
469 ad_getattr(ofork->of_ad, &bshort);
470 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
471 ad_close( ofork->of_ad, adflags );
474 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
475 return(AFPERR_OLOCK);
480 * synchronization locks:
483 /* don't try to lock non-existent rforks. */
484 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
486 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
487 /* can we access the fork? */
490 ad_close( ofork->of_ad, adflags );
493 case EAGAIN: /* return data anyway */
497 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
498 return( AFPERR_DENYCONF );
502 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
503 return( AFPERR_PARAM );
506 if ((access & OPENACC_WR))
507 ofork->of_flags |= AFPFORK_ACCWR;
509 /* the file may be open read only without ressource fork */
510 if ((access & OPENACC_RD))
511 ofork->of_flags |= AFPFORK_ACCRD;
513 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
519 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
523 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
527 u_int16_t ofrefnum, bitmap;
535 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
536 ibuf += sizeof( ofrefnum );
538 memcpy(&bitmap, ibuf, sizeof(bitmap));
539 bitmap = ntohs(bitmap);
540 ibuf += sizeof( bitmap );
543 if (NULL == ( ofork = of_find( ofrefnum )) ) {
544 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
545 return( AFPERR_PARAM );
548 if (ofork->of_vol->v_flags & AFPVOL_RO)
551 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
552 return AFPERR_ACCESS;
554 if ( ofork->of_flags & AFPFORK_DATA) {
556 } else if (ofork->of_flags & AFPFORK_RSRC) {
561 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
562 && eid == ADEID_RFORK
564 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
565 && eid == ADEID_DFORK)) {
566 return AFPERR_BITMAP;
570 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
571 if (afp_version >= 30) {
575 return AFPERR_BITMAP;
578 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
579 return AFPERR_PARAM ;
581 size = get_off_t(&ibuf, is64);
584 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
587 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
588 st_size = ad_size(ofork->of_ad, eid);
590 if (st_size > size &&
591 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
592 goto afp_setfork_err;
594 err = ad_dtruncate( ofork->of_ad, size );
596 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
598 goto afp_setfork_err;
599 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
600 ad_refresh( ofork->of_ad );
602 st_size = ad_size(ofork->of_ad, eid);
604 if (st_size > size &&
605 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
606 goto afp_setfork_err;
608 err = ad_rtruncate(ofork->of_ad, size);
610 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
612 goto afp_setfork_err;
614 if (ad_flush( ofork->of_ad ) < 0) {
615 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
619 return AFPERR_BITMAP;
622 if ( flushfork( ofork ) < 0 ) {
623 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
638 return AFPERR_ACCESS;
649 /* for this to work correctly, we need to check for locks before each
650 * read and write. that's most easily handled by always doing an
651 * appropriate check before each ad_read/ad_write. other things
652 * that can change files like truncate are handled internally to those
655 #define ENDBIT(a) ((a) & 0x80)
656 #define UNLOCKBIT(a) ((a) & 0x01)
659 /* ---------------------- */
660 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
663 off_t offset, length;
671 /* figure out parameters */
673 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
675 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
676 ibuf += sizeof(ofrefnum);
678 if (NULL == ( ofork = of_find( ofrefnum )) ) {
679 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
680 return( AFPERR_PARAM );
683 if ( ofork->of_flags & AFPFORK_DATA) {
685 } else if (ofork->of_flags & AFPFORK_RSRC) {
690 offset = get_off_t(&ibuf, is64);
691 length = get_off_t(&ibuf, is64);
693 /* FIXME AD_FILELOCK test is surely wrong */
695 length = BYTELOCK_MAX;
696 else if (!length || is_neg(is64, length)) {
698 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
703 offset += ad_size(ofork->of_ad, eid);
704 /* FIXME what do we do if file size > 2 GB and
705 it's not byte_lock_ext?
708 if (offset < 0) /* error if we have a negative offset */
711 /* if the file is a read-only file, we use read locks instead of
712 * write locks. that way, we can prevent anyone from initiating
714 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
715 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
716 ofork->of_refnum) < 0) {
720 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
726 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
734 *rbuflen = set_off_t (offset, rbuf, is64);
738 /* --------------------------- */
739 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
741 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
744 /* --------------------------- */
745 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
747 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
752 /* --------------------------- */
753 static int crlf(struct ofork *of)
757 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
758 /* no resource fork or no finderinfo, use our files extension mapping */
759 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
762 /* file type is TEXT */
765 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
772 static ssize_t read_file(struct ofork *ofork, int eid,
773 off_t offset, u_char nlmask,
774 u_char nlchar, char *rbuf,
775 size_t *rbuflen, const int xlate)
781 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
783 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
785 return( AFPERR_PARAM );
787 if ( (size_t)cc < *rbuflen ) {
795 for ( p = rbuf, q = p + cc; p < q; ) {
796 if (( *p++ & nlmask ) == nlchar ) {
807 * If this file is of type TEXT, then swap \012 to \015.
810 for ( p = rbuf, q = p + cc; p < q; p++ ) {
811 if ( *p == '\012' ) {
813 } else if ( *p == '\015' ) {
822 return( AFPERR_EOF );
827 /* -----------------------------
828 * with ddp, afp_read can return fewer bytes than in reqcount
829 * so return EOF only if read actually past end of file not
830 * if offset +reqcount > size of file
832 * getfork size ==> 10430
833 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
834 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
835 * read fork offset 9248 size 1508 ==> 1182 (EOF)
836 * 10752 is a bug in Mac 7.5.x finder
838 * with dsi, should we check that reqcount < server quantum?
840 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
843 off_t offset, saveoff, reqcount, savereqcount;
847 u_char nlmask, nlchar;
850 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
851 ibuf += sizeof( u_short );
853 if (NULL == ( ofork = of_find( ofrefnum )) ) {
854 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
859 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
863 offset = get_off_t(&ibuf, is64);
864 reqcount = get_off_t(&ibuf, is64);
873 /* if we wanted to be picky, we could add in the following
874 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
876 if (reqcount < 0 || offset < 0) {
881 if ( ofork->of_flags & AFPFORK_DATA) {
883 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
884 } else if (ofork->of_flags & AFPFORK_RSRC) {
886 } else { /* fork wasn't opened. this should never really happen. */
891 /* zero request count */
897 savereqcount = reqcount;
899 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
904 #define min(a,b) ((a)<(b)?(a):(b))
905 *rbuflen = min( reqcount, *rbuflen );
906 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
910 /* dsi can stream requests. we can only do this if we're not checking
911 * for an end-of-line character. oh well. */
912 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
913 DSI *dsi = obj->handle;
916 /* reqcount isn't always truthful. we need to deal with that. */
917 size = ad_size(ofork->of_ad, eid);
919 /* subtract off the offset */
921 if (reqcount > size) {
928 /* dsi_readinit() returns size of next read buffer. by this point,
929 * we know that we're sending some data. if we fail, something
930 * horrible happened. */
931 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
934 /* due to the nature of afp packets, we have to exit if we get
935 an error. we can't do this with translation on. */
937 if (!(xlate || Debug(obj) )) {
940 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
941 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
942 if (errno == EINVAL || errno == ENOSYS)
945 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
957 /* fill up our buffer. */
958 while (*rbuflen > 0) {
959 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
965 if (obj->options.flags & OPTION_DEBUG) {
966 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
967 bprint(rbuf, *rbuflen);
970 /* dsi_read() also returns buffer size of next allocation */
971 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
980 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
982 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
983 obj->exit(EXITERR_CLNT);
987 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
995 /* ---------------------- */
996 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
998 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1001 /* ---------------------- */
1002 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1004 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1007 /* ---------------------- */
1008 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1016 memcpy(&vid, ibuf, sizeof(vid));
1017 if (NULL == ( vol = getvolbyvid( vid )) ) {
1018 return( AFPERR_PARAM );
1025 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1027 struct ofork *ofork;
1032 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1034 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1035 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1036 return( AFPERR_PARAM );
1039 if ( flushfork( ofork ) < 0 ) {
1040 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1048 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1049 fsync(2) on OSX is implemented differently than on other platforms.
1050 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1052 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1054 struct ofork *ofork;
1060 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1061 ibuf += sizeof( ofrefnum );
1063 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1064 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1065 return( AFPERR_PARAM );
1068 if ( flushfork( ofork ) < 0 ) {
1069 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1076 /* this is very similar to closefork */
1077 int flushfork(struct ofork *ofork)
1081 int err = 0, doflush = 0;
1083 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1084 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1085 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1086 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1090 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1091 (ofork->of_flags & AFPFORK_RSRC)) {
1093 /* read in the rfork length */
1094 ad_refresh(ofork->of_ad);
1096 /* set the date if we're dirty */
1097 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1098 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1099 ofork->of_flags &= ~AFPFORK_DIRTY;
1103 /* flush the header */
1104 if (doflush && ad_flush(ofork->of_ad) < 0)
1107 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1111 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1112 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1118 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1120 struct ofork *ofork;
1125 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1127 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1128 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1129 return( AFPERR_PARAM );
1131 if ( of_closefork( ofork ) < 0 ) {
1132 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1133 return( AFPERR_PARAM );
1140 static ssize_t write_file(struct ofork *ofork, int eid,
1141 off_t offset, char *rbuf,
1142 size_t rbuflen, const int xlate)
1148 * If this file is of type TEXT, swap \015 to \012.
1151 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1152 if ( *p == '\015' ) {
1154 } else if ( *p == '\012' ) {
1160 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1161 rbuf, rbuflen)) < 0 ) {
1166 return( AFPERR_DFULL );
1168 return AFPERR_ACCESS;
1170 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1171 return( AFPERR_PARAM );
1179 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1180 * the client may have sent us a bunch of data that's not reflected
1181 * in reqcount et al. */
1182 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1184 struct ofork *ofork;
1185 off_t offset, saveoff, reqcount;
1186 int endflag, eid, xlate = 0, err = AFP_OK;
1190 /* figure out parameters */
1192 endflag = ENDBIT(*ibuf);
1194 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1195 ibuf += sizeof( ofrefnum );
1197 offset = get_off_t(&ibuf, is64);
1198 reqcount = get_off_t(&ibuf, is64);
1200 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1201 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1206 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1207 err = AFPERR_ACCESS;
1212 writtenfork = ofork;
1215 if ( ofork->of_flags & AFPFORK_DATA) {
1217 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1218 } else if (ofork->of_flags & AFPFORK_RSRC) {
1221 err = AFPERR_ACCESS; /* should never happen */
1226 offset += ad_size(ofork->of_ad, eid);
1228 /* handle bogus parameters */
1229 if (reqcount < 0 || offset < 0) {
1234 /* offset can overflow on 64-bit capable filesystems.
1235 * report disk full if that's going to happen. */
1236 if (sum_neg(is64, offset, reqcount)) {
1241 if (!reqcount) { /* handle request counts of 0 */
1243 *rbuflen = set_off_t (offset, rbuf, is64);
1248 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1249 reqcount, ofork->of_refnum) < 0) {
1254 /* this is yucky, but dsi can stream i/o and asp can't */
1255 switch (obj->proto) {
1258 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1260 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1261 return( AFPERR_PARAM );
1265 if (obj->options.flags & OPTION_DEBUG) {
1266 printf("(write) len: %d\n", *rbuflen);
1267 bprint(rbuf, *rbuflen);
1270 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1273 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1278 #endif /* no afp/asp */
1282 DSI *dsi = obj->handle;
1284 /* find out what we have already and write it out. */
1285 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1286 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1287 dsi_writeflush(dsi);
1289 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1294 #if 0 /*def HAVE_SENDFILE_WRITE*/
1295 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1296 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1297 offset, dsi->datasize)) < 0) {
1305 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1306 goto afp_write_loop;
1308 dsi_writeflush(dsi);
1310 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1311 reqcount, ofork->of_refnum);
1316 goto afp_write_done;
1318 #endif /* 0, was HAVE_SENDFILE_WRITE */
1320 /* loop until everything gets written. currently
1321 * dsi_write handles the end case by itself. */
1322 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1323 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1324 dsi_writeflush(dsi);
1326 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1327 reqcount, ofork->of_refnum);
1336 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1337 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1338 ofork->of_flags |= AFPFORK_DIRTY;
1340 *rbuflen = set_off_t (offset, rbuf, is64);
1344 if (obj->proto == AFPPROTO_DSI) {
1345 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1346 dsi_writeflush(obj->handle);
1348 if (err != AFP_OK) {
1354 /* ---------------------------- */
1355 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1357 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1360 /* ----------------------------
1361 * FIXME need to deal with SIGXFSZ signal
1363 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1365 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1368 /* ---------------------------- */
1369 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1371 struct ofork *ofork;
1373 u_int16_t ofrefnum, bitmap;
1376 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1377 ibuf += sizeof( ofrefnum );
1378 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1379 bitmap = ntohs( bitmap );
1380 ibuf += sizeof( bitmap );
1383 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1384 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1385 return( AFPERR_PARAM );
1388 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1389 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1390 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1391 return( AFPERR_PARAM );
1395 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1396 rbuf + sizeof( u_short ), &buflen ))) {
1400 *rbuflen = buflen + sizeof( u_short );
1401 bitmap = htons( bitmap );
1402 memcpy(rbuf, &bitmap, sizeof( bitmap ));