2 * $Id: fork.c,v 1.65 2009-10-15 10:43:13 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
18 #include <atalk/adouble.h>
19 #include <atalk/logger.h>
21 #include <sys/param.h>
22 #include <sys/socket.h>
24 #include <netatalk/at.h>
26 #include <atalk/dsi.h>
27 #include <atalk/atp.h>
28 #include <atalk/asp.h>
29 #include <atalk/afp.h>
31 #include <atalk/util.h>
32 #include <atalk/cnid.h>
37 #include "directory.h"
42 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
48 struct ofork *writtenfork;
51 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
61 /* can only get the length of the opened fork */
62 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
63 && (ofork->of_flags & AFPFORK_RSRC))
65 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
66 && (ofork->of_flags & AFPFORK_DATA))) {
67 return( AFPERR_BITMAP );
70 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
79 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
80 return( AFPERR_MISC );
82 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 ) == -1 ) {
88 if (movecwd(vol, dir) < 0)
89 return( AFPERR_NOOBJ );
90 if ( stat( path.u_name, st ) < 0 )
91 return( AFPERR_NOOBJ );
93 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
94 return( AFPERR_BITMAP );
98 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
101 /* ---------------------------- */
102 static off_t get_off_t(char **ibuf, int is64)
108 memcpy(&temp, *ibuf, sizeof( temp ));
109 ret = ntohl(temp); /* ntohl is unsigned */
110 *ibuf += sizeof(temp);
113 memcpy(&temp, *ibuf, sizeof( temp ));
114 *ibuf += sizeof(temp);
115 ret = ntohl(temp)| (ret << 32);
118 ret = (int)ret; /* sign extend */
123 /* ---------------------- */
124 static int set_off_t(off_t offset, char *rbuf, int is64)
131 temp = htonl(offset >> 32);
132 memcpy(rbuf, &temp, sizeof( temp ));
133 rbuf += sizeof(temp);
134 ret = sizeof( temp );
135 offset &= 0xffffffff;
137 temp = htonl(offset);
138 memcpy(rbuf, &temp, sizeof( temp ));
139 ret += sizeof( temp );
144 /* ------------------------
146 static int is_neg(int is64, off_t val)
148 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
153 static int sum_neg(int is64, off_t offset, off_t reqcount)
155 if (is_neg(is64, offset +reqcount) )
160 /* -------------------------
162 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
164 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
167 /* -------------------------
169 int getforkmode(struct adouble *adp, int eid, int what)
171 return ad_testlock(adp, eid, what);
174 /* -------------------------
176 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
184 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
185 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
188 if ((access & (OPENACC_RD | OPENACC_DRD))) {
189 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
191 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
194 if ((access & OPENACC_RD) && denyreadset) {
198 if ((access & OPENACC_DRD) && readset) {
202 /* boolean logic is not enough, because getforkmode is not always telling the
205 if ((access & OPENACC_RD)) {
206 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
210 if ((access & OPENACC_DRD)) {
211 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
216 /* ------------same for writing -------------- */
217 if ((access & (OPENACC_WR | OPENACC_DWR))) {
218 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
220 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
223 if ((access & OPENACC_WR) && denywriteset) {
227 if ((access & OPENACC_DWR) && writeset) {
231 if ((access & OPENACC_WR)) {
232 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
236 if ((access & OPENACC_DWR)) {
237 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
242 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
243 return ad_excl_lock(adp, eid);
248 /* ----------------------- */
249 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
253 struct ofork *ofork, *opened;
254 struct adouble *adsame = NULL;
256 int ret, adflags, eid;
258 u_int16_t vid, bitmap, access, ofrefnum;
259 char fork, *path, *upath;
266 memcpy(&vid, ibuf, sizeof( vid ));
270 if (NULL == ( vol = getvolbyvid( vid ))) {
271 return( AFPERR_PARAM );
274 memcpy(&did, ibuf, sizeof( did ));
275 ibuf += sizeof( int );
277 if (NULL == ( dir = dirlookup( vol, did ))) {
281 memcpy(&bitmap, ibuf, sizeof( bitmap ));
282 bitmap = ntohs( bitmap );
283 ibuf += sizeof( bitmap );
284 memcpy(&access, ibuf, sizeof( access ));
285 access = ntohs( access );
286 ibuf += sizeof( access );
288 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
292 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
293 return get_afp_errno(AFPERR_PARAM);
296 if (*s_path->m_name == '\0') {
298 return AFPERR_BADTYPE;
301 /* stat() data fork st is set because it's not a dir */
302 switch ( s_path->st_errno ) {
308 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
310 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
313 /* FIXME should we check it first ? */
314 upath = s_path->u_name;
315 if (!vol_unix_priv(vol)) {
316 if (check_access(upath, access ) < 0) {
317 return AFPERR_ACCESS;
321 if (file_access(s_path, access ) < 0) {
322 return AFPERR_ACCESS;
327 /* XXX: this probably isn't the best way to do this. the already
328 open bits should really be set if the fork is opened by any
329 program, not just this one. however, that's problematic to do
330 if we can't write lock files somewhere. opened is also passed to
331 ad_open so that we can keep file locks together.
332 FIXME: add the fork we are opening?
334 if ((opened = of_findname(s_path))) {
335 adsame = opened->of_ad;
338 if ( fork == OPENFORK_DATA ) {
340 adflags = ADFLAGS_DF|ADFLAGS_HF;
343 adflags = ADFLAGS_HF;
346 path = s_path->m_name;
347 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
348 adsame, st)) == NULL ) {
349 return( AFPERR_NFILE );
353 if (access & OPENACC_WR) {
354 /* try opening in read-write mode */
355 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
363 if (fork == OPENFORK_DATA) {
364 /* try to open only the data fork */
365 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
368 adflags = ADFLAGS_DF;
371 /* here's the deal. we only try to create the resource
372 * fork if the user wants to open it for write acess. */
373 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
375 ofork->of_flags |= AFPFORK_OPEN;
384 ret = AFPERR_BADTYPE;
388 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
395 /* the ressource fork is open too */
396 ofork->of_flags |= AFPFORK_OPEN;
399 /* try opening in read-only mode */
401 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
409 /* see if client asked for a read only data fork */
410 if (fork == OPENFORK_DATA) {
411 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
414 adflags = ADFLAGS_DF;
416 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
417 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
418 * then create in open read-write.
419 * FIXME , it doesn't play well with byte locking example:
420 * ressource fork open read only
421 * locking set on it (no effect, there's no file!)
422 * ressource fork open read write now
431 ret = AFPERR_BADTYPE;
435 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
441 /* the ressource fork is open too */
442 ofork->of_flags |= AFPFORK_OPEN;
446 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
447 if (ad_setname(ofork->of_ad, path)) {
448 ad_flush( ofork->of_ad );
452 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
453 &buflen )) != AFP_OK ) {
454 ad_close( ofork->of_ad, adflags );
458 *rbuflen = buflen + 2 * sizeof( u_int16_t );
459 bitmap = htons( bitmap );
460 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
461 rbuf += sizeof( u_int16_t );
463 /* check WriteInhibit bit if we have a ressource fork
464 * the test is done here, after some Mac trafic capture
466 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
467 ad_getattr(ofork->of_ad, &bshort);
468 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
469 ad_close( ofork->of_ad, adflags );
472 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
473 return(AFPERR_OLOCK);
478 * synchronization locks:
481 /* don't try to lock non-existent rforks. */
482 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
484 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
485 /* can we access the fork? */
488 ad_close( ofork->of_ad, adflags );
491 case EAGAIN: /* return data anyway */
495 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
496 return( AFPERR_DENYCONF );
500 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
501 return( AFPERR_PARAM );
504 if ((access & OPENACC_WR))
505 ofork->of_flags |= AFPFORK_ACCWR;
507 /* the file may be open read only without ressource fork */
508 if ((access & OPENACC_RD))
509 ofork->of_flags |= AFPFORK_ACCRD;
511 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
517 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
521 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
525 u_int16_t ofrefnum, bitmap;
533 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
534 ibuf += sizeof( ofrefnum );
536 memcpy(&bitmap, ibuf, sizeof(bitmap));
537 bitmap = ntohs(bitmap);
538 ibuf += sizeof( bitmap );
541 if (NULL == ( ofork = of_find( ofrefnum )) ) {
542 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
543 return( AFPERR_PARAM );
546 if (ofork->of_vol->v_flags & AFPVOL_RO)
549 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
550 return AFPERR_ACCESS;
552 if ( ofork->of_flags & AFPFORK_DATA) {
554 } else if (ofork->of_flags & AFPFORK_RSRC) {
559 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
560 && eid == ADEID_RFORK
562 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
563 && eid == ADEID_DFORK)) {
564 return AFPERR_BITMAP;
568 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
569 if (afp_version >= 30) {
573 return AFPERR_BITMAP;
576 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
577 return AFPERR_PARAM ;
579 size = get_off_t(&ibuf, is64);
582 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
585 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
586 st_size = ad_size(ofork->of_ad, eid);
588 if (st_size > size &&
589 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
590 goto afp_setfork_err;
592 err = ad_dtruncate( ofork->of_ad, size );
594 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
596 goto afp_setfork_err;
597 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
598 ad_refresh( ofork->of_ad );
600 st_size = ad_size(ofork->of_ad, eid);
602 if (st_size > size &&
603 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
604 goto afp_setfork_err;
606 err = ad_rtruncate(ofork->of_ad, size);
608 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
610 goto afp_setfork_err;
612 if (ad_flush( ofork->of_ad ) < 0) {
613 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
617 return AFPERR_BITMAP;
620 if ( flushfork( ofork ) < 0 ) {
621 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
636 return AFPERR_ACCESS;
647 /* for this to work correctly, we need to check for locks before each
648 * read and write. that's most easily handled by always doing an
649 * appropriate check before each ad_read/ad_write. other things
650 * that can change files like truncate are handled internally to those
653 #define ENDBIT(a) ((a) & 0x80)
654 #define UNLOCKBIT(a) ((a) & 0x01)
657 /* ---------------------- */
658 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
661 off_t offset, length;
669 /* figure out parameters */
671 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
673 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
674 ibuf += sizeof(ofrefnum);
676 if (NULL == ( ofork = of_find( ofrefnum )) ) {
677 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
678 return( AFPERR_PARAM );
681 if ( ofork->of_flags & AFPFORK_DATA) {
683 } else if (ofork->of_flags & AFPFORK_RSRC) {
688 offset = get_off_t(&ibuf, is64);
689 length = get_off_t(&ibuf, is64);
691 /* FIXME AD_FILELOCK test is surely wrong */
693 length = BYTELOCK_MAX;
694 else if (!length || is_neg(is64, length)) {
696 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
701 offset += ad_size(ofork->of_ad, eid);
702 /* FIXME what do we do if file size > 2 GB and
703 it's not byte_lock_ext?
706 if (offset < 0) /* error if we have a negative offset */
709 /* if the file is a read-only file, we use read locks instead of
710 * write locks. that way, we can prevent anyone from initiating
712 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
713 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
714 ofork->of_refnum) < 0) {
718 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
724 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
732 *rbuflen = set_off_t (offset, rbuf, is64);
736 /* --------------------------- */
737 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
739 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
742 /* --------------------------- */
743 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
745 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
750 /* --------------------------- */
751 static int crlf(struct ofork *of)
755 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
756 /* no resource fork or no finderinfo, use our files extension mapping */
757 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
760 /* file type is TEXT */
763 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
770 static ssize_t read_file(struct ofork *ofork, int eid,
771 off_t offset, u_char nlmask,
772 u_char nlchar, char *rbuf,
773 size_t *rbuflen, const int xlate)
779 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
781 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
783 return( AFPERR_PARAM );
785 if ( (size_t)cc < *rbuflen ) {
793 for ( p = rbuf, q = p + cc; p < q; ) {
794 if (( *p++ & nlmask ) == nlchar ) {
805 * If this file is of type TEXT, then swap \012 to \015.
808 for ( p = rbuf, q = p + cc; p < q; p++ ) {
809 if ( *p == '\012' ) {
811 } else if ( *p == '\015' ) {
820 return( AFPERR_EOF );
825 /* -----------------------------
826 * with ddp, afp_read can return fewer bytes than in reqcount
827 * so return EOF only if read actually past end of file not
828 * if offset +reqcount > size of file
830 * getfork size ==> 10430
831 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
832 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
833 * read fork offset 9248 size 1508 ==> 1182 (EOF)
834 * 10752 is a bug in Mac 7.5.x finder
836 * with dsi, should we check that reqcount < server quantum?
838 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
841 off_t offset, saveoff, reqcount, savereqcount;
845 u_char nlmask, nlchar;
848 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
849 ibuf += sizeof( u_short );
851 if (NULL == ( ofork = of_find( ofrefnum )) ) {
852 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
857 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
861 offset = get_off_t(&ibuf, is64);
862 reqcount = get_off_t(&ibuf, is64);
871 /* if we wanted to be picky, we could add in the following
872 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
874 if (reqcount < 0 || offset < 0) {
879 if ( ofork->of_flags & AFPFORK_DATA) {
881 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
882 } else if (ofork->of_flags & AFPFORK_RSRC) {
884 } else { /* fork wasn't opened. this should never really happen. */
889 /* zero request count */
895 savereqcount = reqcount;
897 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
902 #define min(a,b) ((a)<(b)?(a):(b))
903 *rbuflen = min( reqcount, *rbuflen );
904 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
908 /* dsi can stream requests. we can only do this if we're not checking
909 * for an end-of-line character. oh well. */
910 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
911 DSI *dsi = obj->handle;
913 int non_blocking = 0;
916 if (obj->options.flags & OPTION_DEBUG) {
917 printf( "(read) reply: %d/%d, %d\n", *rbuflen,(int) reqcount, dsi->clientID);
918 bprint(rbuf, *rbuflen);
921 /* reqcount isn't always truthful. we need to deal with that. */
922 size = ad_size(ofork->of_ad, eid);
924 /* subtract off the offset */
926 if (reqcount > size) {
933 /* dsi_readinit() returns size of next read buffer. by this point,
934 * we know that we're sending some data. if we fail, something
935 * horrible happened. */
936 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
939 /* due to the nature of afp packets, we have to exit if we get
940 an error. we can't do this with translation on. */
941 #if 0 /* ifdef WITH_SENDFILE */
942 /* FIXME with OS X deadlock partial workaround we can't use sendfile */
943 if (!(xlate || Debug(obj) )) {
944 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize) < 0) {
945 if (errno == EINVAL || errno == ENOSYS)
948 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
960 /* fill up our buffer. */
962 /* set to non blocking mode */
966 /* fill up our buffer. */
967 while (*rbuflen > 0) {
968 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
974 if (obj->options.flags & OPTION_DEBUG) {
975 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
976 bprint(rbuf, *rbuflen);
979 /* dsi_read() also returns buffer size of next allocation */
980 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
986 /* set back to blocking mode */
993 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
995 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
996 obj->exit(EXITERR_CLNT);
1000 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1008 /* ---------------------- */
1009 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1011 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1014 /* ---------------------- */
1015 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1017 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1020 /* ---------------------- */
1021 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1029 memcpy(&vid, ibuf, sizeof(vid));
1030 if (NULL == ( vol = getvolbyvid( vid )) ) {
1031 return( AFPERR_PARAM );
1038 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1040 struct ofork *ofork;
1045 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1047 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1048 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1049 return( AFPERR_PARAM );
1052 if ( flushfork( ofork ) < 0 ) {
1053 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1061 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1062 fsync(2) on OSX is implemented differently than on other platforms.
1063 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1065 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1067 struct ofork *ofork;
1073 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1074 ibuf += sizeof( ofrefnum );
1076 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1077 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1078 return( AFPERR_PARAM );
1081 if ( flushfork( ofork ) < 0 ) {
1082 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1089 /* this is very similar to closefork */
1090 int flushfork(struct ofork *ofork)
1094 int err = 0, doflush = 0;
1096 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1097 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1098 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1099 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1103 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1104 (ofork->of_flags & AFPFORK_RSRC)) {
1106 /* read in the rfork length */
1107 ad_refresh(ofork->of_ad);
1109 /* set the date if we're dirty */
1110 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1111 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1112 ofork->of_flags &= ~AFPFORK_DIRTY;
1116 /* flush the header */
1117 if (doflush && ad_flush(ofork->of_ad) < 0)
1120 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1124 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1125 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1131 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1133 struct ofork *ofork;
1138 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1140 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1141 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1142 return( AFPERR_PARAM );
1144 if ( of_closefork( ofork ) < 0 ) {
1145 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1146 return( AFPERR_PARAM );
1153 static ssize_t write_file(struct ofork *ofork, int eid,
1154 off_t offset, char *rbuf,
1155 size_t rbuflen, const int xlate)
1161 * If this file is of type TEXT, swap \015 to \012.
1164 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1165 if ( *p == '\015' ) {
1167 } else if ( *p == '\012' ) {
1173 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1174 rbuf, rbuflen)) < 0 ) {
1179 return( AFPERR_DFULL );
1181 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1182 return( AFPERR_PARAM );
1190 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1191 * the client may have sent us a bunch of data that's not reflected
1192 * in reqcount et al. */
1193 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1195 struct ofork *ofork;
1196 off_t offset, saveoff, reqcount;
1197 int endflag, eid, xlate = 0, err = AFP_OK;
1201 /* figure out parameters */
1203 endflag = ENDBIT(*ibuf);
1205 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1206 ibuf += sizeof( ofrefnum );
1208 offset = get_off_t(&ibuf, is64);
1209 reqcount = get_off_t(&ibuf, is64);
1211 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1212 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1217 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1218 err = AFPERR_ACCESS;
1223 writtenfork = ofork;
1226 if ( ofork->of_flags & AFPFORK_DATA) {
1228 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1229 } else if (ofork->of_flags & AFPFORK_RSRC) {
1232 err = AFPERR_ACCESS; /* should never happen */
1237 offset += ad_size(ofork->of_ad, eid);
1239 /* handle bogus parameters */
1240 if (reqcount < 0 || offset < 0) {
1245 /* offset can overflow on 64-bit capable filesystems.
1246 * report disk full if that's going to happen. */
1247 if (sum_neg(is64, offset, reqcount)) {
1252 if (!reqcount) { /* handle request counts of 0 */
1254 *rbuflen = set_off_t (offset, rbuf, is64);
1259 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1260 reqcount, ofork->of_refnum) < 0) {
1265 /* this is yucky, but dsi can stream i/o and asp can't */
1266 switch (obj->proto) {
1269 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1271 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1272 return( AFPERR_PARAM );
1276 if (obj->options.flags & OPTION_DEBUG) {
1277 printf("(write) len: %d\n", *rbuflen);
1278 bprint(rbuf, *rbuflen);
1281 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1284 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1289 #endif /* no afp/asp */
1293 DSI *dsi = obj->handle;
1295 /* find out what we have already and write it out. */
1296 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1297 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1298 dsi_writeflush(dsi);
1300 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1305 #if 0 /*def HAVE_SENDFILE_WRITE*/
1306 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1307 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1308 offset, dsi->datasize)) < 0) {
1316 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1317 goto afp_write_loop;
1319 dsi_writeflush(dsi);
1321 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1322 reqcount, ofork->of_refnum);
1327 goto afp_write_done;
1329 #endif /* 0, was HAVE_SENDFILE_WRITE */
1331 /* loop until everything gets written. currently
1332 * dsi_write handles the end case by itself. */
1333 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1335 if ( obj->options.flags & OPTION_DEBUG ) {
1336 printf("(write) command cont'd: %d\n", cc);
1340 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1341 dsi_writeflush(dsi);
1343 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1344 reqcount, ofork->of_refnum);
1353 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1354 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1355 ofork->of_flags |= AFPFORK_DIRTY;
1357 *rbuflen = set_off_t (offset, rbuf, is64);
1361 if (obj->proto == AFPPROTO_DSI) {
1362 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1363 dsi_writeflush(obj->handle);
1365 if (err != AFP_OK) {
1371 /* ---------------------------- */
1372 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1374 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1377 /* ----------------------------
1378 * FIXME need to deal with SIGXFSZ signal
1380 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1382 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1385 /* ---------------------------- */
1386 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1388 struct ofork *ofork;
1390 u_int16_t ofrefnum, bitmap;
1393 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1394 ibuf += sizeof( ofrefnum );
1395 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1396 bitmap = ntohs( bitmap );
1397 ibuf += sizeof( bitmap );
1400 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1401 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1402 return( AFPERR_PARAM );
1405 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1406 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1407 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1408 return( AFPERR_PARAM );
1412 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1413 rbuf + sizeof( u_short ), &buflen ))) {
1417 *rbuflen = buflen + sizeof( u_short );
1418 bitmap = htons( bitmap );
1419 memcpy(rbuf, &bitmap, sizeof( bitmap ));