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(const AFPObj *obj, struct adouble *adp, int eid, int access, int ofrefnum)
158 if (obj->options.flags & OPTION_SHARE_RESERV) {
159 shmd.f_access = (access & OPENACC_RD ? F_RDACC : 0) | (access & OPENACC_WR ? F_WRACC : 0);
160 if (shmd.f_access == 0)
161 /* we must give an access mode, otherwise fcntl will complain */
162 shmd.f_access = F_RDACC;
163 shmd.f_deny = (access & OPENACC_DRD ? F_RDDNY : F_NODNY) | (access & OPENACC_DWR) ? F_WRDNY : 0;
164 shmd.f_id = ofrefnum;
166 int fd = (eid == ADEID_DFORK) ? ad_data_fileno(adp) : ad_reso_fileno(adp);
168 if (fd != -1 && fd != AD_SYMLINK && fcntl(fd, F_SHARE, &shmd) != 0) {
169 LOG(log_debug, logtype_afpd, "fork_setmode: fcntl: %s", strerror(errno));
176 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
177 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
180 if ((access & (OPENACC_RD | OPENACC_DRD))) {
181 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
183 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
186 if ((access & OPENACC_RD) && denyreadset) {
190 if ((access & OPENACC_DRD) && readset) {
194 /* boolean logic is not enough, because getforkmode is not always telling the
197 if ((access & OPENACC_RD)) {
198 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
202 if ((access & OPENACC_DRD)) {
203 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
208 /* ------------same for writing -------------- */
209 if ((access & (OPENACC_WR | OPENACC_DWR))) {
210 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
212 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
215 if ((access & OPENACC_WR) && denywriteset) {
219 if ((access & OPENACC_DWR) && writeset) {
223 if ((access & OPENACC_WR)) {
224 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
228 if ((access & OPENACC_DWR)) {
229 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
238 /* ----------------------- */
239 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
243 struct ofork *ofork, *opened;
244 struct adouble *adsame = NULL;
246 int ret, adflags, eid;
248 uint16_t vid, bitmap, access, ofrefnum;
249 char fork, *path, *upath;
257 memcpy(&vid, ibuf, sizeof( vid ));
261 if (NULL == ( vol = getvolbyvid( vid ))) {
262 return( AFPERR_PARAM );
265 memcpy(&did, ibuf, sizeof( did ));
266 ibuf += sizeof( int );
268 if (NULL == ( dir = dirlookup( vol, did ))) {
272 memcpy(&bitmap, ibuf, sizeof( bitmap ));
273 bitmap = ntohs( bitmap );
274 ibuf += sizeof( bitmap );
275 memcpy(&access, ibuf, sizeof( access ));
276 access = ntohs( access );
277 ibuf += sizeof( access );
279 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
283 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
284 return get_afp_errno(AFPERR_PARAM);
287 if (*s_path->m_name == '\0') {
289 return AFPERR_BADTYPE;
292 /* stat() data fork st is set because it's not a dir */
293 switch ( s_path->st_errno ) {
299 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
301 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
304 /* FIXME should we check it first ? */
305 upath = s_path->u_name;
306 if (!vol_unix_priv(vol)) {
307 if (check_access(obj, vol, upath, access ) < 0) {
308 return AFPERR_ACCESS;
311 if (file_access(obj, vol, s_path, access ) < 0) {
312 return AFPERR_ACCESS;
317 /* XXX: this probably isn't the best way to do this. the already
318 open bits should really be set if the fork is opened by any
319 program, not just this one. however, that's problematic to do
320 if we can't write lock files somewhere. opened is also passed to
321 ad_open so that we can keep file locks together.
322 FIXME: add the fork we are opening?
324 if ((opened = of_findname(s_path))) {
325 adsame = opened->of_ad;
328 if ( fork == OPENFORK_DATA ) {
330 adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF;
333 adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF;
334 if (!(access & OPENACC_WR))
335 adflags |= ADFLAGS_NORF;
338 path = s_path->m_name;
339 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
340 adsame, st)) == NULL ) {
341 return( AFPERR_NFILE );
344 LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)",
345 fullpathname(s_path->u_name),
346 (fork == OPENFORK_DATA) ? "data" : "reso",
347 !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR");
350 if (access & OPENACC_WR) {
351 /* try opening in read-write mode */
352 if (ad_open(ofork->of_ad, upath,
353 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
360 if (fork == OPENFORK_DATA) {
361 /* try to open only the data fork */
362 if (ad_open(ofork->of_ad, upath,
363 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
366 adflags = ADFLAGS_DF;
368 /* here's the deal. we only try to create the resource
369 * fork if the user wants to open it for write acess. */
370 if (ad_open(ofork->of_ad, upath,
371 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0)
373 ofork->of_flags |= AFPFORK_META;
381 ret = AFPERR_BADTYPE;
384 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
390 /* the ressource fork is open too */
391 ofork->of_flags |= AFPFORK_META;
394 /* try opening in read-only mode */
396 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
404 /* see if client asked for a read only data fork */
405 if (fork == OPENFORK_DATA) {
406 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
409 adflags = ADFLAGS_DF;
411 /* else we don't set AFPFORK_META because there's no ressource fork file
412 * We need to check AFPFORK_META in afp_closefork(). eg fork open read-only
413 * then create in open read-write.
414 * FIXME , it doesn't play well with byte locking example:
415 * ressource fork open read only
416 * locking set on it (no effect, there's no file!)
417 * ressource fork open read write now
425 ret = AFPERR_BADTYPE;
428 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
429 fullpathname(s_path->m_name), strerror(errno) );
433 ofork->of_flags |= AFPFORK_META;
437 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
438 if (ad_setname(ofork->of_ad, path)) {
439 ad_flush( ofork->of_ad );
443 if ((ret = getforkparams(obj, ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
444 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
448 *rbuflen = buflen + 2 * sizeof( uint16_t );
449 bitmap = htons( bitmap );
450 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
451 rbuf += sizeof( uint16_t );
453 /* check WriteInhibit bit if we have a ressource fork
454 * the test is done here, after some Mac trafic capture
456 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
457 ad_getattr(ofork->of_ad, &bshort);
458 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
459 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
462 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
463 return(AFPERR_OLOCK);
468 * synchronization locks:
471 /* don't try to lock non-existent rforks. */
472 if ((eid == ADEID_DFORK)
473 || (ad_reso_fileno(ofork->of_ad) != -1)
474 || (ofork->of_ad->ad_vers == AD_VERSION_EA)) {
475 ret = fork_setmode(obj, ofork->of_ad, eid, access, ofrefnum);
476 /* can we access the fork? */
478 ofork->of_flags |= AFPFORK_ERROR;
480 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
483 case EAGAIN: /* return data anyway */
487 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
488 return( AFPERR_DENYCONF );
492 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
493 return( AFPERR_PARAM );
496 if ((access & OPENACC_WR))
497 ofork->of_flags |= AFPFORK_ACCWR;
499 /* the file may be open read only without ressource fork */
500 if ((access & OPENACC_RD))
501 ofork->of_flags |= AFPFORK_ACCRD;
503 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
509 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
513 int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
517 uint16_t ofrefnum, bitmap;
525 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
526 ibuf += sizeof( ofrefnum );
528 memcpy(&bitmap, ibuf, sizeof(bitmap));
529 bitmap = ntohs(bitmap);
530 ibuf += sizeof( bitmap );
533 if (NULL == ( ofork = of_find( ofrefnum )) ) {
534 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
535 return( AFPERR_PARAM );
538 if (ofork->of_vol->v_flags & AFPVOL_RO)
541 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
542 return AFPERR_ACCESS;
544 if ( ofork->of_flags & AFPFORK_DATA) {
546 } else if (ofork->of_flags & AFPFORK_RSRC) {
551 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
552 && eid == ADEID_RFORK
554 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
555 && eid == ADEID_DFORK)) {
556 return AFPERR_BITMAP;
560 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
561 if (obj->afp_version >= 30) {
565 return AFPERR_BITMAP;
568 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
569 return AFPERR_PARAM ;
571 size = get_off_t(&ibuf, is64);
574 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
577 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
578 st_size = ad_size(ofork->of_ad, eid);
580 if (st_size > size &&
581 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
582 goto afp_setfork_err;
584 err = ad_dtruncate( ofork->of_ad, size );
586 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
588 goto afp_setfork_err;
589 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
590 ad_refresh(NULL, ofork->of_ad );
592 st_size = ad_size(ofork->of_ad, eid);
594 if (st_size > size &&
595 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
596 goto afp_setfork_err;
599 err = ad_rtruncate(ofork->of_ad, size);
601 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
603 goto afp_setfork_err;
605 if (ad_flush( ofork->of_ad ) < 0) {
606 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
610 return AFPERR_BITMAP;
613 if ( flushfork( ofork ) < 0 ) {
614 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
629 return AFPERR_ACCESS;
633 LOG(log_error, logtype_afpd, "afp_setforkparams: DISK FULL");
641 /* for this to work correctly, we need to check for locks before each
642 * read and write. that's most easily handled by always doing an
643 * appropriate check before each ad_read/ad_write. other things
644 * that can change files like truncate are handled internally to those
647 #define ENDBIT(a) ((a) & 0x80)
648 #define UNLOCKBIT(a) ((a) & 0x01)
651 /* ---------------------- */
652 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
655 off_t offset, length;
663 /* figure out parameters */
665 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
667 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
668 ibuf += sizeof(ofrefnum);
670 if (NULL == ( ofork = of_find( ofrefnum )) ) {
671 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
672 return( AFPERR_PARAM );
675 if ( ofork->of_flags & AFPFORK_DATA) {
677 } else if (ofork->of_flags & AFPFORK_RSRC) {
682 offset = get_off_t(&ibuf, is64);
683 length = get_off_t(&ibuf, is64);
686 length = BYTELOCK_MAX;
687 else if (!length || is_neg(is64, length)) {
689 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
694 offset += ad_size(ofork->of_ad, eid);
695 /* FIXME what do we do if file size > 2 GB and
696 it's not byte_lock_ext?
699 if (offset < 0) /* error if we have a negative offset */
702 /* if the file is a read-only file, we use read locks instead of
703 * write locks. that way, we can prevent anyone from initiating
705 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
706 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
707 ofork->of_refnum) < 0) {
711 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
717 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
725 *rbuflen = set_off_t (offset, rbuf, is64);
729 /* --------------------------- */
730 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
732 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
735 /* --------------------------- */
736 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
738 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
744 * Read *rbuflen bytes from fork at offset
746 * @param ofork (r) fork handle
747 * @param eid (r) data fork or ressource fork entry id
748 * @param offset (r) offset
749 * @param rbuf (r) data buffer
750 * @param rbuflen (rw) in: number of bytes to read, out: bytes read
752 * @return AFP status code
754 static int read_file(const struct ofork *ofork, int eid, off_t offset, char *rbuf, size_t *rbuflen)
760 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
762 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
764 return( AFPERR_PARAM );
768 if ((size_t)cc < *rbuflen)
773 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
777 off_t offset, saveoff, reqcount, savereqcount, size;
782 /* we break the AFP spec here by not supporting nlmask and nlchar anymore */
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) {
799 if ( ofork->of_flags & AFPFORK_DATA) {
801 } else if (ofork->of_flags & AFPFORK_RSRC) {
803 } else { /* fork wasn't opened. this should never really happen. */
808 offset = get_off_t(&ibuf, is64);
809 reqcount = get_off_t(&ibuf, is64);
811 /* zero request count */
817 /* reqcount isn't always truthful. we need to deal with that. */
818 size = ad_size(ofork->of_ad, eid);
820 LOG(log_debug, logtype_afpd,
821 "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s, size: %" PRIu64 ")",
822 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r", size);
829 /* subtract off the offset */
830 if (reqcount + offset > size) {
831 reqcount = size - offset;
835 savereqcount = reqcount;
838 LOG(log_debug, logtype_afpd,
839 "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s)",
840 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
842 if (reqcount < 0 || offset < 0) {
847 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
848 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
850 if (obj->options.flags & OPTION_AFP_READ_LOCK) {
851 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) {
858 if (!(eid == ADEID_DFORK && ad_data_fileno(ofork->of_ad) == AD_SYMLINK) &&
859 !(obj->options.flags & OPTION_NOSENDFILE)) {
860 int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
861 if (dsi_stream_read_file(dsi, fd, offset, reqcount, err) < 0) {
862 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s",
863 of_name(ofork), strerror(errno));
871 *rbuflen = MIN(reqcount, *rbuflen);
873 err = read_file(ofork, eid, offset, rbuf, rbuflen);
877 LOG(log_debug, logtype_afpd,
878 "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
879 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
884 * dsi_readinit() returns size of next read buffer. by this point,
885 * we know that we're sending some data. if we fail, something
888 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
892 while (*rbuflen > 0) {
893 cc = read_file(ofork, eid, offset, rbuf, rbuflen);
898 /* dsi_read() also returns buffer size of next allocation */
899 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
908 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
910 if (obj->options.flags & OPTION_AFP_READ_LOCK)
911 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
912 obj->exit(EXITERR_CLNT);
915 if (obj->options.flags & OPTION_AFP_READ_LOCK)
916 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum);
924 /* ---------------------- */
925 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
927 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
930 /* ---------------------- */
931 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
933 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
936 /* ---------------------- */
937 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
945 memcpy(&vid, ibuf, sizeof(vid));
946 if (NULL == ( vol = getvolbyvid( vid )) ) {
947 return( AFPERR_PARAM );
954 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
961 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
963 if (NULL == ( ofork = of_find( ofrefnum )) ) {
964 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
965 return( AFPERR_PARAM );
968 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
969 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
971 if ( flushfork( ofork ) < 0 ) {
972 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
980 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
981 fsync(2) on OSX is implemented differently than on other platforms.
982 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
984 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
992 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
993 ibuf += sizeof( ofrefnum );
995 if (NULL == ( ofork = of_find( ofrefnum )) ) {
996 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
997 return( AFPERR_PARAM );
1000 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1001 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1003 if ( flushfork( ofork ) < 0 ) {
1004 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1011 /* this is very similar to closefork */
1012 int flushfork(struct ofork *ofork)
1016 int err = 0, doflush = 0;
1018 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1019 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1020 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1021 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1025 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1026 (ofork->of_flags & AFPFORK_RSRC)) {
1028 /* read in the rfork length */
1029 ad_refresh(NULL, ofork->of_ad);
1031 /* set the date if we're dirty */
1032 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1033 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1034 ofork->of_flags &= ~AFPFORK_DIRTY;
1038 /* flush the header */
1039 if (doflush && ad_flush(ofork->of_ad) < 0)
1042 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1046 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1047 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1053 int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1055 struct ofork *ofork;
1060 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1062 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1063 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1064 return( AFPERR_PARAM );
1067 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1068 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1070 if (of_closefork(obj, ofork) < 0 ) {
1071 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1072 return( AFPERR_PARAM );
1079 static ssize_t write_file(struct ofork *ofork, int eid,
1080 off_t offset, char *rbuf,
1086 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1087 (uintmax_t)offset, rbuflen);
1089 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1090 rbuf, rbuflen)) < 0 ) {
1095 LOG(log_error, logtype_afpd, "write_file: DISK FULL");
1096 return( AFPERR_DFULL );
1098 return AFPERR_ACCESS;
1100 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1101 return( AFPERR_PARAM );
1110 * FPWrite. NOTE: on an error, we always use afp_write_err as
1111 * the client may have sent us a bunch of data that's not reflected
1112 * in reqcount et al.
1114 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1116 struct ofork *ofork;
1117 off_t offset, saveoff, reqcount, oldsize, newsize;
1118 int endflag, eid, err = AFP_OK;
1121 DSI *dsi = obj->dsi;
1122 char *rcvbuf = dsi->buffer;
1123 size_t rcvbuflen = dsi->dsireadbuf * dsi->server_quantum;
1125 /* figure out parameters */
1127 endflag = ENDBIT(*ibuf);
1129 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1130 ibuf += sizeof( ofrefnum );
1132 offset = get_off_t(&ibuf, is64);
1133 reqcount = get_off_t(&ibuf, is64);
1135 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1136 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1141 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1142 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1144 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1145 err = AFPERR_ACCESS;
1150 writtenfork = ofork;
1153 if ( ofork->of_flags & AFPFORK_DATA) {
1155 } else if (ofork->of_flags & AFPFORK_RSRC) {
1158 err = AFPERR_ACCESS; /* should never happen */
1162 oldsize = ad_size(ofork->of_ad, eid);
1166 /* handle bogus parameters */
1167 if (reqcount < 0 || offset < 0) {
1172 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1174 /* offset can overflow on 64-bit capable filesystems.
1175 * report disk full if that's going to happen. */
1176 if (sum_neg(is64, offset, reqcount)) {
1177 LOG(log_error, logtype_afpd, "write_fork: DISK FULL");
1182 if (!reqcount) { /* handle request counts of 0 */
1184 *rbuflen = set_off_t (offset, rbuf, is64);
1189 if (obj->options.flags & OPTION_AFP_READ_LOCK) {
1190 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, reqcount, ofork->of_refnum) < 0) {
1196 /* find out what we have already */
1197 cc = dsi_writeinit(dsi, rcvbuf, rcvbuflen);
1199 if (!cc || (cc = write_file(ofork, eid, offset, rcvbuf, cc)) < 0) {
1200 dsi_writeflush(dsi);
1202 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1203 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1209 #if 0 /*def HAVE_SENDFILE_WRITE*/
1210 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize)) < 0) {
1218 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1219 goto afp_write_loop;
1221 dsi_writeflush(dsi);
1223 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1224 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1229 goto afp_write_done;
1230 #endif /* 0, was HAVE_SENDFILE_WRITE */
1232 /* loop until everything gets written. currently
1233 * dsi_write handles the end case by itself. */
1234 while ((cc = dsi_write(dsi, rcvbuf, rcvbuflen))) {
1236 if ((cc = write_file(ofork, eid, offset, rcvbuf, cc)) < 0) {
1237 dsi_writeflush(dsi);
1239 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1240 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1244 LOG(log_debug, logtype_afpd, "afp_write: wrote: %jd, offset: %jd",
1245 (intmax_t)cc, (intmax_t)offset);
1250 if (obj->options.flags & OPTION_AFP_READ_LOCK)
1251 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1252 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1253 ofork->of_flags |= AFPFORK_DIRTY;
1255 /* we have modified any fork, remember until close_fork */
1256 ofork->of_flags |= AFPFORK_MODIFIED;
1258 /* update write count */
1259 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1261 *rbuflen = set_off_t (offset, rbuf, is64);
1265 dsi_writeinit(obj->dsi, rbuf, *rbuflen);
1266 dsi_writeflush(obj->dsi);
1268 if (err != AFP_OK) {
1274 /* ---------------------------- */
1275 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1277 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1280 /* ----------------------------
1281 * FIXME need to deal with SIGXFSZ signal
1283 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1285 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1288 /* ---------------------------- */
1289 int afp_getforkparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1291 struct ofork *ofork;
1293 uint16_t ofrefnum, bitmap;
1296 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1297 ibuf += sizeof( ofrefnum );
1298 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1299 bitmap = ntohs( bitmap );
1300 ibuf += sizeof( bitmap );
1303 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1304 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1305 return( AFPERR_PARAM );
1308 if (AD_META_OPEN(ofork->of_ad)) {
1309 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1310 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1311 return( AFPERR_PARAM );
1315 if (AFP_OK != (ret = getforkparams(obj, ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1319 *rbuflen = buflen + sizeof( u_short );
1320 bitmap = htons( bitmap );
1321 memcpy(rbuf, &bitmap, sizeof( bitmap ));