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 <atalk/dsi.h>
20 #include <atalk/afp.h>
21 #include <atalk/adouble.h>
22 #include <atalk/logger.h>
23 #include <atalk/util.h>
24 #include <atalk/cnid.h>
25 #include <atalk/bstradd.h>
26 #include <atalk/globals.h>
30 #include "directory.h"
35 struct ofork *writtenfork;
38 static int getforkparams(struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen)
48 /* can only get the length of the opened fork */
49 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
50 && (ofork->of_flags & AFPFORK_RSRC))
52 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
53 && (ofork->of_flags & AFPFORK_DATA))) {
54 return( AFPERR_BITMAP );
57 if (! AD_META_OPEN(ofork->of_ad)) {
64 dir = dirlookup(vol, ofork->of_did);
66 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
67 return( AFPERR_MISC );
69 path.m_name = of_name(ofork);
72 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
73 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
74 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
75 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
76 /* 0 is for symlink */
77 if (movecwd(vol, dir) < 0)
78 return( AFPERR_NOOBJ );
79 if ( lstat( path.u_name, st ) < 0 )
80 return( AFPERR_NOOBJ );
82 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
83 return( AFPERR_BITMAP );
87 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
90 static off_t get_off_t(char **ibuf, int is64)
96 memcpy(&temp, *ibuf, sizeof( temp ));
97 ret = ntohl(temp); /* ntohl is unsigned */
98 *ibuf += sizeof(temp);
101 memcpy(&temp, *ibuf, sizeof( temp ));
102 *ibuf += sizeof(temp);
103 ret = ntohl(temp)| (ret << 32);
106 ret = (int)ret; /* sign extend */
111 static int set_off_t(off_t offset, char *rbuf, int is64)
118 temp = htonl(offset >> 32);
119 memcpy(rbuf, &temp, sizeof( temp ));
120 rbuf += sizeof(temp);
121 ret = sizeof( temp );
122 offset &= 0xffffffff;
124 temp = htonl(offset);
125 memcpy(rbuf, &temp, sizeof( temp ));
126 ret += sizeof( temp );
131 static int is_neg(int is64, off_t val)
133 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
138 static int sum_neg(int is64, off_t offset, off_t reqcount)
140 if (is_neg(is64, offset +reqcount) )
145 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
153 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
154 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
157 if ((access & (OPENACC_RD | OPENACC_DRD))) {
158 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
160 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
163 if ((access & OPENACC_RD) && denyreadset) {
167 if ((access & OPENACC_DRD) && readset) {
171 /* boolean logic is not enough, because getforkmode is not always telling the
174 if ((access & OPENACC_RD)) {
175 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
179 if ((access & OPENACC_DRD)) {
180 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
185 /* ------------same for writing -------------- */
186 if ((access & (OPENACC_WR | OPENACC_DWR))) {
187 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
189 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
192 if ((access & OPENACC_WR) && denywriteset) {
196 if ((access & OPENACC_DWR) && writeset) {
200 if ((access & OPENACC_WR)) {
201 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
205 if ((access & OPENACC_DWR)) {
206 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
215 /* ----------------------- */
216 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
220 struct ofork *ofork, *opened;
221 struct adouble *adsame = NULL;
223 int ret, adflags, eid;
225 uint16_t vid, bitmap, access, ofrefnum;
226 char fork, *path, *upath;
234 memcpy(&vid, ibuf, sizeof( vid ));
238 if (NULL == ( vol = getvolbyvid( vid ))) {
239 return( AFPERR_PARAM );
242 memcpy(&did, ibuf, sizeof( did ));
243 ibuf += sizeof( int );
245 if (NULL == ( dir = dirlookup( vol, did ))) {
249 memcpy(&bitmap, ibuf, sizeof( bitmap ));
250 bitmap = ntohs( bitmap );
251 ibuf += sizeof( bitmap );
252 memcpy(&access, ibuf, sizeof( access ));
253 access = ntohs( access );
254 ibuf += sizeof( access );
256 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
260 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
261 return get_afp_errno(AFPERR_PARAM);
264 if (*s_path->m_name == '\0') {
266 return AFPERR_BADTYPE;
269 /* stat() data fork st is set because it's not a dir */
270 switch ( s_path->st_errno ) {
276 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
278 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
281 /* FIXME should we check it first ? */
282 upath = s_path->u_name;
283 if (!vol_unix_priv(vol)) {
284 if (check_access(upath, access ) < 0) {
285 return AFPERR_ACCESS;
288 if (file_access(s_path, access ) < 0) {
289 return AFPERR_ACCESS;
294 /* XXX: this probably isn't the best way to do this. the already
295 open bits should really be set if the fork is opened by any
296 program, not just this one. however, that's problematic to do
297 if we can't write lock files somewhere. opened is also passed to
298 ad_open so that we can keep file locks together.
299 FIXME: add the fork we are opening?
301 if ((opened = of_findname(s_path))) {
302 adsame = opened->of_ad;
305 if ( fork == OPENFORK_DATA ) {
307 adflags = ADFLAGS_DF | ADFLAGS_HF ;
310 adflags = ADFLAGS_RF | ADFLAGS_HF;
311 if (!(access & OPENACC_WR))
312 adflags |= ADFLAGS_NORF;
315 path = s_path->m_name;
316 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
317 adsame, st)) == NULL ) {
318 return( AFPERR_NFILE );
321 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
322 fullpathname(s_path->u_name),
323 (fork & OPENFORK_RSCS) ? "data" : "reso",
324 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
327 if (access & OPENACC_WR) {
328 /* try opening in read-write mode */
329 if (ad_open(ofork->of_ad, upath,
330 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
337 if (fork == OPENFORK_DATA) {
338 /* try to open only the data fork */
339 if (ad_open(ofork->of_ad, upath,
340 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
343 adflags = ADFLAGS_DF;
345 /* here's the deal. we only try to create the resource
346 * fork if the user wants to open it for write acess. */
347 if (ad_open(ofork->of_ad, upath,
348 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
350 ofork->of_flags |= AFPFORK_META;
358 ret = AFPERR_BADTYPE;
361 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
367 /* the ressource fork is open too */
368 ofork->of_flags |= AFPFORK_META;
371 /* try opening in read-only mode */
373 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
381 /* see if client asked for a read only data fork */
382 if (fork == OPENFORK_DATA) {
383 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
386 adflags = ADFLAGS_DF;
388 /* else we don't set AFPFORK_META because there's no ressource fork file
389 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
390 * then create in open read-write.
391 * FIXME , it doesn't play well with byte locking example:
392 * ressource fork open read only
393 * locking set on it (no effect, there's no file!)
394 * ressource fork open read write now
402 ret = AFPERR_BADTYPE;
405 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
406 fullpathname(s_path->m_name), strerror(errno) );
410 ofork->of_flags |= AFPFORK_META;
414 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
415 if (ad_setname(ofork->of_ad, path)) {
416 ad_flush( ofork->of_ad );
420 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
421 ad_close( ofork->of_ad, adflags );
425 *rbuflen = buflen + 2 * sizeof( uint16_t );
426 bitmap = htons( bitmap );
427 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
428 rbuf += sizeof( uint16_t );
430 /* check WriteInhibit bit if we have a ressource fork
431 * the test is done here, after some Mac trafic capture
433 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
434 ad_getattr(ofork->of_ad, &bshort);
435 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
436 ad_close( ofork->of_ad, adflags );
439 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
440 return(AFPERR_OLOCK);
445 * synchronization locks:
448 /* don't try to lock non-existent rforks. */
449 if ((eid == ADEID_DFORK)
450 || (ad_reso_fileno(ofork->of_ad) != -1)
451 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
452 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
453 /* can we access the fork? */
456 ad_close( ofork->of_ad, adflags );
459 case EAGAIN: /* return data anyway */
463 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
464 return( AFPERR_DENYCONF );
468 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
469 return( AFPERR_PARAM );
472 if ((access & OPENACC_WR))
473 ofork->of_flags |= AFPFORK_ACCWR;
475 /* the file may be open read only without ressource fork */
476 if ((access & OPENACC_RD))
477 ofork->of_flags |= AFPFORK_ACCRD;
479 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
485 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
489 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
493 uint16_t ofrefnum, bitmap;
501 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
502 ibuf += sizeof( ofrefnum );
504 memcpy(&bitmap, ibuf, sizeof(bitmap));
505 bitmap = ntohs(bitmap);
506 ibuf += sizeof( bitmap );
509 if (NULL == ( ofork = of_find( ofrefnum )) ) {
510 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
511 return( AFPERR_PARAM );
514 if (ofork->of_vol->v_flags & AFPVOL_RO)
517 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
518 return AFPERR_ACCESS;
520 if ( ofork->of_flags & AFPFORK_DATA) {
522 } else if (ofork->of_flags & AFPFORK_RSRC) {
527 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
528 && eid == ADEID_RFORK
530 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
531 && eid == ADEID_DFORK)) {
532 return AFPERR_BITMAP;
536 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
537 if (afp_version >= 30) {
541 return AFPERR_BITMAP;
544 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
545 return AFPERR_PARAM ;
547 size = get_off_t(&ibuf, is64);
550 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
553 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
554 st_size = ad_size(ofork->of_ad, eid);
556 if (st_size > size &&
557 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
558 goto afp_setfork_err;
560 err = ad_dtruncate( ofork->of_ad, size );
562 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
564 goto afp_setfork_err;
565 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
566 ad_refresh(NULL, ofork->of_ad );
568 st_size = ad_size(ofork->of_ad, eid);
570 if (st_size > size &&
571 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
572 goto afp_setfork_err;
574 err = ad_rtruncate(ofork->of_ad, size);
576 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
578 goto afp_setfork_err;
580 if (ad_flush( ofork->of_ad ) < 0) {
581 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
585 return AFPERR_BITMAP;
588 if ( flushfork( ofork ) < 0 ) {
589 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
604 return AFPERR_ACCESS;
615 /* for this to work correctly, we need to check for locks before each
616 * read and write. that's most easily handled by always doing an
617 * appropriate check before each ad_read/ad_write. other things
618 * that can change files like truncate are handled internally to those
621 #define ENDBIT(a) ((a) & 0x80)
622 #define UNLOCKBIT(a) ((a) & 0x01)
625 /* ---------------------- */
626 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
629 off_t offset, length;
637 /* figure out parameters */
639 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
641 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
642 ibuf += sizeof(ofrefnum);
644 if (NULL == ( ofork = of_find( ofrefnum )) ) {
645 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
646 return( AFPERR_PARAM );
649 if ( ofork->of_flags & AFPFORK_DATA) {
651 } else if (ofork->of_flags & AFPFORK_RSRC) {
656 offset = get_off_t(&ibuf, is64);
657 length = get_off_t(&ibuf, is64);
660 length = BYTELOCK_MAX;
661 else if (!length || is_neg(is64, length)) {
663 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
668 offset += ad_size(ofork->of_ad, eid);
669 /* FIXME what do we do if file size > 2 GB and
670 it's not byte_lock_ext?
673 if (offset < 0) /* error if we have a negative offset */
676 /* if the file is a read-only file, we use read locks instead of
677 * write locks. that way, we can prevent anyone from initiating
679 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
680 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
681 ofork->of_refnum) < 0) {
685 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
691 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
699 *rbuflen = set_off_t (offset, rbuf, is64);
703 /* --------------------------- */
704 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
706 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
709 /* --------------------------- */
710 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
712 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
717 /* --------------------------- */
718 static int crlf(struct ofork *of)
722 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
723 /* no resource fork or no finderinfo, use our files extension mapping */
724 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
727 /* file type is TEXT */
730 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
737 static ssize_t read_file(struct ofork *ofork, int eid,
738 off_t offset, u_char nlmask,
739 u_char nlchar, char *rbuf,
740 size_t *rbuflen, const int xlate)
746 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
748 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
750 return( AFPERR_PARAM );
752 if ( (size_t)cc < *rbuflen ) {
760 for ( p = rbuf, q = p + cc; p < q; ) {
761 if (( *p++ & nlmask ) == nlchar ) {
772 * If this file is of type TEXT, then swap \012 to \015.
775 for ( p = rbuf, q = p + cc; p < q; p++ ) {
776 if ( *p == '\012' ) {
778 } else if ( *p == '\015' ) {
787 return( AFPERR_EOF );
792 /* -----------------------------
793 * with ddp, afp_read can return fewer bytes than in reqcount
794 * so return EOF only if read actually past end of file not
795 * if offset +reqcount > size of file
797 * getfork size ==> 10430
798 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
799 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
800 * read fork offset 9248 size 1508 ==> 1182 (EOF)
801 * 10752 is a bug in Mac 7.5.x finder
803 * with dsi, should we check that reqcount < server quantum?
805 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
808 off_t offset, saveoff, reqcount, savereqcount;
812 u_char nlmask, nlchar;
815 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
816 ibuf += sizeof( u_short );
818 if (NULL == ( ofork = of_find( ofrefnum )) ) {
819 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
824 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
828 offset = get_off_t(&ibuf, is64);
829 reqcount = get_off_t(&ibuf, is64);
831 LOG(log_debug, logtype_afpd,
832 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
833 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
842 /* if we wanted to be picky, we could add in the following
843 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
845 if (reqcount < 0 || offset < 0) {
850 if ( ofork->of_flags & AFPFORK_DATA) {
852 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
853 } else if (ofork->of_flags & AFPFORK_RSRC) {
855 } else { /* fork wasn't opened. this should never really happen. */
860 /* zero request count */
866 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
867 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
869 savereqcount = reqcount;
871 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
876 *rbuflen = MIN(reqcount, *rbuflen);
877 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
878 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
880 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
883 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
884 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
886 /* dsi can stream requests. we can only do this if we're not checking
887 * for an end-of-line character. oh well. */
888 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
889 DSI *dsi = obj->handle;
892 /* reqcount isn't always truthful. we need to deal with that. */
893 size = ad_size(ofork->of_ad, eid);
895 /* subtract off the offset */
897 if (reqcount > size) {
904 /* dsi_readinit() returns size of next read buffer. by this point,
905 * we know that we're sending some data. if we fail, something
906 * horrible happened. */
907 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
910 /* due to the nature of afp packets, we have to exit if we get
911 an error. we can't do this with translation on. */
916 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
918 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
919 if (errno == EINVAL || errno == ENOSYS)
922 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
934 /* fill up our buffer. */
935 while (*rbuflen > 0) {
936 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
941 /* dsi_read() also returns buffer size of next allocation */
942 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
951 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
953 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
954 obj->exit(EXITERR_CLNT);
958 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
966 /* ---------------------- */
967 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
969 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
972 /* ---------------------- */
973 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
975 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
978 /* ---------------------- */
979 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
987 memcpy(&vid, ibuf, sizeof(vid));
988 if (NULL == ( vol = getvolbyvid( vid )) ) {
989 return( AFPERR_PARAM );
996 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1003 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1005 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1006 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1007 return( AFPERR_PARAM );
1010 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
1011 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1013 if ( flushfork( ofork ) < 0 ) {
1014 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1022 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1023 fsync(2) on OSX is implemented differently than on other platforms.
1024 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1026 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1028 struct ofork *ofork;
1034 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1035 ibuf += sizeof( ofrefnum );
1037 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1038 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1039 return( AFPERR_PARAM );
1042 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1043 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1045 if ( flushfork( ofork ) < 0 ) {
1046 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1053 /* this is very similar to closefork */
1054 int flushfork(struct ofork *ofork)
1058 int err = 0, doflush = 0;
1060 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1061 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1062 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1063 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1067 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1068 (ofork->of_flags & AFPFORK_RSRC)) {
1070 /* read in the rfork length */
1071 ad_refresh(NULL, ofork->of_ad);
1073 /* set the date if we're dirty */
1074 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1075 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1076 ofork->of_flags &= ~AFPFORK_DIRTY;
1080 /* flush the header */
1081 if (doflush && ad_flush(ofork->of_ad) < 0)
1084 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1088 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1089 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1095 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1097 struct ofork *ofork;
1102 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1104 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1105 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1106 return( AFPERR_PARAM );
1109 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1110 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1112 if ( of_closefork( ofork ) < 0 ) {
1113 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1114 return( AFPERR_PARAM );
1121 static ssize_t write_file(struct ofork *ofork, int eid,
1122 off_t offset, char *rbuf,
1123 size_t rbuflen, const int xlate)
1129 * If this file is of type TEXT, swap \015 to \012.
1132 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1133 if ( *p == '\015' ) {
1135 } else if ( *p == '\012' ) {
1141 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1142 (uintmax_t)offset, rbuflen);
1144 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1145 rbuf, rbuflen)) < 0 ) {
1150 return( AFPERR_DFULL );
1152 return AFPERR_ACCESS;
1154 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1155 return( AFPERR_PARAM );
1163 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1164 * the client may have sent us a bunch of data that's not reflected
1165 * in reqcount et al. */
1166 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1168 struct ofork *ofork;
1169 off_t offset, saveoff, reqcount, oldsize, newsize;
1170 int endflag, eid, xlate = 0, err = AFP_OK;
1174 /* figure out parameters */
1176 endflag = ENDBIT(*ibuf);
1178 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1179 ibuf += sizeof( ofrefnum );
1181 offset = get_off_t(&ibuf, is64);
1182 reqcount = get_off_t(&ibuf, is64);
1184 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1185 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1190 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1191 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1193 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1194 err = AFPERR_ACCESS;
1199 writtenfork = ofork;
1202 if ( ofork->of_flags & AFPFORK_DATA) {
1204 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1205 } else if (ofork->of_flags & AFPFORK_RSRC) {
1208 err = AFPERR_ACCESS; /* should never happen */
1212 oldsize = ad_size(ofork->of_ad, eid);
1216 /* handle bogus parameters */
1217 if (reqcount < 0 || offset < 0) {
1222 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1224 /* offset can overflow on 64-bit capable filesystems.
1225 * report disk full if that's going to happen. */
1226 if (sum_neg(is64, offset, reqcount)) {
1231 if (!reqcount) { /* handle request counts of 0 */
1233 *rbuflen = set_off_t (offset, rbuf, is64);
1238 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1239 reqcount, ofork->of_refnum) < 0) {
1244 /* this is yucky, but dsi can stream i/o and asp can't */
1245 switch (obj->proto) {
1248 DSI *dsi = obj->handle;
1249 /* find out what we have already and write it out. */
1250 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1252 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1253 dsi_writeflush(dsi);
1255 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1261 #if 0 /*def HAVE_SENDFILE_WRITE*/
1262 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1263 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1264 offset, dsi->datasize)) < 0) {
1272 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1273 goto afp_write_loop;
1275 dsi_writeflush(dsi);
1277 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1278 reqcount, ofork->of_refnum);
1283 goto afp_write_done;
1285 #endif /* 0, was HAVE_SENDFILE_WRITE */
1287 /* loop until everything gets written. currently
1288 * dsi_write handles the end case by itself. */
1289 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1290 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1291 dsi_writeflush(dsi);
1293 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1294 reqcount, ofork->of_refnum);
1303 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1304 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1305 ofork->of_flags |= AFPFORK_DIRTY;
1307 /* we have modified any fork, remember until close_fork */
1308 ofork->of_flags |= AFPFORK_MODIFIED;
1310 /* update write count */
1311 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1313 *rbuflen = set_off_t (offset, rbuf, is64);
1317 if (obj->proto == AFPPROTO_DSI) {
1318 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1319 dsi_writeflush(obj->handle);
1321 if (err != AFP_OK) {
1327 /* ---------------------------- */
1328 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1330 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1333 /* ----------------------------
1334 * FIXME need to deal with SIGXFSZ signal
1336 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1338 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1341 /* ---------------------------- */
1342 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1344 struct ofork *ofork;
1346 uint16_t ofrefnum, bitmap;
1349 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1350 ibuf += sizeof( ofrefnum );
1351 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1352 bitmap = ntohs( bitmap );
1353 ibuf += sizeof( bitmap );
1356 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1357 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1358 return( AFPERR_PARAM );
1361 if (AD_META_OPEN(ofork->of_ad)) {
1362 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1363 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1364 return( AFPERR_PARAM );
1368 if (AFP_OK != (ret = getforkparams(ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1372 *rbuflen = buflen + sizeof( u_short );
1373 bitmap = htons( bitmap );
1374 memcpy(rbuf, &bitmap, sizeof( bitmap ));