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 | ADFLAGS_SETSHRMD);
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 | ADFLAGS_SETSHRMD);
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? */
455 ofork->of_flags |= AFPFORK_ERROR;
457 ad_close( ofork->of_ad, adflags | ADFLAGS_SETSHRMD);
460 case EAGAIN: /* return data anyway */
464 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
465 return( AFPERR_DENYCONF );
469 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
470 return( AFPERR_PARAM );
473 if ((access & OPENACC_WR))
474 ofork->of_flags |= AFPFORK_ACCWR;
476 /* the file may be open read only without ressource fork */
477 if ((access & OPENACC_RD))
478 ofork->of_flags |= AFPFORK_ACCRD;
480 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
486 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
490 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
494 uint16_t ofrefnum, bitmap;
502 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
503 ibuf += sizeof( ofrefnum );
505 memcpy(&bitmap, ibuf, sizeof(bitmap));
506 bitmap = ntohs(bitmap);
507 ibuf += sizeof( bitmap );
510 if (NULL == ( ofork = of_find( ofrefnum )) ) {
511 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
512 return( AFPERR_PARAM );
515 if (ofork->of_vol->v_flags & AFPVOL_RO)
518 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
519 return AFPERR_ACCESS;
521 if ( ofork->of_flags & AFPFORK_DATA) {
523 } else if (ofork->of_flags & AFPFORK_RSRC) {
528 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
529 && eid == ADEID_RFORK
531 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
532 && eid == ADEID_DFORK)) {
533 return AFPERR_BITMAP;
537 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
538 if (afp_version >= 30) {
542 return AFPERR_BITMAP;
545 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
546 return AFPERR_PARAM ;
548 size = get_off_t(&ibuf, is64);
551 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
554 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
555 st_size = ad_size(ofork->of_ad, eid);
557 if (st_size > size &&
558 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
559 goto afp_setfork_err;
561 err = ad_dtruncate( ofork->of_ad, size );
563 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
565 goto afp_setfork_err;
566 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
567 ad_refresh(NULL, ofork->of_ad );
569 st_size = ad_size(ofork->of_ad, eid);
571 if (st_size > size &&
572 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
573 goto afp_setfork_err;
575 err = ad_rtruncate(ofork->of_ad, size);
577 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
579 goto afp_setfork_err;
581 if (ad_flush( ofork->of_ad ) < 0) {
582 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
586 return AFPERR_BITMAP;
589 if ( flushfork( ofork ) < 0 ) {
590 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
605 return AFPERR_ACCESS;
616 /* for this to work correctly, we need to check for locks before each
617 * read and write. that's most easily handled by always doing an
618 * appropriate check before each ad_read/ad_write. other things
619 * that can change files like truncate are handled internally to those
622 #define ENDBIT(a) ((a) & 0x80)
623 #define UNLOCKBIT(a) ((a) & 0x01)
626 /* ---------------------- */
627 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
630 off_t offset, length;
638 /* figure out parameters */
640 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
642 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
643 ibuf += sizeof(ofrefnum);
645 if (NULL == ( ofork = of_find( ofrefnum )) ) {
646 LOG(log_error, logtype_afpd, "byte_lock: of_find(%d) could not locate fork", ofrefnum );
647 return( AFPERR_PARAM );
650 if ( ofork->of_flags & AFPFORK_DATA) {
652 } else if (ofork->of_flags & AFPFORK_RSRC) {
657 offset = get_off_t(&ibuf, is64);
658 length = get_off_t(&ibuf, is64);
661 length = BYTELOCK_MAX;
662 else if (!length || is_neg(is64, length)) {
664 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
669 offset += ad_size(ofork->of_ad, eid);
670 /* FIXME what do we do if file size > 2 GB and
671 it's not byte_lock_ext?
674 if (offset < 0) /* error if we have a negative offset */
677 /* if the file is a read-only file, we use read locks instead of
678 * write locks. that way, we can prevent anyone from initiating
680 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
681 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
682 ofork->of_refnum) < 0) {
686 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
692 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
700 *rbuflen = set_off_t (offset, rbuf, is64);
704 /* --------------------------- */
705 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
707 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
710 /* --------------------------- */
711 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
713 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
718 /* --------------------------- */
719 static int crlf(struct ofork *of)
723 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
724 /* no resource fork or no finderinfo, use our files extension mapping */
725 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
728 /* file type is TEXT */
731 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
738 static ssize_t read_file(struct ofork *ofork, int eid,
739 off_t offset, u_char nlmask,
740 u_char nlchar, char *rbuf,
741 size_t *rbuflen, const int xlate)
747 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
749 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
751 return( AFPERR_PARAM );
753 if ( (size_t)cc < *rbuflen ) {
761 for ( p = rbuf, q = p + cc; p < q; ) {
762 if (( *p++ & nlmask ) == nlchar ) {
773 * If this file is of type TEXT, then swap \012 to \015.
776 for ( p = rbuf, q = p + cc; p < q; p++ ) {
777 if ( *p == '\012' ) {
779 } else if ( *p == '\015' ) {
788 return( AFPERR_EOF );
793 /* -----------------------------
794 * with ddp, afp_read can return fewer bytes than in reqcount
795 * so return EOF only if read actually past end of file not
796 * if offset +reqcount > size of file
798 * getfork size ==> 10430
799 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
800 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
801 * read fork offset 9248 size 1508 ==> 1182 (EOF)
802 * 10752 is a bug in Mac 7.5.x finder
804 * with dsi, should we check that reqcount < server quantum?
806 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
809 off_t offset, saveoff, reqcount, savereqcount;
813 u_char nlmask, nlchar;
816 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
817 ibuf += sizeof( u_short );
819 if (NULL == ( ofork = of_find( ofrefnum )) ) {
820 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
825 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
829 offset = get_off_t(&ibuf, is64);
830 reqcount = get_off_t(&ibuf, is64);
832 LOG(log_debug, logtype_afpd,
833 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", offset, reqcount,
834 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
843 /* if we wanted to be picky, we could add in the following
844 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
846 if (reqcount < 0 || offset < 0) {
851 if ( ofork->of_flags & AFPFORK_DATA) {
854 } else if (ofork->of_flags & AFPFORK_RSRC) {
856 } else { /* fork wasn't opened. this should never really happen. */
861 /* zero request count */
867 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
868 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
870 savereqcount = reqcount;
872 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
877 *rbuflen = MIN(reqcount, *rbuflen);
878 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
879 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
881 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
884 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
885 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
887 /* dsi can stream requests. we can only do this if we're not checking
888 * for an end-of-line character. oh well. */
889 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
890 DSI *dsi = obj->handle;
893 /* reqcount isn't always truthful. we need to deal with that. */
894 size = ad_size(ofork->of_ad, eid);
896 /* subtract off the offset */
898 if (reqcount > size) {
905 /* dsi_readinit() returns size of next read buffer. by this point,
906 * we know that we're sending some data. if we fail, something
907 * horrible happened. */
908 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
911 /* due to the nature of afp packets, we have to exit if we get
912 an error. we can't do this with translation on. */
917 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
919 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
920 if (errno == EINVAL || errno == ENOSYS)
923 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
935 /* fill up our buffer. */
936 while (*rbuflen > 0) {
937 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
942 /* dsi_read() also returns buffer size of next allocation */
943 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
952 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
954 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
955 obj->exit(EXITERR_CLNT);
959 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
967 /* ---------------------- */
968 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
970 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
973 /* ---------------------- */
974 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
976 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
979 /* ---------------------- */
980 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
988 memcpy(&vid, ibuf, sizeof(vid));
989 if (NULL == ( vol = getvolbyvid( vid )) ) {
990 return( AFPERR_PARAM );
997 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1004 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1006 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1007 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1008 return( AFPERR_PARAM );
1011 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
1012 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1014 if ( flushfork( ofork ) < 0 ) {
1015 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1023 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1024 fsync(2) on OSX is implemented differently than on other platforms.
1025 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1027 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1029 struct ofork *ofork;
1035 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1036 ibuf += sizeof( ofrefnum );
1038 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1039 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1040 return( AFPERR_PARAM );
1043 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1044 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1046 if ( flushfork( ofork ) < 0 ) {
1047 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1054 /* this is very similar to closefork */
1055 int flushfork(struct ofork *ofork)
1059 int err = 0, doflush = 0;
1061 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1062 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1063 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1064 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1068 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1069 (ofork->of_flags & AFPFORK_RSRC)) {
1071 /* read in the rfork length */
1072 ad_refresh(NULL, ofork->of_ad);
1074 /* set the date if we're dirty */
1075 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1076 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1077 ofork->of_flags &= ~AFPFORK_DIRTY;
1081 /* flush the header */
1082 if (doflush && ad_flush(ofork->of_ad) < 0)
1085 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1089 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1090 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1096 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1098 struct ofork *ofork;
1103 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1105 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1106 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1107 return( AFPERR_PARAM );
1110 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1111 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1113 if ( of_closefork( ofork ) < 0 ) {
1114 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1115 return( AFPERR_PARAM );
1122 static ssize_t write_file(struct ofork *ofork, int eid,
1123 off_t offset, char *rbuf,
1124 size_t rbuflen, const int xlate)
1130 * If this file is of type TEXT, swap \015 to \012.
1133 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1134 if ( *p == '\015' ) {
1136 } else if ( *p == '\012' ) {
1142 LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)",
1143 (uintmax_t)offset, rbuflen);
1145 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1146 rbuf, rbuflen)) < 0 ) {
1151 return( AFPERR_DFULL );
1153 return AFPERR_ACCESS;
1155 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1156 return( AFPERR_PARAM );
1164 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1165 * the client may have sent us a bunch of data that's not reflected
1166 * in reqcount et al. */
1167 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1169 struct ofork *ofork;
1170 off_t offset, saveoff, reqcount, oldsize, newsize;
1171 int endflag, eid, xlate = 0, err = AFP_OK;
1175 /* figure out parameters */
1177 endflag = ENDBIT(*ibuf);
1179 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1180 ibuf += sizeof( ofrefnum );
1182 offset = get_off_t(&ibuf, is64);
1183 reqcount = get_off_t(&ibuf, is64);
1185 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1186 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1191 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1192 offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1194 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1195 err = AFPERR_ACCESS;
1200 writtenfork = ofork;
1203 if ( ofork->of_flags & AFPFORK_DATA) {
1206 } else if (ofork->of_flags & AFPFORK_RSRC) {
1209 err = AFPERR_ACCESS; /* should never happen */
1213 oldsize = ad_size(ofork->of_ad, eid);
1217 /* handle bogus parameters */
1218 if (reqcount < 0 || offset < 0) {
1223 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1225 /* offset can overflow on 64-bit capable filesystems.
1226 * report disk full if that's going to happen. */
1227 if (sum_neg(is64, offset, reqcount)) {
1232 if (!reqcount) { /* handle request counts of 0 */
1234 *rbuflen = set_off_t (offset, rbuf, is64);
1239 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1240 reqcount, ofork->of_refnum) < 0) {
1245 /* this is yucky, but dsi can stream i/o and asp can't */
1246 switch (obj->proto) {
1249 DSI *dsi = obj->handle;
1250 /* find out what we have already and write it out. */
1251 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1253 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1254 dsi_writeflush(dsi);
1256 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1262 #if 0 /*def HAVE_SENDFILE_WRITE*/
1263 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1264 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1265 offset, dsi->datasize)) < 0) {
1273 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1274 goto afp_write_loop;
1276 dsi_writeflush(dsi);
1278 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1279 reqcount, ofork->of_refnum);
1284 goto afp_write_done;
1286 #endif /* 0, was HAVE_SENDFILE_WRITE */
1288 /* loop until everything gets written. currently
1289 * dsi_write handles the end case by itself. */
1290 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1291 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1292 dsi_writeflush(dsi);
1294 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1295 reqcount, ofork->of_refnum);
1304 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1305 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1306 ofork->of_flags |= AFPFORK_DIRTY;
1308 /* we have modified any fork, remember until close_fork */
1309 ofork->of_flags |= AFPFORK_MODIFIED;
1311 /* update write count */
1312 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1314 *rbuflen = set_off_t (offset, rbuf, is64);
1318 if (obj->proto == AFPPROTO_DSI) {
1319 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1320 dsi_writeflush(obj->handle);
1322 if (err != AFP_OK) {
1328 /* ---------------------------- */
1329 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1331 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1334 /* ----------------------------
1335 * FIXME need to deal with SIGXFSZ signal
1337 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1339 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1342 /* ---------------------------- */
1343 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1345 struct ofork *ofork;
1347 uint16_t ofrefnum, bitmap;
1350 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1351 ibuf += sizeof( ofrefnum );
1352 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1353 bitmap = ntohs( bitmap );
1354 ibuf += sizeof( bitmap );
1357 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1358 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1359 return( AFPERR_PARAM );
1362 if (AD_META_OPEN(ofork->of_ad)) {
1363 if ( ad_refresh(NULL, ofork->of_ad ) < 0 ) {
1364 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1365 return( AFPERR_PARAM );
1369 if (AFP_OK != (ret = getforkparams(ofork, bitmap, rbuf + sizeof( u_short ), &buflen ))) {
1373 *rbuflen = buflen + sizeof( u_short );
1374 bitmap = htons( bitmap );
1375 memcpy(rbuf, &bitmap, sizeof( bitmap ));