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 ? */
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): ad_open: %s", s_path->m_name, strerror(errno) );
442 /* the ressource fork is open too */
443 ofork->of_flags |= AFPFORK_OPEN;
447 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
448 if (ad_setname(ofork->of_ad, path)) {
449 ad_flush( ofork->of_ad );
453 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
454 &buflen )) != AFP_OK ) {
455 ad_close( ofork->of_ad, adflags );
459 *rbuflen = buflen + 2 * sizeof( u_int16_t );
460 bitmap = htons( bitmap );
461 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
462 rbuf += sizeof( u_int16_t );
464 /* check WriteInhibit bit if we have a ressource fork
465 * the test is done here, after some Mac trafic capture
467 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
468 ad_getattr(ofork->of_ad, &bshort);
469 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
470 ad_close( ofork->of_ad, adflags );
473 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
474 return(AFPERR_OLOCK);
479 * synchronization locks:
482 /* don't try to lock non-existent rforks. */
483 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
485 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
486 /* can we access the fork? */
489 ad_close( ofork->of_ad, adflags );
492 case EAGAIN: /* return data anyway */
496 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
497 return( AFPERR_DENYCONF );
501 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
502 return( AFPERR_PARAM );
505 if ((access & OPENACC_WR))
506 ofork->of_flags |= AFPFORK_ACCWR;
508 /* the file may be open read only without ressource fork */
509 if ((access & OPENACC_RD))
510 ofork->of_flags |= AFPFORK_ACCRD;
512 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
518 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
522 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
526 u_int16_t ofrefnum, bitmap;
534 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
535 ibuf += sizeof( ofrefnum );
537 memcpy(&bitmap, ibuf, sizeof(bitmap));
538 bitmap = ntohs(bitmap);
539 ibuf += sizeof( bitmap );
542 if (NULL == ( ofork = of_find( ofrefnum )) ) {
543 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
544 return( AFPERR_PARAM );
547 if (ofork->of_vol->v_flags & AFPVOL_RO)
550 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
551 return AFPERR_ACCESS;
553 if ( ofork->of_flags & AFPFORK_DATA) {
555 } else if (ofork->of_flags & AFPFORK_RSRC) {
560 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
561 && eid == ADEID_RFORK
563 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
564 && eid == ADEID_DFORK)) {
565 return AFPERR_BITMAP;
569 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
570 if (afp_version >= 30) {
574 return AFPERR_BITMAP;
577 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
578 return AFPERR_PARAM ;
580 size = get_off_t(&ibuf, is64);
583 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
586 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
587 st_size = ad_size(ofork->of_ad, eid);
589 if (st_size > size &&
590 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
591 goto afp_setfork_err;
593 err = ad_dtruncate( ofork->of_ad, size );
595 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
597 goto afp_setfork_err;
598 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
599 ad_refresh( ofork->of_ad );
601 st_size = ad_size(ofork->of_ad, eid);
603 if (st_size > size &&
604 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
605 goto afp_setfork_err;
607 err = ad_rtruncate(ofork->of_ad, size);
609 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
611 goto afp_setfork_err;
613 if (ad_flush( ofork->of_ad ) < 0) {
614 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
618 return AFPERR_BITMAP;
621 if ( flushfork( ofork ) < 0 ) {
622 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
637 return AFPERR_ACCESS;
648 /* for this to work correctly, we need to check for locks before each
649 * read and write. that's most easily handled by always doing an
650 * appropriate check before each ad_read/ad_write. other things
651 * that can change files like truncate are handled internally to those
654 #define ENDBIT(a) ((a) & 0x80)
655 #define UNLOCKBIT(a) ((a) & 0x01)
658 /* ---------------------- */
659 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
662 off_t offset, length;
670 /* figure out parameters */
672 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
674 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
675 ibuf += sizeof(ofrefnum);
677 if (NULL == ( ofork = of_find( ofrefnum )) ) {
678 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
679 return( AFPERR_PARAM );
682 if ( ofork->of_flags & AFPFORK_DATA) {
684 } else if (ofork->of_flags & AFPFORK_RSRC) {
689 offset = get_off_t(&ibuf, is64);
690 length = get_off_t(&ibuf, is64);
692 /* FIXME AD_FILELOCK test is surely wrong */
694 length = BYTELOCK_MAX;
695 else if (!length || is_neg(is64, length)) {
697 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
702 offset += ad_size(ofork->of_ad, eid);
703 /* FIXME what do we do if file size > 2 GB and
704 it's not byte_lock_ext?
707 if (offset < 0) /* error if we have a negative offset */
710 /* if the file is a read-only file, we use read locks instead of
711 * write locks. that way, we can prevent anyone from initiating
713 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
714 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
715 ofork->of_refnum) < 0) {
719 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
725 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
733 *rbuflen = set_off_t (offset, rbuf, is64);
737 /* --------------------------- */
738 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
740 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
743 /* --------------------------- */
744 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
746 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
751 /* --------------------------- */
752 static int crlf(struct ofork *of)
756 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
757 /* no resource fork or no finderinfo, use our files extension mapping */
758 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
761 /* file type is TEXT */
764 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
771 static ssize_t read_file(struct ofork *ofork, int eid,
772 off_t offset, u_char nlmask,
773 u_char nlchar, char *rbuf,
774 size_t *rbuflen, const int xlate)
780 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
782 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
784 return( AFPERR_PARAM );
786 if ( (size_t)cc < *rbuflen ) {
794 for ( p = rbuf, q = p + cc; p < q; ) {
795 if (( *p++ & nlmask ) == nlchar ) {
806 * If this file is of type TEXT, then swap \012 to \015.
809 for ( p = rbuf, q = p + cc; p < q; p++ ) {
810 if ( *p == '\012' ) {
812 } else if ( *p == '\015' ) {
821 return( AFPERR_EOF );
826 /* -----------------------------
827 * with ddp, afp_read can return fewer bytes than in reqcount
828 * so return EOF only if read actually past end of file not
829 * if offset +reqcount > size of file
831 * getfork size ==> 10430
832 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
833 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
834 * read fork offset 9248 size 1508 ==> 1182 (EOF)
835 * 10752 is a bug in Mac 7.5.x finder
837 * with dsi, should we check that reqcount < server quantum?
839 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
842 off_t offset, saveoff, reqcount, savereqcount;
846 u_char nlmask, nlchar;
849 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
850 ibuf += sizeof( u_short );
852 if (NULL == ( ofork = of_find( ofrefnum )) ) {
853 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
858 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
862 offset = get_off_t(&ibuf, is64);
863 reqcount = get_off_t(&ibuf, is64);
872 /* if we wanted to be picky, we could add in the following
873 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
875 if (reqcount < 0 || offset < 0) {
880 if ( ofork->of_flags & AFPFORK_DATA) {
882 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
883 } else if (ofork->of_flags & AFPFORK_RSRC) {
885 } else { /* fork wasn't opened. this should never really happen. */
890 /* zero request count */
896 savereqcount = reqcount;
898 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
903 #define min(a,b) ((a)<(b)?(a):(b))
904 *rbuflen = min( reqcount, *rbuflen );
905 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
909 /* dsi can stream requests. we can only do this if we're not checking
910 * for an end-of-line character. oh well. */
911 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
912 DSI *dsi = obj->handle;
915 /* reqcount isn't always truthful. we need to deal with that. */
916 size = ad_size(ofork->of_ad, eid);
918 /* subtract off the offset */
920 if (reqcount > size) {
927 /* dsi_readinit() returns size of next read buffer. by this point,
928 * we know that we're sending some data. if we fail, something
929 * horrible happened. */
930 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
933 /* due to the nature of afp packets, we have to exit if we get
934 an error. we can't do this with translation on. */
936 if (!(xlate || Debug(obj) )) {
939 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
940 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
941 if (errno == EINVAL || errno == ENOSYS)
944 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
956 /* fill up our buffer. */
957 while (*rbuflen > 0) {
958 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
964 if (obj->options.flags & OPTION_DEBUG) {
965 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
966 bprint(rbuf, *rbuflen);
969 /* dsi_read() also returns buffer size of next allocation */
970 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
979 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
981 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
982 obj->exit(EXITERR_CLNT);
986 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
994 /* ---------------------- */
995 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
997 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1000 /* ---------------------- */
1001 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1003 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1006 /* ---------------------- */
1007 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1015 memcpy(&vid, ibuf, sizeof(vid));
1016 if (NULL == ( vol = getvolbyvid( vid )) ) {
1017 return( AFPERR_PARAM );
1024 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1026 struct ofork *ofork;
1031 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1033 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1034 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1035 return( AFPERR_PARAM );
1038 if ( flushfork( ofork ) < 0 ) {
1039 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1047 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1048 fsync(2) on OSX is implemented differently than on other platforms.
1049 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1051 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1053 struct ofork *ofork;
1059 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1060 ibuf += sizeof( ofrefnum );
1062 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1063 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1064 return( AFPERR_PARAM );
1067 if ( flushfork( ofork ) < 0 ) {
1068 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1075 /* this is very similar to closefork */
1076 int flushfork(struct ofork *ofork)
1080 int err = 0, doflush = 0;
1082 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1083 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1084 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1085 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1089 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1090 (ofork->of_flags & AFPFORK_RSRC)) {
1092 /* read in the rfork length */
1093 ad_refresh(ofork->of_ad);
1095 /* set the date if we're dirty */
1096 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1097 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1098 ofork->of_flags &= ~AFPFORK_DIRTY;
1102 /* flush the header */
1103 if (doflush && ad_flush(ofork->of_ad) < 0)
1106 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1110 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1111 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1117 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1119 struct ofork *ofork;
1124 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1126 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1127 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1128 return( AFPERR_PARAM );
1130 if ( of_closefork( ofork ) < 0 ) {
1131 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1132 return( AFPERR_PARAM );
1139 static ssize_t write_file(struct ofork *ofork, int eid,
1140 off_t offset, char *rbuf,
1141 size_t rbuflen, const int xlate)
1147 * If this file is of type TEXT, swap \015 to \012.
1150 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1151 if ( *p == '\015' ) {
1153 } else if ( *p == '\012' ) {
1159 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1160 rbuf, rbuflen)) < 0 ) {
1165 return( AFPERR_DFULL );
1167 return AFPERR_ACCESS;
1169 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1170 return( AFPERR_PARAM );
1178 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1179 * the client may have sent us a bunch of data that's not reflected
1180 * in reqcount et al. */
1181 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1183 struct ofork *ofork;
1184 off_t offset, saveoff, reqcount;
1185 int endflag, eid, xlate = 0, err = AFP_OK;
1189 /* figure out parameters */
1191 endflag = ENDBIT(*ibuf);
1193 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1194 ibuf += sizeof( ofrefnum );
1196 offset = get_off_t(&ibuf, is64);
1197 reqcount = get_off_t(&ibuf, is64);
1199 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1200 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1205 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1206 err = AFPERR_ACCESS;
1211 writtenfork = ofork;
1214 if ( ofork->of_flags & AFPFORK_DATA) {
1216 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1217 } else if (ofork->of_flags & AFPFORK_RSRC) {
1220 err = AFPERR_ACCESS; /* should never happen */
1225 offset += ad_size(ofork->of_ad, eid);
1227 /* handle bogus parameters */
1228 if (reqcount < 0 || offset < 0) {
1233 /* offset can overflow on 64-bit capable filesystems.
1234 * report disk full if that's going to happen. */
1235 if (sum_neg(is64, offset, reqcount)) {
1240 if (!reqcount) { /* handle request counts of 0 */
1242 *rbuflen = set_off_t (offset, rbuf, is64);
1247 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1248 reqcount, ofork->of_refnum) < 0) {
1253 /* this is yucky, but dsi can stream i/o and asp can't */
1254 switch (obj->proto) {
1257 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1259 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1260 return( AFPERR_PARAM );
1264 if (obj->options.flags & OPTION_DEBUG) {
1265 printf("(write) len: %d\n", *rbuflen);
1266 bprint(rbuf, *rbuflen);
1269 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1272 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1277 #endif /* no afp/asp */
1281 DSI *dsi = obj->handle;
1283 /* find out what we have already and write it out. */
1284 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1285 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1286 dsi_writeflush(dsi);
1288 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1293 #if 0 /*def HAVE_SENDFILE_WRITE*/
1294 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1295 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1296 offset, dsi->datasize)) < 0) {
1304 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1305 goto afp_write_loop;
1307 dsi_writeflush(dsi);
1309 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1310 reqcount, ofork->of_refnum);
1315 goto afp_write_done;
1317 #endif /* 0, was HAVE_SENDFILE_WRITE */
1319 /* loop until everything gets written. currently
1320 * dsi_write handles the end case by itself. */
1321 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1322 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1323 dsi_writeflush(dsi);
1325 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1326 reqcount, ofork->of_refnum);
1335 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1336 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1337 ofork->of_flags |= AFPFORK_DIRTY;
1339 *rbuflen = set_off_t (offset, rbuf, is64);
1343 if (obj->proto == AFPPROTO_DSI) {
1344 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1345 dsi_writeflush(obj->handle);
1347 if (err != AFP_OK) {
1353 /* ---------------------------- */
1354 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1356 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1359 /* ----------------------------
1360 * FIXME need to deal with SIGXFSZ signal
1362 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1364 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1367 /* ---------------------------- */
1368 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1370 struct ofork *ofork;
1372 u_int16_t ofrefnum, bitmap;
1375 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1376 ibuf += sizeof( ofrefnum );
1377 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1378 bitmap = ntohs( bitmap );
1379 ibuf += sizeof( bitmap );
1382 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1383 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1384 return( AFPERR_PARAM );
1387 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1388 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1389 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1390 return( AFPERR_PARAM );
1394 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1395 rbuf + sizeof( u_short ), &buflen ))) {
1399 *rbuflen = buflen + sizeof( u_short );
1400 bitmap = htons( bitmap );
1401 memcpy(rbuf, &bitmap, sizeof( bitmap ));