2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * Copyright (c) 2010 Frank Lahm
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
15 #include <sys/param.h>
16 #include <sys/socket.h>
19 #include <netatalk/at.h>
20 #include <atalk/dsi.h>
21 #include <atalk/atp.h>
22 #include <atalk/asp.h>
23 #include <atalk/afp.h>
24 #include <atalk/adouble.h>
25 #include <atalk/logger.h>
26 #include <atalk/util.h>
27 #include <atalk/cnid.h>
28 #include <atalk/bstradd.h>
33 #include "directory.h"
38 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
44 struct ofork *writtenfork;
47 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
57 /* can only get the length of the opened fork */
58 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
59 && (ofork->of_flags & AFPFORK_RSRC))
61 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
62 && (ofork->of_flags & AFPFORK_DATA))) {
63 return( AFPERR_BITMAP );
66 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
73 dir = dirlookup(vol, ofork->of_did);
75 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
76 return( AFPERR_MISC );
78 path.m_name = of_name(ofork);
81 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
82 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
83 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
84 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
85 /* 0 is for symlink */
86 if (movecwd(vol, dir) < 0)
87 return( AFPERR_NOOBJ );
88 if ( lstat( path.u_name, st ) < 0 )
89 return( AFPERR_NOOBJ );
91 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
92 return( AFPERR_BITMAP );
96 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
99 /* ---------------------------- */
100 static off_t get_off_t(char **ibuf, int is64)
106 memcpy(&temp, *ibuf, sizeof( temp ));
107 ret = ntohl(temp); /* ntohl is unsigned */
108 *ibuf += sizeof(temp);
111 memcpy(&temp, *ibuf, sizeof( temp ));
112 *ibuf += sizeof(temp);
113 ret = ntohl(temp)| (ret << 32);
116 ret = (int)ret; /* sign extend */
121 /* ---------------------- */
122 static int set_off_t(off_t offset, char *rbuf, int is64)
129 temp = htonl(offset >> 32);
130 memcpy(rbuf, &temp, sizeof( temp ));
131 rbuf += sizeof(temp);
132 ret = sizeof( temp );
133 offset &= 0xffffffff;
135 temp = htonl(offset);
136 memcpy(rbuf, &temp, sizeof( temp ));
137 ret += sizeof( temp );
142 /* ------------------------
144 static int is_neg(int is64, off_t val)
146 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
151 static int sum_neg(int is64, off_t offset, off_t reqcount)
153 if (is_neg(is64, offset +reqcount) )
158 /* -------------------------
160 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
162 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
165 /* -------------------------
167 int getforkmode(struct adouble *adp, int eid, int what)
169 return ad_testlock(adp, eid, what);
172 /* -------------------------
174 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
182 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
183 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
186 if ((access & (OPENACC_RD | OPENACC_DRD))) {
187 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
189 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
192 if ((access & OPENACC_RD) && denyreadset) {
196 if ((access & OPENACC_DRD) && readset) {
200 /* boolean logic is not enough, because getforkmode is not always telling the
203 if ((access & OPENACC_RD)) {
204 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
208 if ((access & OPENACC_DRD)) {
209 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
214 /* ------------same for writing -------------- */
215 if ((access & (OPENACC_WR | OPENACC_DWR))) {
216 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
218 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
221 if ((access & OPENACC_WR) && denywriteset) {
225 if ((access & OPENACC_DWR) && writeset) {
229 if ((access & OPENACC_WR)) {
230 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
234 if ((access & OPENACC_DWR)) {
235 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
240 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
241 return ad_excl_lock(adp, eid);
246 /* ----------------------- */
247 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
251 struct ofork *ofork, *opened;
252 struct adouble *adsame = NULL;
254 int ret, adflags, eid;
256 uint16_t vid, bitmap, access, ofrefnum;
257 char fork, *path, *upath;
264 memcpy(&vid, ibuf, sizeof( vid ));
268 if (NULL == ( vol = getvolbyvid( vid ))) {
269 return( AFPERR_PARAM );
272 memcpy(&did, ibuf, sizeof( did ));
273 ibuf += sizeof( int );
275 if (NULL == ( dir = dirlookup( vol, did ))) {
279 memcpy(&bitmap, ibuf, sizeof( bitmap ));
280 bitmap = ntohs( bitmap );
281 ibuf += sizeof( bitmap );
282 memcpy(&access, ibuf, sizeof( access ));
283 access = ntohs( access );
284 ibuf += sizeof( access );
286 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
290 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
291 return get_afp_errno(AFPERR_PARAM);
294 if (*s_path->m_name == '\0') {
296 return AFPERR_BADTYPE;
299 LOG(log_debug, logtype_afpd,
300 "afp_openfork(\"%s\", fork: %s)",
301 abspath(s_path->u_name),
302 (fork & OPENFORK_DATA) ? "d" : "r");
304 /* stat() data fork st is set because it's not a dir */
305 switch ( s_path->st_errno ) {
311 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
313 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
316 /* FIXME should we check it first ? */
317 upath = s_path->u_name;
318 if (!vol_unix_priv(vol)) {
319 if (check_access(upath, access ) < 0) {
320 return AFPERR_ACCESS;
323 if (file_access(s_path, access ) < 0) {
324 return AFPERR_ACCESS;
329 /* XXX: this probably isn't the best way to do this. the already
330 open bits should really be set if the fork is opened by any
331 program, not just this one. however, that's problematic to do
332 if we can't write lock files somewhere. opened is also passed to
333 ad_open so that we can keep file locks together.
334 FIXME: add the fork we are opening?
336 if ((opened = of_findname(s_path))) {
337 adsame = opened->of_ad;
340 if ( fork == OPENFORK_DATA ) {
342 adflags = ADFLAGS_DF | ADFLAGS_HF;
345 adflags = ADFLAGS_RF | ADFLAGS_HF;
348 path = s_path->m_name;
349 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
350 adsame, st)) == NULL ) {
351 return( AFPERR_NFILE );
355 if (access & OPENACC_WR) {
356 /* try opening in read-write mode */
357 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
365 if (fork == OPENFORK_DATA) {
366 /* try to open only the data fork */
367 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
370 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(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 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(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
410 /* see if client asked for a read only data fork */
411 if (fork == OPENFORK_DATA) {
412 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
415 adflags = ADFLAGS_DF;
417 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
418 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
419 * then create in open read-write.
420 * FIXME , it doesn't play well with byte locking example:
421 * ressource fork open read only
422 * locking set on it (no effect, there's no file!)
423 * ressource fork open read write now
432 ret = AFPERR_BADTYPE;
436 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
437 abspath(s_path->m_name), strerror(errno) );
443 /* the ressource fork is open too */
444 ofork->of_flags |= AFPFORK_OPEN;
448 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
449 if (ad_setname(ofork->of_ad, path)) {
450 ad_flush( ofork->of_ad );
454 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
455 &buflen )) != AFP_OK ) {
456 ad_close( ofork->of_ad, adflags );
460 *rbuflen = buflen + 2 * sizeof( u_int16_t );
461 bitmap = htons( bitmap );
462 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
463 rbuf += sizeof( u_int16_t );
465 /* check WriteInhibit bit if we have a ressource fork
466 * the test is done here, after some Mac trafic capture
468 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
469 ad_getattr(ofork->of_ad, &bshort);
470 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
471 ad_close( ofork->of_ad, adflags );
474 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
475 return(AFPERR_OLOCK);
480 * synchronization locks:
483 /* don't try to lock non-existent rforks. */
484 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
486 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
487 /* can we access the fork? */
490 ad_close( ofork->of_ad, adflags );
493 case EAGAIN: /* return data anyway */
497 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
498 return( AFPERR_DENYCONF );
502 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
503 return( AFPERR_PARAM );
506 if ((access & OPENACC_WR))
507 ofork->of_flags |= AFPFORK_ACCWR;
509 /* the file may be open read only without ressource fork */
510 if ((access & OPENACC_RD))
511 ofork->of_flags |= AFPFORK_ACCRD;
513 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
519 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
523 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
527 u_int16_t ofrefnum, bitmap;
535 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
536 ibuf += sizeof( ofrefnum );
538 memcpy(&bitmap, ibuf, sizeof(bitmap));
539 bitmap = ntohs(bitmap);
540 ibuf += sizeof( bitmap );
543 if (NULL == ( ofork = of_find( ofrefnum )) ) {
544 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
545 return( AFPERR_PARAM );
548 if (ofork->of_vol->v_flags & AFPVOL_RO)
551 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
552 return AFPERR_ACCESS;
554 if ( ofork->of_flags & AFPFORK_DATA) {
556 } else if (ofork->of_flags & AFPFORK_RSRC) {
561 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
562 && eid == ADEID_RFORK
564 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
565 && eid == ADEID_DFORK)) {
566 return AFPERR_BITMAP;
570 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
571 if (afp_version >= 30) {
575 return AFPERR_BITMAP;
578 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
579 return AFPERR_PARAM ;
581 size = get_off_t(&ibuf, is64);
584 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
587 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
588 st_size = ad_size(ofork->of_ad, eid);
590 if (st_size > size &&
591 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
592 goto afp_setfork_err;
594 err = ad_dtruncate( ofork->of_ad, size );
596 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
598 goto afp_setfork_err;
599 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
600 ad_refresh( ofork->of_ad );
602 st_size = ad_size(ofork->of_ad, eid);
604 if (st_size > size &&
605 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
606 goto afp_setfork_err;
608 err = ad_rtruncate(ofork->of_ad, size);
610 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
612 goto afp_setfork_err;
614 if (ad_flush( ofork->of_ad ) < 0) {
615 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
619 return AFPERR_BITMAP;
622 if ( flushfork( ofork ) < 0 ) {
623 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
638 return AFPERR_ACCESS;
649 /* for this to work correctly, we need to check for locks before each
650 * read and write. that's most easily handled by always doing an
651 * appropriate check before each ad_read/ad_write. other things
652 * that can change files like truncate are handled internally to those
655 #define ENDBIT(a) ((a) & 0x80)
656 #define UNLOCKBIT(a) ((a) & 0x01)
659 /* ---------------------- */
660 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
663 off_t offset, length;
671 /* figure out parameters */
673 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
675 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
676 ibuf += sizeof(ofrefnum);
678 if (NULL == ( ofork = of_find( ofrefnum )) ) {
679 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
680 return( AFPERR_PARAM );
683 if ( ofork->of_flags & AFPFORK_DATA) {
685 } else if (ofork->of_flags & AFPFORK_RSRC) {
690 offset = get_off_t(&ibuf, is64);
691 length = get_off_t(&ibuf, is64);
693 /* FIXME AD_FILELOCK test is surely wrong */
695 length = BYTELOCK_MAX;
696 else if (!length || is_neg(is64, length)) {
698 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
703 offset += ad_size(ofork->of_ad, eid);
704 /* FIXME what do we do if file size > 2 GB and
705 it's not byte_lock_ext?
708 if (offset < 0) /* error if we have a negative offset */
711 /* if the file is a read-only file, we use read locks instead of
712 * write locks. that way, we can prevent anyone from initiating
714 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
715 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
716 ofork->of_refnum) < 0) {
720 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
726 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
734 *rbuflen = set_off_t (offset, rbuf, is64);
738 /* --------------------------- */
739 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
741 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
744 /* --------------------------- */
745 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
747 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
752 /* --------------------------- */
753 static int crlf(struct ofork *of)
757 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
758 /* no resource fork or no finderinfo, use our files extension mapping */
759 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
762 /* file type is TEXT */
765 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
772 static ssize_t read_file(struct ofork *ofork, int eid,
773 off_t offset, u_char nlmask,
774 u_char nlchar, char *rbuf,
775 size_t *rbuflen, const int xlate)
781 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
783 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
785 return( AFPERR_PARAM );
787 if ( (size_t)cc < *rbuflen ) {
795 for ( p = rbuf, q = p + cc; p < q; ) {
796 if (( *p++ & nlmask ) == nlchar ) {
807 * If this file is of type TEXT, then swap \012 to \015.
810 for ( p = rbuf, q = p + cc; p < q; p++ ) {
811 if ( *p == '\012' ) {
813 } else if ( *p == '\015' ) {
822 return( AFPERR_EOF );
827 /* -----------------------------
828 * with ddp, afp_read can return fewer bytes than in reqcount
829 * so return EOF only if read actually past end of file not
830 * if offset +reqcount > size of file
832 * getfork size ==> 10430
833 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
834 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
835 * read fork offset 9248 size 1508 ==> 1182 (EOF)
836 * 10752 is a bug in Mac 7.5.x finder
838 * with dsi, should we check that reqcount < server quantum?
840 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
843 off_t offset, saveoff, reqcount, savereqcount;
847 u_char nlmask, nlchar;
850 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
851 ibuf += sizeof( u_short );
853 if (NULL == ( ofork = of_find( ofrefnum )) ) {
854 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
859 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
863 offset = get_off_t(&ibuf, is64);
864 reqcount = get_off_t(&ibuf, is64);
866 LOG(log_debug, logtype_afpd,
867 "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
868 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
869 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
878 /* if we wanted to be picky, we could add in the following
879 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
881 if (reqcount < 0 || offset < 0) {
886 if ( ofork->of_flags & AFPFORK_DATA) {
888 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
889 } else if (ofork->of_flags & AFPFORK_RSRC) {
891 } else { /* fork wasn't opened. this should never really happen. */
896 /* zero request count */
902 savereqcount = reqcount;
904 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
909 #define min(a,b) ((a)<(b)?(a):(b))
910 *rbuflen = min( reqcount, *rbuflen );
911 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
915 /* dsi can stream requests. we can only do this if we're not checking
916 * for an end-of-line character. oh well. */
917 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
918 DSI *dsi = obj->handle;
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. */
942 if (!(xlate || Debug(obj) )) {
945 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
946 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
947 if (errno == EINVAL || errno == ENOSYS)
950 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
962 /* fill up our buffer. */
963 while (*rbuflen > 0) {
964 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
970 if (obj->options.flags & OPTION_DEBUG) {
971 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
972 bprint(rbuf, *rbuflen);
975 /* dsi_read() also returns buffer size of next allocation */
976 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
985 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
987 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
988 obj->exit(EXITERR_CLNT);
992 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1000 /* ---------------------- */
1001 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1003 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1006 /* ---------------------- */
1007 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1009 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1012 /* ---------------------- */
1013 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1021 memcpy(&vid, ibuf, sizeof(vid));
1022 if (NULL == ( vol = getvolbyvid( vid )) ) {
1023 return( AFPERR_PARAM );
1030 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1032 struct ofork *ofork;
1037 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1039 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1040 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1041 return( AFPERR_PARAM );
1044 LOG(log_debug, logtype_afpd,
1045 "afp_flushfork(\"%s\", fork: %s)",
1046 cfrombstr(ofork->of_ad->ad_fullpath),
1047 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1049 if ( flushfork( ofork ) < 0 ) {
1050 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1058 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1059 fsync(2) on OSX is implemented differently than on other platforms.
1060 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1062 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1064 struct ofork *ofork;
1070 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1071 ibuf += sizeof( ofrefnum );
1073 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1074 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1075 return( AFPERR_PARAM );
1078 LOG(log_debug, logtype_afpd,
1079 "afp_syncfork(\"%s\", fork: %s)",
1080 cfrombstr(ofork->of_ad->ad_fullpath),
1081 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1083 if ( flushfork( ofork ) < 0 ) {
1084 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1091 /* this is very similar to closefork */
1092 int flushfork(struct ofork *ofork)
1096 int err = 0, doflush = 0;
1098 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1099 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1100 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1101 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1105 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1106 (ofork->of_flags & AFPFORK_RSRC)) {
1108 /* read in the rfork length */
1109 ad_refresh(ofork->of_ad);
1111 /* set the date if we're dirty */
1112 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1113 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1114 ofork->of_flags &= ~AFPFORK_DIRTY;
1118 /* flush the header */
1119 if (doflush && ad_flush(ofork->of_ad) < 0)
1122 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1126 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1127 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1133 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1135 struct ofork *ofork;
1140 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1142 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1143 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1144 return( AFPERR_PARAM );
1147 LOG(log_debug, logtype_afpd,
1148 "afp_closefork(\"%s\", fork: %s)",
1149 cfrombstr(ofork->of_ad->ad_fullpath),
1150 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1152 if ( of_closefork( ofork ) < 0 ) {
1153 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1154 return( AFPERR_PARAM );
1161 static ssize_t write_file(struct ofork *ofork, int eid,
1162 off_t offset, char *rbuf,
1163 size_t rbuflen, const int xlate)
1169 * If this file is of type TEXT, swap \015 to \012.
1172 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1173 if ( *p == '\015' ) {
1175 } else if ( *p == '\012' ) {
1181 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1182 rbuf, rbuflen)) < 0 ) {
1187 return( AFPERR_DFULL );
1189 return AFPERR_ACCESS;
1191 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1192 return( AFPERR_PARAM );
1200 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1201 * the client may have sent us a bunch of data that's not reflected
1202 * in reqcount et al. */
1203 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1205 struct ofork *ofork;
1206 off_t offset, saveoff, reqcount;
1207 int endflag, eid, xlate = 0, err = AFP_OK;
1211 /* figure out parameters */
1213 endflag = ENDBIT(*ibuf);
1215 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1216 ibuf += sizeof( ofrefnum );
1218 offset = get_off_t(&ibuf, is64);
1219 reqcount = get_off_t(&ibuf, is64);
1221 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1222 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1227 LOG(log_debug, logtype_afpd,
1228 "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1229 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
1230 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1232 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1233 err = AFPERR_ACCESS;
1238 writtenfork = ofork;
1241 if ( ofork->of_flags & AFPFORK_DATA) {
1243 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1244 } else if (ofork->of_flags & AFPFORK_RSRC) {
1247 err = AFPERR_ACCESS; /* should never happen */
1252 offset += ad_size(ofork->of_ad, eid);
1254 /* handle bogus parameters */
1255 if (reqcount < 0 || offset < 0) {
1260 /* offset can overflow on 64-bit capable filesystems.
1261 * report disk full if that's going to happen. */
1262 if (sum_neg(is64, offset, reqcount)) {
1267 if (!reqcount) { /* handle request counts of 0 */
1269 *rbuflen = set_off_t (offset, rbuf, is64);
1274 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1275 reqcount, ofork->of_refnum) < 0) {
1280 /* this is yucky, but dsi can stream i/o and asp can't */
1281 switch (obj->proto) {
1284 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1286 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1287 return( AFPERR_PARAM );
1291 if (obj->options.flags & OPTION_DEBUG) {
1292 printf("(write) len: %d\n", *rbuflen);
1293 bprint(rbuf, *rbuflen);
1296 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1299 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1304 #endif /* no afp/asp */
1308 DSI *dsi = obj->handle;
1310 /* find out what we have already and write it out. */
1311 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1312 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1313 dsi_writeflush(dsi);
1315 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1320 #if 0 /*def HAVE_SENDFILE_WRITE*/
1321 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1322 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1323 offset, dsi->datasize)) < 0) {
1331 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1332 goto afp_write_loop;
1334 dsi_writeflush(dsi);
1336 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1337 reqcount, ofork->of_refnum);
1342 goto afp_write_done;
1344 #endif /* 0, was HAVE_SENDFILE_WRITE */
1346 /* loop until everything gets written. currently
1347 * dsi_write handles the end case by itself. */
1348 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1349 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1350 dsi_writeflush(dsi);
1352 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1353 reqcount, ofork->of_refnum);
1362 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1363 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1364 ofork->of_flags |= AFPFORK_DIRTY;
1366 *rbuflen = set_off_t (offset, rbuf, is64);
1370 if (obj->proto == AFPPROTO_DSI) {
1371 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1372 dsi_writeflush(obj->handle);
1374 if (err != AFP_OK) {
1380 /* ---------------------------- */
1381 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1383 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1386 /* ----------------------------
1387 * FIXME need to deal with SIGXFSZ signal
1389 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1391 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1394 /* ---------------------------- */
1395 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1397 struct ofork *ofork;
1399 u_int16_t ofrefnum, bitmap;
1402 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1403 ibuf += sizeof( ofrefnum );
1404 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1405 bitmap = ntohs( bitmap );
1406 ibuf += sizeof( bitmap );
1409 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1410 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1411 return( AFPERR_PARAM );
1414 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1415 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1416 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1417 return( AFPERR_PARAM );
1421 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1422 rbuf + sizeof( u_short ), &buflen ))) {
1426 *rbuflen = buflen + sizeof( u_short );
1427 bitmap = htons( bitmap );
1428 memcpy(rbuf, &bitmap, sizeof( bitmap ));