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, 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/%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;
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 /* we have modified any fork, remember until close_fork */
1340 ofork->of_flags |= AFPFORK_MODIFIED;
1342 /* update write count */
1343 ofork->of_vol->v_written += reqcount;
1345 *rbuflen = set_off_t (offset, rbuf, is64);
1349 if (obj->proto == AFPPROTO_DSI) {
1350 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1351 dsi_writeflush(obj->handle);
1353 if (err != AFP_OK) {
1359 /* ---------------------------- */
1360 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1362 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1365 /* ----------------------------
1366 * FIXME need to deal with SIGXFSZ signal
1368 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1370 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1373 /* ---------------------------- */
1374 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1376 struct ofork *ofork;
1378 u_int16_t ofrefnum, bitmap;
1381 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1382 ibuf += sizeof( ofrefnum );
1383 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1384 bitmap = ntohs( bitmap );
1385 ibuf += sizeof( bitmap );
1388 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1389 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1390 return( AFPERR_PARAM );
1393 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1394 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1395 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1396 return( AFPERR_PARAM );
1400 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1401 rbuf + sizeof( u_short ), &buflen ))) {
1405 *rbuflen = buflen + sizeof( u_short );
1406 bitmap = htons( bitmap );
1407 memcpy(rbuf, &bitmap, sizeof( bitmap ));