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>
27 #include <atalk/netatalk_conf.h>
32 #include "directory.h"
37 struct ofork *writtenfork;
40 static int getforkparams(const AFPObj *obj, struct ofork *ofork, uint16_t bitmap, char *buf, size_t *buflen)
50 /* can only get the length of the opened fork */
51 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
52 && (ofork->of_flags & AFPFORK_RSRC))
54 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
55 && (ofork->of_flags & AFPFORK_DATA))) {
56 return( AFPERR_BITMAP );
59 if (! AD_META_OPEN(ofork->of_ad)) {
66 dir = dirlookup(vol, ofork->of_did);
68 if (NULL == (path.m_name = utompath(vol, of_name(ofork), dir->d_did, utf8_encoding(obj)))) {
69 return( AFPERR_MISC );
71 path.u_name = of_name(ofork);
74 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
75 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
76 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
77 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
78 /* 0 is for symlink */
79 if (movecwd(vol, dir) < 0)
80 return( AFPERR_NOOBJ );
81 if ( lstat( path.u_name, st ) < 0 )
82 return( AFPERR_NOOBJ );
84 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
85 return( AFPERR_BITMAP );
89 return getmetadata(obj, vol, bitmap, &path, dir, buf, buflen, adp );
92 static off_t get_off_t(char **ibuf, int is64)
98 memcpy(&temp, *ibuf, sizeof( temp ));
99 ret = ntohl(temp); /* ntohl is unsigned */
100 *ibuf += sizeof(temp);
103 memcpy(&temp, *ibuf, sizeof( temp ));
104 *ibuf += sizeof(temp);
105 ret = ntohl(temp)| (ret << 32);
108 ret = (int)ret; /* sign extend */
113 static int set_off_t(off_t offset, char *rbuf, int is64)
120 temp = htonl(offset >> 32);
121 memcpy(rbuf, &temp, sizeof( temp ));
122 rbuf += sizeof(temp);
123 ret = sizeof( temp );
124 offset &= 0xffffffff;
126 temp = htonl(offset);
127 memcpy(rbuf, &temp, sizeof( temp ));
128 ret += sizeof( temp );
133 static int is_neg(int is64, off_t val)
135 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
140 static int sum_neg(int is64, off_t offset, off_t reqcount)
142 if (is_neg(is64, offset +reqcount) )
147 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
155 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
156 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
159 if ((access & (OPENACC_RD | OPENACC_DRD))) {
160 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
162 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
165 if ((access & OPENACC_RD) && denyreadset) {
169 if ((access & OPENACC_DRD) && readset) {
173 /* boolean logic is not enough, because getforkmode is not always telling the
176 if ((access & OPENACC_RD)) {
177 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
181 if ((access & OPENACC_DRD)) {
182 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
187 /* ------------same for writing -------------- */
188 if ((access & (OPENACC_WR | OPENACC_DWR))) {
189 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
191 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
194 if ((access & OPENACC_WR) && denywriteset) {
198 if ((access & OPENACC_DWR) && writeset) {
202 if ((access & OPENACC_WR)) {
203 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
207 if ((access & OPENACC_DWR)) {
208 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
217 /* ----------------------- */
218 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
222 struct ofork *ofork, *opened;
223 struct adouble *adsame = NULL;
225 int ret, adflags, eid;
227 uint16_t vid, bitmap, access, ofrefnum;
228 char fork, *path, *upath;
236 memcpy(&vid, ibuf, sizeof( vid ));
240 if (NULL == ( vol = getvolbyvid( vid ))) {
241 return( AFPERR_PARAM );
244 memcpy(&did, ibuf, sizeof( did ));
245 ibuf += sizeof( int );
247 if (NULL == ( dir = dirlookup( vol, did ))) {
251 memcpy(&bitmap, ibuf, sizeof( bitmap ));
252 bitmap = ntohs( bitmap );
253 ibuf += sizeof( bitmap );
254 memcpy(&access, ibuf, sizeof( access ));
255 access = ntohs( access );
256 ibuf += sizeof( access );
258 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
262 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
263 return get_afp_errno(AFPERR_PARAM);
266 if (*s_path->m_name == '\0') {
268 return AFPERR_BADTYPE;
271 /* stat() data fork st is set because it's not a dir */
272 switch ( s_path->st_errno ) {
278 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
280 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
283 /* FIXME should we check it first ? */
284 upath = s_path->u_name;
285 if (!vol_unix_priv(vol)) {
286 if (check_access(obj, vol, upath, access ) < 0) {
287 return AFPERR_ACCESS;
290 if (file_access(obj, vol, s_path, access ) < 0) {
291 return AFPERR_ACCESS;
296 /* XXX: this probably isn't the best way to do this. the already
297 open bits should really be set if the fork is opened by any
298 program, not just this one. however, that's problematic to do
299 if we can't write lock files somewhere. opened is also passed to
300 ad_open so that we can keep file locks together.
301 FIXME: add the fork we are opening?
303 if ((opened = of_findname(s_path))) {
304 adsame = opened->of_ad;
307 if ( fork == OPENFORK_DATA ) {
309 adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF;
312 adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF;
313 if (!(access & OPENACC_WR))
314 adflags |= ADFLAGS_NORF;
317 path = s_path->m_name;
318 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
319 adsame, st)) == NULL ) {
320 return( AFPERR_NFILE );
323 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
324 fullpathname(s_path->u_name),
325 (fork == OPENFORK_DATA) ? "data" : "reso",
326 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
329 if (access & OPENACC_WR) {
330 /* try opening in read-write mode */
331 if (ad_open(ofork->of_ad, upath,
332 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
339 if (fork == OPENFORK_DATA) {
340 /* try to open only the data fork */
341 if (ad_open(ofork->of_ad, upath,
342 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
345 adflags = ADFLAGS_DF;
347 /* here's the deal. we only try to create the resource
348 * fork if the user wants to open it for write acess. */
349 if (ad_open(ofork->of_ad, upath,
350 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
352 ofork->of_flags |= AFPFORK_META;
360 ret = AFPERR_BADTYPE;
363 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
369 /* the ressource fork is open too */
370 ofork->of_flags |= AFPFORK_META;
373 /* try opening in read-only mode */
375 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
383 /* see if client asked for a read only data fork */
384 if (fork == OPENFORK_DATA) {
385 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
388 adflags = ADFLAGS_DF;
390 /* else we don't set AFPFORK_META because there's no ressource fork file
391 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
392 * then create in open read-write.
393 * FIXME , it doesn't play well with byte locking example:
394 * ressource fork open read only
395 * locking set on it (no effect, there's no file!)
396 * ressource fork open read write now
404 ret = AFPERR_BADTYPE;
407 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
408 fullpathname(s_path->m_name), strerror(errno) );
412 ofork->of_flags |= AFPFORK_META;
416 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
417 if (ad_setname(ofork->of_ad, path)) {
418 ad_flush( ofork->of_ad );
422 if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
423 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
427 *rbuflen = buflen + 2 * sizeof( uint16_t );
428 bitmap = htons( bitmap );
429 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
430 rbuf += sizeof( uint16_t );
432 /* check WriteInhibit bit if we have a ressource fork
433 * the test is done here, after some Mac trafic capture
435 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
436 ad_getattr(ofork->of_ad, &bshort);
437 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
438 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
441 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
442 return(AFPERR_OLOCK);
447 * synchronization locks:
450 /* don't try to lock non-existent rforks. */
451 if ((eid == ADEID_DFORK)
452 || (ad_reso_fileno(ofork->of_ad) != -1)
453 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
454 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
455 /* can we access the fork? */
457 ofork->of_flags |= AFPFORK_ERROR;
459 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
462 case EAGAIN: /* return data anyway */
466 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
467 return( AFPERR_DENYCONF );
471 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
472 return( AFPERR_PARAM );
475 if ((access & OPENACC_WR))
476 ofork->of_flags |= AFPFORK_ACCWR;
478 /* the file may be open read only without ressource fork */
479 if ((access & OPENACC_RD))
480 ofork->of_flags |= AFPFORK_ACCRD;
482 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
488 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
492 int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
496 uint16_t ofrefnum, bitmap;
504 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
505 ibuf += sizeof( ofrefnum );
507 memcpy(&bitmap, ibuf, sizeof(bitmap));
508 bitmap = ntohs(bitmap);
509 ibuf += sizeof( bitmap );
512 if (NULL == ( ofork = of_find( ofrefnum )) ) {
513 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
514 return( AFPERR_PARAM );
517 if (ofork->of_vol->v_flags & AFPVOL_RO)
520 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
521 return AFPERR_ACCESS;
523 if ( ofork->of_flags & AFPFORK_DATA) {
525 } else if (ofork->of_flags & AFPFORK_RSRC) {
530 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
531 && eid == ADEID_RFORK
533 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
534 && eid == ADEID_DFORK)) {
535 return AFPERR_BITMAP;
539 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
540 if (obj->afp_version >= 30) {
544 return AFPERR_BITMAP;
547 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
548 return AFPERR_PARAM ;
550 size = get_off_t(&ibuf, is64);
553 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
556 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
557 st_size = ad_size(ofork->of_ad, eid);
559 if (st_size > size &&
560 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
561 goto afp_setfork_err;
563 err = ad_dtruncate( ofork->of_ad, size );
565 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
567 goto afp_setfork_err;
568 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
569 ad_refresh(NULL, ofork->of_ad );
571 st_size = ad_size(ofork->of_ad, eid);
573 if (st_size > size &&
574 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
575 goto afp_setfork_err;
578 err = ad_rtruncate(ofork->of_ad, size);
580 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
582 goto afp_setfork_err;
584 if (ad_flush( ofork->of_ad ) < 0) {
585 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
589 return AFPERR_BITMAP;
592 if ( flushfork( ofork ) < 0 ) {
593 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
608 return AFPERR_ACCESS;
619 /* for this to work correctly, we need to check for locks before each
620 * read and write. that's most easily handled by always doing an
621 * appropriate check before each ad_read/ad_write. other things
622 * that can change files like truncate are handled internally to those
625 #define ENDBIT(a) ((a) & 0x80)
626 #define UNLOCKBIT(a) ((a) & 0x01)
629 /* ---------------------- */
630 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
633 off_t offset, length;
641 /* figure out parameters */
643 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
645 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
646 ibuf += sizeof(ofrefnum);
648 if (NULL == ( ofork = of_find( ofrefnum )) ) {
649 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
650 return( AFPERR_PARAM );
653 if ( ofork->of_flags & AFPFORK_DATA) {
655 } else if (ofork->of_flags & AFPFORK_RSRC) {
660 offset = get_off_t(&ibuf, is64);
661 length = get_off_t(&ibuf, is64);
664 length = BYTELOCK_MAX;
665 else if (!length || is_neg(is64, length)) {
667 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
672 offset += ad_size(ofork->of_ad, eid);
673 /* FIXME what do we do if file size > 2 GB and
674 it's not byte_lock_ext?
677 if (offset < 0) /* error if we have a negative offset */
680 /* if the file is a read-only file, we use read locks instead of
681 * write locks. that way, we can prevent anyone from initiating
683 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
684 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
685 ofork->of_refnum) < 0) {
689 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
695 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
703 *rbuflen = set_off_t (offset, rbuf, is64);
707 /* --------------------------- */
708 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
710 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
713 /* --------------------------- */
714 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
716 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
721 static ssize_t read_file(struct ofork *ofork, int eid,
722 off_t offset, u_char nlmask,
723 u_char nlchar, char *rbuf,
730 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
732 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
734 return( AFPERR_PARAM );
736 if ( (size_t)cc < *rbuflen ) {
744 for ( p = rbuf, q = p + cc; p < q; ) {
745 if (( *p++ & nlmask ) == nlchar ) {
757 return( AFPERR_EOF );
762 /* -----------------------------
763 * with ddp, afp_read can return fewer bytes than in reqcount
764 * so return EOF only if read actually past end of file not
765 * if offset +reqcount > size of file
767 * getfork size ==> 10430
768 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
769 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
770 * read fork offset 9248 size 1508 ==> 1182 (EOF)
771 * 10752 is a bug in Mac 7.5.x finder
773 * with dsi, should we check that reqcount < server quantum?
775 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
778 off_t offset, saveoff, reqcount, savereqcount;
782 u_char nlmask, nlchar;
785 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
786 ibuf += sizeof( u_short );
788 if (NULL == ( ofork = of_find( ofrefnum )) ) {
789 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
794 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
798 offset = get_off_t(&ibuf, is64);
799 reqcount = get_off_t(&ibuf, is64);
801 LOG(log_debug, logtype_afpd,
802 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
803 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
812 /* if we wanted to be picky, we could add in the following
813 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
815 if (reqcount < 0 || offset < 0) {
820 if ( ofork->of_flags & AFPFORK_DATA) {
822 } else if (ofork->of_flags & AFPFORK_RSRC) {
824 } else { /* fork wasn't opened. this should never really happen. */
829 /* zero request count */
835 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
836 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
838 savereqcount = reqcount;
840 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
845 *rbuflen = MIN(reqcount, *rbuflen);
846 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
847 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
849 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen);
852 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
853 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
855 /* dsi can stream requests. we can only do this if we're not checking
856 * for an end-of-line character. oh well. */
857 if ((*rbuflen < reqcount) && !nlmask) {
861 /* reqcount isn't always truthful. we need to deal with that. */
862 size = ad_size(ofork->of_ad, eid);
864 /* subtract off the offset */
866 if (reqcount > size) {
873 /* dsi_readinit() returns size of next read buffer. by this point,
874 * we know that we're sending some data. if we fail, something
875 * horrible happened. */
876 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
879 /* due to the nature of afp packets, we have to exit if we get
880 an error. we can't do this with translation on. */
882 if (!(obj->options.flags & OPTION_NOSENDFILE)) {
883 int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
884 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
890 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
901 /* fill up our buffer. */
902 while (*rbuflen > 0) {
903 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen);
908 /* dsi_read() also returns buffer size of next allocation */
909 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
918 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
920 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
921 obj->exit(EXITERR_CLNT);
925 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
933 /* ---------------------- */
934 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
936 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
939 /* ---------------------- */
940 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
942 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
945 /* ---------------------- */
946 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
954 memcpy(&vid, ibuf, sizeof(vid));
955 if (NULL == ( vol = getvolbyvid( vid )) ) {
956 return( AFPERR_PARAM );
963 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
970 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
972 if (NULL == ( ofork = of_find( ofrefnum )) ) {
973 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
974 return( AFPERR_PARAM );
977 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
978 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
980 if ( flushfork( ofork ) < 0 ) {
981 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
989 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
990 fsync(2) on OSX is implemented differently than on other platforms.
991 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
993 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1001 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1002 ibuf += sizeof( ofrefnum );
1004 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1005 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1006 return( AFPERR_PARAM );
1009 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1010 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1012 if ( flushfork( ofork ) < 0 ) {
1013 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1020 /* this is very similar to closefork */
1021 int flushfork(struct ofork *ofork)
1025 int err = 0, doflush = 0;
1027 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1028 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1029 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1030 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1034 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1035 (ofork->of_flags & AFPFORK_RSRC)) {
1037 /* read in the rfork length */
1038 ad_refresh(NULL, ofork->of_ad);
1040 /* set the date if we're dirty */
1041 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1042 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1043 ofork->of_flags &= ~AFPFORK_DIRTY;
1047 /* flush the header */
1048 if (doflush && ad_flush(ofork->of_ad) < 0)
1051 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1055 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1056 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1062 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1064 struct ofork *ofork;
1069 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1071 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1072 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1073 return( AFPERR_PARAM );
1076 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1077 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1079 if ( of_closefork( ofork ) < 0 ) {
1080 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1081 return( AFPERR_PARAM );
1088 static ssize_t write_file(struct ofork *ofork, int eid,
1089 off_t offset, char *rbuf,
1095 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1096 (uintmax_t)offset, rbuflen);
1098 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1099 rbuf, rbuflen)) < 0 ) {
1104 return( AFPERR_DFULL );
1106 return AFPERR_ACCESS;
1108 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1109 return( AFPERR_PARAM );
1117 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1118 * the client may have sent us a bunch of data that's not reflected
1119 * in reqcount et al. */
1120 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1122 struct ofork *ofork;
1123 off_t offset, saveoff, reqcount, oldsize, newsize;
1124 int endflag, eid, err = AFP_OK;
1128 /* figure out parameters */
1130 endflag = ENDBIT(*ibuf);
1132 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1133 ibuf += sizeof( ofrefnum );
1135 offset = get_off_t(&ibuf, is64);
1136 reqcount = get_off_t(&ibuf, is64);
1138 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1139 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1144 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1145 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1147 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1148 err = AFPERR_ACCESS;
1153 writtenfork = ofork;
1156 if ( ofork->of_flags & AFPFORK_DATA) {
1158 } else if (ofork->of_flags & AFPFORK_RSRC) {
1161 err = AFPERR_ACCESS; /* should never happen */
1165 oldsize = ad_size(ofork->of_ad, eid);
1169 /* handle bogus parameters */
1170 if (reqcount < 0 || offset < 0) {
1175 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1177 /* offset can overflow on 64-bit capable filesystems.
1178 * report disk full if that's going to happen. */
1179 if (sum_neg(is64, offset, reqcount)) {
1184 if (!reqcount) { /* handle request counts of 0 */
1186 *rbuflen = set_off_t (offset, rbuf, is64);
1191 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1192 reqcount, ofork->of_refnum) < 0) {
1197 DSI *dsi = obj->dsi;
1198 /* find out what we have already and write it out. */
1199 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1201 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1202 dsi_writeflush(dsi);
1204 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1210 #if 0 /*def HAVE_SENDFILE_WRITE*/
1211 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1212 offset, dsi->datasize)) < 0) {
1220 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1221 goto afp_write_loop;
1223 dsi_writeflush(dsi);
1225 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1226 reqcount, ofork->of_refnum);
1231 goto afp_write_done;
1232 #endif /* 0, was HAVE_SENDFILE_WRITE */
1234 /* loop until everything gets written. currently
1235 * dsi_write handles the end case by itself. */
1236 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1237 if ((cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) {
1238 dsi_writeflush(dsi);
1240 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1241 reqcount, ofork->of_refnum);
1247 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1248 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1249 ofork->of_flags |= AFPFORK_DIRTY;
1251 /* we have modified any fork, remember until close_fork */
1252 ofork->of_flags |= AFPFORK_MODIFIED;
1254 /* update write count */
1255 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1257 *rbuflen = set_off_t (offset, rbuf, is64);
1261 dsi_writeinit(obj->dsi, rbuf, *rbuflen);
1262 dsi_writeflush(obj->dsi);
1264 if (err != AFP_OK) {
1270 /* ---------------------------- */
1271 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1273 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1276 /* ----------------------------
1277 * FIXME need to deal with SIGXFSZ signal
1279 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1281 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1284 /* ---------------------------- */
1285 int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1287 struct ofork *ofork;
1289 uint16_t ofrefnum, bitmap;
1292 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1293 ibuf += sizeof( ofrefnum );
1294 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1295 bitmap = ntohs( bitmap );
1296 ibuf += sizeof( bitmap );
1299 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1300 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1301 return( AFPERR_PARAM );
1304 if (AD_META_OPEN(ofork->of_ad)) {
1305 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1306 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1307 return( AFPERR_PARAM );
1311 if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1315 *rbuflen = buflen + sizeof( u_short );
1316 bitmap = htons( bitmap );
1317 memcpy(rbuf, &bitmap, sizeof( bitmap ));