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_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
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);
211 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
212 return ad_excl_lock(adp, eid);
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;
235 memcpy(&vid, ibuf, sizeof( vid ));
239 if (NULL == ( vol = getvolbyvid( vid ))) {
240 return( AFPERR_PARAM );
243 memcpy(&did, ibuf, sizeof( did ));
244 ibuf += sizeof( int );
246 if (NULL == ( dir = dirlookup( vol, did ))) {
250 memcpy(&bitmap, ibuf, sizeof( bitmap ));
251 bitmap = ntohs( bitmap );
252 ibuf += sizeof( bitmap );
253 memcpy(&access, ibuf, sizeof( access ));
254 access = ntohs( access );
255 ibuf += sizeof( access );
257 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
261 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
262 return get_afp_errno(AFPERR_PARAM);
265 if (*s_path->m_name == '\0') {
267 return AFPERR_BADTYPE;
270 LOG(log_debug, logtype_afpd,
271 "afp_openfork(\"%s\", %s)",
272 abspath(s_path->u_name),
273 (fork & OPENFORK_RSCS) ? "OPENFORK_RSCS" : "OPENFORK_DATA");
275 /* stat() data fork st is set because it's not a dir */
276 switch ( s_path->st_errno ) {
282 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
284 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
287 /* FIXME should we check it first ? */
288 upath = s_path->u_name;
289 if (!vol_unix_priv(vol)) {
290 if (check_access(upath, access ) < 0) {
291 return AFPERR_ACCESS;
294 if (file_access(s_path, access ) < 0) {
295 return AFPERR_ACCESS;
300 /* XXX: this probably isn't the best way to do this. the already
301 open bits should really be set if the fork is opened by any
302 program, not just this one. however, that's problematic to do
303 if we can't write lock files somewhere. opened is also passed to
304 ad_open so that we can keep file locks together.
305 FIXME: add the fork we are opening?
307 if ((opened = of_findname(s_path))) {
308 adsame = opened->of_ad;
311 if ( fork == OPENFORK_DATA ) {
313 adflags = ADFLAGS_DF | ADFLAGS_HF ;
316 adflags = ADFLAGS_RF | ADFLAGS_HF;
319 path = s_path->m_name;
320 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
321 adsame, st)) == NULL ) {
322 return( AFPERR_NFILE );
326 if (access & OPENACC_WR) {
327 /* try opening in read-write mode */
328 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
336 if (fork == OPENFORK_DATA) {
337 /* try to open only the data fork */
338 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
341 adflags = ADFLAGS_DF;
343 /* here's the deal. we only try to create the resource
344 * fork if the user wants to open it for write acess. */
345 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
347 ofork->of_flags |= AFPFORK_OPEN;
356 ret = AFPERR_BADTYPE;
360 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_OPEN;
371 /* try opening in read-only mode */
373 if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 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, O_RDONLY) < 0) {
386 adflags = ADFLAGS_DF;
388 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
389 * We need to check AFPFORK_OPEN 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
403 ret = AFPERR_BADTYPE;
407 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
408 abspath(s_path->m_name), strerror(errno) );
414 /* the ressource fork is open too */
415 ofork->of_flags |= AFPFORK_OPEN;
419 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
420 if (ad_setname(ofork->of_ad, path)) {
421 ad_flush( ofork->of_ad );
425 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
426 ad_close( ofork->of_ad, adflags );
430 *rbuflen = buflen + 2 * sizeof( uint16_t );
431 bitmap = htons( bitmap );
432 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
433 rbuf += sizeof( uint16_t );
435 /* check WriteInhibit bit if we have a ressource fork
436 * the test is done here, after some Mac trafic capture
438 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
439 ad_getattr(ofork->of_ad, &bshort);
440 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
441 ad_close( ofork->of_ad, adflags );
444 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
445 return(AFPERR_OLOCK);
450 * synchronization locks:
453 /* don't try to lock non-existent rforks. */
454 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
456 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
457 /* can we access the fork? */
460 ad_close( ofork->of_ad, adflags );
463 case EAGAIN: /* return data anyway */
467 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
468 return( AFPERR_DENYCONF );
472 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
473 return( AFPERR_PARAM );
476 if ((access & OPENACC_WR))
477 ofork->of_flags |= AFPFORK_ACCWR;
479 /* the file may be open read only without ressource fork */
480 if ((access & OPENACC_RD))
481 ofork->of_flags |= AFPFORK_ACCRD;
483 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
489 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
493 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
497 uint16_t ofrefnum, bitmap;
505 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
506 ibuf += sizeof( ofrefnum );
508 memcpy(&bitmap, ibuf, sizeof(bitmap));
509 bitmap = ntohs(bitmap);
510 ibuf += sizeof( bitmap );
513 if (NULL == ( ofork = of_find( ofrefnum )) ) {
514 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
515 return( AFPERR_PARAM );
518 if (ofork->of_vol->v_flags & AFPVOL_RO)
521 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
522 return AFPERR_ACCESS;
524 if ( ofork->of_flags & AFPFORK_DATA) {
526 } else if (ofork->of_flags & AFPFORK_RSRC) {
531 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
532 && eid == ADEID_RFORK
534 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
535 && eid == ADEID_DFORK)) {
536 return AFPERR_BITMAP;
540 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
541 if (afp_version >= 30) {
545 return AFPERR_BITMAP;
548 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
549 return AFPERR_PARAM ;
551 size = get_off_t(&ibuf, is64);
554 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
557 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
558 st_size = ad_size(ofork->of_ad, eid);
560 if (st_size > size &&
561 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
562 goto afp_setfork_err;
564 err = ad_dtruncate( ofork->of_ad, size );
566 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
568 goto afp_setfork_err;
569 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
570 ad_refresh( ofork->of_ad );
572 st_size = ad_size(ofork->of_ad, eid);
574 if (st_size > size &&
575 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
576 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, "afp_bytelock: 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);
663 /* FIXME AD_FILELOCK test is surely wrong */
665 length = BYTELOCK_MAX;
666 else if (!length || is_neg(is64, length)) {
668 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
673 offset += ad_size(ofork->of_ad, eid);
674 /* FIXME what do we do if file size > 2 GB and
675 it's not byte_lock_ext?
678 if (offset < 0) /* error if we have a negative offset */
681 /* if the file is a read-only file, we use read locks instead of
682 * write locks. that way, we can prevent anyone from initiating
684 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
685 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
686 ofork->of_refnum) < 0) {
690 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
696 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
704 *rbuflen = set_off_t (offset, rbuf, is64);
708 /* --------------------------- */
709 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
711 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
714 /* --------------------------- */
715 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
717 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
722 /* --------------------------- */
723 static int crlf(struct ofork *of)
727 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
728 /* no resource fork or no finderinfo, use our files extension mapping */
729 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
732 /* file type is TEXT */
735 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
742 static ssize_t read_file(struct ofork *ofork, int eid,
743 off_t offset, u_char nlmask,
744 u_char nlchar, char *rbuf,
745 size_t *rbuflen, const int xlate)
751 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
753 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
755 return( AFPERR_PARAM );
757 if ( (size_t)cc < *rbuflen ) {
765 for ( p = rbuf, q = p + cc; p < q; ) {
766 if (( *p++ & nlmask ) == nlchar ) {
777 * If this file is of type TEXT, then swap \012 to \015.
780 for ( p = rbuf, q = p + cc; p < q; p++ ) {
781 if ( *p == '\012' ) {
783 } else if ( *p == '\015' ) {
792 return( AFPERR_EOF );
797 /* -----------------------------
798 * with ddp, afp_read can return fewer bytes than in reqcount
799 * so return EOF only if read actually past end of file not
800 * if offset +reqcount > size of file
802 * getfork size ==> 10430
803 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
804 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
805 * read fork offset 9248 size 1508 ==> 1182 (EOF)
806 * 10752 is a bug in Mac 7.5.x finder
808 * with dsi, should we check that reqcount < server quantum?
810 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
813 off_t offset, saveoff, reqcount, savereqcount;
817 u_char nlmask, nlchar;
820 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
821 ibuf += sizeof( u_short );
823 if (NULL == ( ofork = of_find( ofrefnum )) ) {
824 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
829 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
833 offset = get_off_t(&ibuf, is64);
834 reqcount = get_off_t(&ibuf, is64);
836 LOG(log_debug, logtype_afpd,
837 "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
838 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
839 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
848 /* if we wanted to be picky, we could add in the following
849 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
851 if (reqcount < 0 || offset < 0) {
856 if ( ofork->of_flags & AFPFORK_DATA) {
858 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
859 } else if (ofork->of_flags & AFPFORK_RSRC) {
861 } else { /* fork wasn't opened. this should never really happen. */
866 /* zero request count */
872 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
873 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
875 savereqcount = reqcount;
877 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
883 #define min(a,b) ((a)<(b)?(a):(b))
884 *rbuflen = min( reqcount, *rbuflen );
886 *rbuflen = MIN(reqcount, *rbuflen);
887 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
888 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
889 >>>>>>> netafp/master
890 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
893 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
894 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
896 /* dsi can stream requests. we can only do this if we're not checking
897 * for an end-of-line character. oh well. */
898 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
899 DSI *dsi = obj->handle;
902 /* reqcount isn't always truthful. we need to deal with that. */
903 size = ad_size(ofork->of_ad, eid);
905 /* subtract off the offset */
907 if (reqcount > size) {
914 /* dsi_readinit() returns size of next read buffer. by this point,
915 * we know that we're sending some data. if we fail, something
916 * horrible happened. */
917 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
920 /* due to the nature of afp packets, we have to exit if we get
921 an error. we can't do this with translation on. */
926 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
928 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
929 if (errno == EINVAL || errno == ENOSYS)
932 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
944 /* fill up our buffer. */
945 while (*rbuflen > 0) {
946 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
951 /* dsi_read() also returns buffer size of next allocation */
952 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
961 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
963 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
964 obj->exit(EXITERR_CLNT);
968 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
976 /* ---------------------- */
977 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
979 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
982 /* ---------------------- */
983 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
985 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
988 /* ---------------------- */
989 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
997 memcpy(&vid, ibuf, sizeof(vid));
998 if (NULL == ( vol = getvolbyvid( vid )) ) {
999 return( AFPERR_PARAM );
1006 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1008 struct ofork *ofork;
1013 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1015 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1016 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1017 return( AFPERR_PARAM );
1020 LOG(log_debug, logtype_afpd,
1021 "afp_flushfork(\"%s\", fork: %s)",
1022 cfrombstr(ofork->of_ad->ad_fullpath),
1023 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1025 if ( flushfork( ofork ) < 0 ) {
1026 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1034 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1035 fsync(2) on OSX is implemented differently than on other platforms.
1036 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1038 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1040 struct ofork *ofork;
1046 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1047 ibuf += sizeof( ofrefnum );
1049 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1050 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1051 return( AFPERR_PARAM );
1054 LOG(log_debug, logtype_afpd,
1055 "afp_syncfork(\"%s\", fork: %s)",
1056 cfrombstr(ofork->of_ad->ad_fullpath),
1057 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1059 if ( flushfork( ofork ) < 0 ) {
1060 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1067 /* this is very similar to closefork */
1068 int flushfork(struct ofork *ofork)
1072 int err = 0, doflush = 0;
1074 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1075 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1076 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1077 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1081 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1082 (ofork->of_flags & AFPFORK_RSRC)) {
1084 /* read in the rfork length */
1085 ad_refresh(ofork->of_ad);
1087 /* set the date if we're dirty */
1088 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1089 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1090 ofork->of_flags &= ~AFPFORK_DIRTY;
1094 /* flush the header */
1095 if (doflush && ad_flush(ofork->of_ad) < 0)
1098 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1102 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1103 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1109 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1111 struct ofork *ofork;
1116 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1118 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1119 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1120 return( AFPERR_PARAM );
1123 LOG(log_debug, logtype_afpd,
1124 "afp_closefork(\"%s\", fork: %s)",
1125 cfrombstr(ofork->of_ad->ad_fullpath),
1126 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1128 if ( of_closefork( ofork ) < 0 ) {
1129 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1130 return( AFPERR_PARAM );
1137 static ssize_t write_file(struct ofork *ofork, int eid,
1138 off_t offset, char *rbuf,
1139 size_t rbuflen, const int xlate)
1145 * If this file is of type TEXT, swap \015 to \012.
1148 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1149 if ( *p == '\015' ) {
1151 } else if ( *p == '\012' ) {
1157 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1158 rbuf, rbuflen)) < 0 ) {
1163 return( AFPERR_DFULL );
1165 return AFPERR_ACCESS;
1167 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1168 return( AFPERR_PARAM );
1176 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1177 * the client may have sent us a bunch of data that's not reflected
1178 * in reqcount et al. */
1179 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1182 struct ofork *ofork;
1183 off_t offset, saveoff, reqcount;
1184 int endflag, eid, xlate = 0, err = AFP_OK;
1187 struct ofork *ofork;
1188 off_t offset, saveoff, reqcount, oldsize, newsize;
1189 int endflag, eid, xlate = 0, err = AFP_OK;
1191 >>>>>>> netafp/master
1194 /* figure out parameters */
1196 endflag = ENDBIT(*ibuf);
1198 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1199 ibuf += sizeof( ofrefnum );
1201 offset = get_off_t(&ibuf, is64);
1202 reqcount = get_off_t(&ibuf, is64);
1204 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1205 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1210 LOG(log_debug, logtype_afpd,
1211 "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1212 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
1213 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1215 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1216 err = AFPERR_ACCESS;
1221 writtenfork = ofork;
1224 if ( ofork->of_flags & AFPFORK_DATA) {
1226 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1227 } else if (ofork->of_flags & AFPFORK_RSRC) {
1230 err = AFPERR_ACCESS; /* should never happen */
1234 oldsize = ad_size(ofork->of_ad, eid);
1238 /* handle bogus parameters */
1239 if (reqcount < 0 || offset < 0) {
1244 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1246 /* offset can overflow on 64-bit capable filesystems.
1247 * report disk full if that's going to happen. */
1248 if (sum_neg(is64, offset, reqcount)) {
1253 if (!reqcount) { /* handle request counts of 0 */
1255 *rbuflen = set_off_t (offset, rbuf, is64);
1260 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1261 reqcount, ofork->of_refnum) < 0) {
1266 /* this is yucky, but dsi can stream i/o and asp can't */
1267 switch (obj->proto) {
1270 DSI *dsi = obj->handle;
1272 /* find out what we have already and write it out. */
1273 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1274 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1275 dsi_writeflush(dsi);
1277 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1282 #if 0 /*def HAVE_SENDFILE_WRITE*/
1283 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1284 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1285 offset, dsi->datasize)) < 0) {
1293 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1294 goto afp_write_loop;
1296 dsi_writeflush(dsi);
1298 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1299 reqcount, ofork->of_refnum);
1304 goto afp_write_done;
1306 #endif /* 0, was HAVE_SENDFILE_WRITE */
1308 /* loop until everything gets written. currently
1309 * dsi_write handles the end case by itself. */
1310 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1311 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1312 dsi_writeflush(dsi);
1314 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1315 reqcount, ofork->of_refnum);
1324 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1325 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1326 ofork->of_flags |= AFPFORK_DIRTY;
1328 /* we have modified any fork, remember until close_fork */
1329 ofork->of_flags |= AFPFORK_MODIFIED;
1331 /* update write count */
1332 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1334 *rbuflen = set_off_t (offset, rbuf, is64);
1338 if (obj->proto == AFPPROTO_DSI) {
1339 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1340 dsi_writeflush(obj->handle);
1342 if (err != AFP_OK) {
1348 /* ---------------------------- */
1349 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1351 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1354 /* ----------------------------
1355 * FIXME need to deal with SIGXFSZ signal
1357 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1359 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1362 /* ---------------------------- */
1363 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1365 struct ofork *ofork;
1367 uint16_t ofrefnum, bitmap;
1370 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1371 ibuf += sizeof( ofrefnum );
1372 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1373 bitmap = ntohs( bitmap );
1374 ibuf += sizeof( bitmap );
1377 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1378 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1379 return( AFPERR_PARAM );
1382 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1383 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1384 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1385 return( AFPERR_PARAM );
1389 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1390 rbuf + sizeof( u_short ), &buflen ))) {
1394 *rbuflen = buflen + sizeof( u_short );
1395 bitmap = htons( bitmap );
1396 memcpy(rbuf, &bitmap, sizeof( bitmap ));