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>
29 #include <atalk/util.h>
30 #include <atalk/cnid.h>
31 #include <atalk/globals.h>
35 #include "directory.h"
40 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
46 struct ofork *writtenfork;
49 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
59 /* can only get the length of the opened fork */
60 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
61 && (ofork->of_flags & AFPFORK_RSRC))
63 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
64 && (ofork->of_flags & AFPFORK_DATA))) {
65 return( AFPERR_BITMAP );
68 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
75 dir = dirlookup(vol, ofork->of_did);
77 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
78 return( AFPERR_MISC );
80 path.m_name = of_name(ofork);
83 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
84 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
85 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
86 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
87 /* 0 is for symlink */
88 if (movecwd(vol, dir) < 0)
89 return( AFPERR_NOOBJ );
90 if ( lstat( 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, off_t what)
164 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
167 /* -------------------------
169 int getforkmode(struct adouble *adp, int eid, off_t 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(vol, 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/%s'): ad_open: errno: %i (%s)",
436 getcwdpath, s_path->m_name, errno, 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;
641 LOG(log_error, logtype_afpd, "afp_setforkparams: DISK FULL");
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 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
898 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
900 savereqcount = reqcount;
902 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
907 *rbuflen = MIN(reqcount, *rbuflen);
908 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
909 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
910 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
913 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
914 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
916 /* dsi can stream requests. we can only do this if we're not checking
917 * for an end-of-line character. oh well. */
918 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
919 DSI *dsi = obj->handle;
922 /* reqcount isn't always truthful. we need to deal with that. */
923 size = ad_size(ofork->of_ad, eid);
925 /* subtract off the offset */
927 if (reqcount > size) {
934 /* dsi_readinit() returns size of next read buffer. by this point,
935 * we know that we're sending some data. if we fail, something
936 * horrible happened. */
937 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
940 /* due to the nature of afp packets, we have to exit if we get
941 an error. we can't do this with translation on. */
943 if (!(xlate || Debug(obj) )) {
946 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
948 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
949 if (errno == EINVAL || errno == ENOSYS)
952 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
964 /* fill up our buffer. */
965 while (*rbuflen > 0) {
966 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
971 /* dsi_read() also returns buffer size of next allocation */
972 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
981 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
983 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
984 obj->exit(EXITERR_CLNT);
988 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
996 /* ---------------------- */
997 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
999 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1002 /* ---------------------- */
1003 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1005 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1008 /* ---------------------- */
1009 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1017 memcpy(&vid, ibuf, sizeof(vid));
1018 if (NULL == ( vol = getvolbyvid( vid )) ) {
1019 return( AFPERR_PARAM );
1026 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1028 struct ofork *ofork;
1033 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1035 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1036 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1037 return( AFPERR_PARAM );
1040 if ( flushfork( ofork ) < 0 ) {
1041 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1049 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1050 fsync(2) on OSX is implemented differently than on other platforms.
1051 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1053 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1055 struct ofork *ofork;
1061 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1062 ibuf += sizeof( ofrefnum );
1064 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1065 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1066 return( AFPERR_PARAM );
1069 if ( flushfork( ofork ) < 0 ) {
1070 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1077 /* this is very similar to closefork */
1078 int flushfork(struct ofork *ofork)
1082 int err = 0, doflush = 0;
1084 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1085 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1086 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1087 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1091 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1092 (ofork->of_flags & AFPFORK_RSRC)) {
1094 /* read in the rfork length */
1095 ad_refresh(ofork->of_ad);
1097 /* set the date if we're dirty */
1098 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1099 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1100 ofork->of_flags &= ~AFPFORK_DIRTY;
1104 /* flush the header */
1105 if (doflush && ad_flush(ofork->of_ad) < 0)
1108 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1112 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1113 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1119 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1121 struct ofork *ofork;
1126 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1128 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1129 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1130 return( AFPERR_PARAM );
1132 if ( of_closefork( ofork ) < 0 ) {
1133 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1134 return( AFPERR_PARAM );
1141 static ssize_t write_file(struct ofork *ofork, int eid,
1142 off_t offset, char *rbuf,
1143 size_t rbuflen, const int xlate)
1149 * If this file is of type TEXT, swap \015 to \012.
1152 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1153 if ( *p == '\015' ) {
1155 } else if ( *p == '\012' ) {
1161 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1162 rbuf, rbuflen)) < 0 ) {
1167 LOG(log_error, logtype_afpd, "write_file: DISK FULL");
1168 return( AFPERR_DFULL );
1170 return AFPERR_ACCESS;
1172 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1173 return( AFPERR_PARAM );
1181 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1182 * the client may have sent us a bunch of data that's not reflected
1183 * in reqcount et al. */
1184 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1186 struct ofork *ofork;
1187 off_t offset, saveoff, reqcount, oldsize, newsize;
1188 int endflag, eid, xlate = 0, err = AFP_OK;
1192 /* figure out parameters */
1194 endflag = ENDBIT(*ibuf);
1196 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1197 ibuf += sizeof( ofrefnum );
1199 offset = get_off_t(&ibuf, is64);
1200 reqcount = get_off_t(&ibuf, is64);
1202 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1203 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1208 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1209 err = AFPERR_ACCESS;
1214 writtenfork = ofork;
1217 if ( ofork->of_flags & AFPFORK_DATA) {
1219 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1220 } else if (ofork->of_flags & AFPFORK_RSRC) {
1223 err = AFPERR_ACCESS; /* should never happen */
1227 oldsize = ad_size(ofork->of_ad, eid);
1231 /* handle bogus parameters */
1232 if (reqcount < 0 || offset < 0) {
1237 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1239 /* offset can overflow on 64-bit capable filesystems.
1240 * report disk full if that's going to happen. */
1241 if (sum_neg(is64, offset, reqcount)) {
1242 LOG(log_error, logtype_afpd, "write_fork: DISK FULL");
1247 if (!reqcount) { /* handle request counts of 0 */
1249 *rbuflen = set_off_t (offset, rbuf, is64);
1254 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1255 reqcount, ofork->of_refnum) < 0) {
1260 /* this is yucky, but dsi can stream i/o and asp can't */
1261 switch (obj->proto) {
1264 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1266 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1267 return( AFPERR_PARAM );
1271 if (obj->options.flags & OPTION_DEBUG) {
1272 printf("(write) len: %d\n", *rbuflen);
1273 bprint(rbuf, *rbuflen);
1276 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1279 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1284 #endif /* no afp/asp */
1288 DSI *dsi = obj->handle;
1290 /* find out what we have already and write it out. */
1291 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1292 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1293 dsi_writeflush(dsi);
1295 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1300 #if 0 /*def HAVE_SENDFILE_WRITE*/
1301 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1302 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1303 offset, dsi->datasize)) < 0) {
1311 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1312 goto afp_write_loop;
1314 dsi_writeflush(dsi);
1316 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1317 reqcount, ofork->of_refnum);
1322 goto afp_write_done;
1324 #endif /* 0, was HAVE_SENDFILE_WRITE */
1326 /* loop until everything gets written. currently
1327 * dsi_write handles the end case by itself. */
1328 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1329 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1330 dsi_writeflush(dsi);
1332 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1333 reqcount, ofork->of_refnum);
1342 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1343 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1344 ofork->of_flags |= AFPFORK_DIRTY;
1346 /* we have modified any fork, remember until close_fork */
1347 ofork->of_flags |= AFPFORK_MODIFIED;
1349 /* update write count */
1350 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1352 *rbuflen = set_off_t (offset, rbuf, is64);
1356 if (obj->proto == AFPPROTO_DSI) {
1357 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1358 dsi_writeflush(obj->handle);
1360 if (err != AFP_OK) {
1366 /* ---------------------------- */
1367 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1369 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1372 /* ----------------------------
1373 * FIXME need to deal with SIGXFSZ signal
1375 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1377 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1380 /* ---------------------------- */
1381 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1383 struct ofork *ofork;
1385 u_int16_t ofrefnum, bitmap;
1388 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1389 ibuf += sizeof( ofrefnum );
1390 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1391 bitmap = ntohs( bitmap );
1392 ibuf += sizeof( bitmap );
1395 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1396 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1397 return( AFPERR_PARAM );
1400 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1401 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1402 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1403 return( AFPERR_PARAM );
1407 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1408 rbuf + sizeof( u_short ), &buflen ))) {
1412 *rbuflen = buflen + sizeof( u_short );
1413 bitmap = htons( bitmap );
1414 memcpy(rbuf, &bitmap, sizeof( bitmap ));