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 <netatalk/at.h>
20 #include <atalk/dsi.h>
21 #include <atalk/afp.h>
22 #include <atalk/adouble.h>
23 #include <atalk/logger.h>
24 #include <atalk/util.h>
25 #include <atalk/cnid.h>
26 #include <atalk/bstradd.h>
31 #include "directory.h"
36 struct ofork *writtenfork;
39 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
49 /* can only get the length of the opened fork */
50 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
51 && (ofork->of_flags & AFPFORK_RSRC))
53 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
54 && (ofork->of_flags & AFPFORK_DATA))) {
55 return( AFPERR_BITMAP );
58 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
65 dir = dirlookup(vol, ofork->of_did);
67 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
68 return( AFPERR_MISC );
70 path.m_name = of_name(ofork);
73 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
74 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
75 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
76 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
77 /* 0 is for symlink */
78 if (movecwd(vol, dir) < 0)
79 return( AFPERR_NOOBJ );
80 if ( lstat( path.u_name, st ) < 0 )
81 return( AFPERR_NOOBJ );
83 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
84 return( AFPERR_BITMAP );
88 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
91 static off_t get_off_t(char **ibuf, int is64)
97 memcpy(&temp, *ibuf, sizeof( temp ));
98 ret = ntohl(temp); /* ntohl is unsigned */
99 *ibuf += sizeof(temp);
102 memcpy(&temp, *ibuf, sizeof( temp ));
103 *ibuf += sizeof(temp);
104 ret = ntohl(temp)| (ret << 32);
107 ret = (int)ret; /* sign extend */
112 static int set_off_t(off_t offset, char *rbuf, int is64)
119 temp = htonl(offset >> 32);
120 memcpy(rbuf, &temp, sizeof( temp ));
121 rbuf += sizeof(temp);
122 ret = sizeof( temp );
123 offset &= 0xffffffff;
125 temp = htonl(offset);
126 memcpy(rbuf, &temp, sizeof( temp ));
127 ret += sizeof( temp );
132 static int is_neg(int is64, off_t val)
134 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
139 static int sum_neg(int is64, off_t offset, off_t reqcount)
141 if (is_neg(is64, offset +reqcount) )
146 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
154 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
155 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
158 if ((access & (OPENACC_RD | OPENACC_DRD))) {
159 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
161 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
164 if ((access & OPENACC_RD) && denyreadset) {
168 if ((access & OPENACC_DRD) && readset) {
172 /* boolean logic is not enough, because getforkmode is not always telling the
175 if ((access & OPENACC_RD)) {
176 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
180 if ((access & OPENACC_DRD)) {
181 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
186 /* ------------same for writing -------------- */
187 if ((access & (OPENACC_WR | OPENACC_DWR))) {
188 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
190 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
193 if ((access & OPENACC_WR) && denywriteset) {
197 if ((access & OPENACC_DWR) && writeset) {
201 if ((access & OPENACC_WR)) {
202 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
206 if ((access & OPENACC_DWR)) {
207 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
212 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
213 return ad_excl_lock(adp, eid);
218 /* ----------------------- */
219 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
223 struct ofork *ofork, *opened;
224 struct adouble *adsame = NULL;
226 int ret, adflags, eid;
228 uint16_t vid, bitmap, access, ofrefnum;
229 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 LOG(log_debug, logtype_afpd,
272 "afp_openfork(\"%s\", %s)",
273 abspath(s_path->u_name),
274 (fork & OPENFORK_RSCS) ? "OPENFORK_RSCS" : "OPENFORK_DATA");
276 /* stat() data fork st is set because it's not a dir */
277 switch ( s_path->st_errno ) {
283 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
285 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
288 /* FIXME should we check it first ? */
289 upath = s_path->u_name;
290 if (!vol_unix_priv(vol)) {
291 if (check_access(upath, access ) < 0) {
292 return AFPERR_ACCESS;
295 if (file_access(s_path, access ) < 0) {
296 return AFPERR_ACCESS;
301 /* XXX: this probably isn't the best way to do this. the already
302 open bits should really be set if the fork is opened by any
303 program, not just this one. however, that's problematic to do
304 if we can't write lock files somewhere. opened is also passed to
305 ad_open so that we can keep file locks together.
306 FIXME: add the fork we are opening?
308 if ((opened = of_findname(s_path))) {
309 adsame = opened->of_ad;
312 if ( fork == OPENFORK_DATA ) {
314 adflags = ADFLAGS_DF | ADFLAGS_HF ;
317 adflags = ADFLAGS_RF | ADFLAGS_HF;
320 path = s_path->m_name;
321 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
322 adsame, st)) == NULL ) {
323 return( AFPERR_NFILE );
327 if (access & OPENACC_WR) {
328 /* try opening in read-write mode */
329 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
337 if (fork == OPENFORK_DATA) {
338 /* try to open only the data fork */
339 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
342 adflags = ADFLAGS_DF;
344 /* here's the deal. we only try to create the resource
345 * fork if the user wants to open it for write acess. */
346 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
348 ofork->of_flags |= AFPFORK_OPEN;
357 ret = AFPERR_BADTYPE;
361 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
368 /* the ressource fork is open too */
369 ofork->of_flags |= AFPFORK_OPEN;
372 /* try opening in read-only mode */
374 if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
382 /* see if client asked for a read only data fork */
383 if (fork == OPENFORK_DATA) {
384 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
387 adflags = ADFLAGS_DF;
389 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
390 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
391 * then create in open read-write.
392 * FIXME , it doesn't play well with byte locking example:
393 * ressource fork open read only
394 * locking set on it (no effect, there's no file!)
395 * ressource fork open read write now
404 ret = AFPERR_BADTYPE;
408 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
409 abspath(s_path->m_name), strerror(errno) );
415 /* the ressource fork is open too */
416 ofork->of_flags |= AFPFORK_OPEN;
420 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
421 if (ad_setname(ofork->of_ad, path)) {
422 ad_flush( ofork->of_ad );
426 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
427 ad_close( ofork->of_ad, adflags );
431 *rbuflen = buflen + 2 * sizeof( u_int16_t );
432 bitmap = htons( bitmap );
433 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
434 rbuf += sizeof( u_int16_t );
436 /* check WriteInhibit bit if we have a ressource fork
437 * the test is done here, after some Mac trafic capture
439 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
440 ad_getattr(ofork->of_ad, &bshort);
441 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
442 ad_close( ofork->of_ad, adflags );
445 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
446 return(AFPERR_OLOCK);
451 * synchronization locks:
454 /* don't try to lock non-existent rforks. */
455 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
457 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
458 /* can we access the fork? */
461 ad_close( ofork->of_ad, adflags );
464 case EAGAIN: /* return data anyway */
468 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
469 return( AFPERR_DENYCONF );
473 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
474 return( AFPERR_PARAM );
477 if ((access & OPENACC_WR))
478 ofork->of_flags |= AFPFORK_ACCWR;
480 /* the file may be open read only without ressource fork */
481 if ((access & OPENACC_RD))
482 ofork->of_flags |= AFPFORK_ACCRD;
484 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
490 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
494 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
498 u_int16_t ofrefnum, bitmap;
506 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
507 ibuf += sizeof( ofrefnum );
509 memcpy(&bitmap, ibuf, sizeof(bitmap));
510 bitmap = ntohs(bitmap);
511 ibuf += sizeof( bitmap );
514 if (NULL == ( ofork = of_find( ofrefnum )) ) {
515 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
516 return( AFPERR_PARAM );
519 if (ofork->of_vol->v_flags & AFPVOL_RO)
522 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
523 return AFPERR_ACCESS;
525 if ( ofork->of_flags & AFPFORK_DATA) {
527 } else if (ofork->of_flags & AFPFORK_RSRC) {
532 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
533 && eid == ADEID_RFORK
535 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
536 && eid == ADEID_DFORK)) {
537 return AFPERR_BITMAP;
541 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
542 if (afp_version >= 30) {
546 return AFPERR_BITMAP;
549 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
550 return AFPERR_PARAM ;
552 size = get_off_t(&ibuf, is64);
555 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
558 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
559 st_size = ad_size(ofork->of_ad, eid);
561 if (st_size > size &&
562 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
563 goto afp_setfork_err;
565 err = ad_dtruncate( ofork->of_ad, size );
567 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
569 goto afp_setfork_err;
570 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
571 ad_refresh( ofork->of_ad );
573 st_size = ad_size(ofork->of_ad, eid);
575 if (st_size > size &&
576 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
577 goto afp_setfork_err;
579 err = ad_rtruncate(ofork->of_ad, size);
581 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
583 goto afp_setfork_err;
585 if (ad_flush( ofork->of_ad ) < 0) {
586 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
590 return AFPERR_BITMAP;
593 if ( flushfork( ofork ) < 0 ) {
594 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
609 return AFPERR_ACCESS;
620 /* for this to work correctly, we need to check for locks before each
621 * read and write. that's most easily handled by always doing an
622 * appropriate check before each ad_read/ad_write. other things
623 * that can change files like truncate are handled internally to those
626 #define ENDBIT(a) ((a) & 0x80)
627 #define UNLOCKBIT(a) ((a) & 0x01)
630 /* ---------------------- */
631 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
634 off_t offset, length;
642 /* figure out parameters */
644 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
646 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
647 ibuf += sizeof(ofrefnum);
649 if (NULL == ( ofork = of_find( ofrefnum )) ) {
650 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
651 return( AFPERR_PARAM );
654 if ( ofork->of_flags & AFPFORK_DATA) {
656 } else if (ofork->of_flags & AFPFORK_RSRC) {
661 offset = get_off_t(&ibuf, is64);
662 length = get_off_t(&ibuf, is64);
664 /* FIXME AD_FILELOCK test is surely wrong */
666 length = BYTELOCK_MAX;
667 else if (!length || is_neg(is64, length)) {
669 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
674 offset += ad_size(ofork->of_ad, eid);
675 /* FIXME what do we do if file size > 2 GB and
676 it's not byte_lock_ext?
679 if (offset < 0) /* error if we have a negative offset */
682 /* if the file is a read-only file, we use read locks instead of
683 * write locks. that way, we can prevent anyone from initiating
685 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
686 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
687 ofork->of_refnum) < 0) {
691 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
697 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
705 *rbuflen = set_off_t (offset, rbuf, is64);
709 /* --------------------------- */
710 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
712 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
715 /* --------------------------- */
716 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
718 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
723 /* --------------------------- */
724 static int crlf(struct ofork *of)
728 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
729 /* no resource fork or no finderinfo, use our files extension mapping */
730 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
733 /* file type is TEXT */
736 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
743 static ssize_t read_file(struct ofork *ofork, int eid,
744 off_t offset, u_char nlmask,
745 u_char nlchar, char *rbuf,
746 size_t *rbuflen, const int xlate)
752 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
754 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
756 return( AFPERR_PARAM );
758 if ( (size_t)cc < *rbuflen ) {
766 for ( p = rbuf, q = p + cc; p < q; ) {
767 if (( *p++ & nlmask ) == nlchar ) {
778 * If this file is of type TEXT, then swap \012 to \015.
781 for ( p = rbuf, q = p + cc; p < q; p++ ) {
782 if ( *p == '\012' ) {
784 } else if ( *p == '\015' ) {
793 return( AFPERR_EOF );
798 /* -----------------------------
799 * with ddp, afp_read can return fewer bytes than in reqcount
800 * so return EOF only if read actually past end of file not
801 * if offset +reqcount > size of file
803 * getfork size ==> 10430
804 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
805 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
806 * read fork offset 9248 size 1508 ==> 1182 (EOF)
807 * 10752 is a bug in Mac 7.5.x finder
809 * with dsi, should we check that reqcount < server quantum?
811 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
814 off_t offset, saveoff, reqcount, savereqcount;
818 u_char nlmask, nlchar;
821 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
822 ibuf += sizeof( u_short );
824 if (NULL == ( ofork = of_find( ofrefnum )) ) {
825 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
830 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
834 offset = get_off_t(&ibuf, is64);
835 reqcount = get_off_t(&ibuf, is64);
837 LOG(log_debug, logtype_afpd,
838 "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
839 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
840 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
849 /* if we wanted to be picky, we could add in the following
850 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
852 if (reqcount < 0 || offset < 0) {
857 if ( ofork->of_flags & AFPFORK_DATA) {
859 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
860 } else if (ofork->of_flags & AFPFORK_RSRC) {
862 } else { /* fork wasn't opened. this should never really happen. */
867 /* zero request count */
873 savereqcount = reqcount;
875 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
880 #define min(a,b) ((a)<(b)?(a):(b))
881 *rbuflen = min( reqcount, *rbuflen );
882 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
886 /* dsi can stream requests. we can only do this if we're not checking
887 * for an end-of-line character. oh well. */
888 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
889 DSI *dsi = obj->handle;
892 /* reqcount isn't always truthful. we need to deal with that. */
893 size = ad_size(ofork->of_ad, eid);
895 /* subtract off the offset */
897 if (reqcount > size) {
904 /* dsi_readinit() returns size of next read buffer. by this point,
905 * we know that we're sending some data. if we fail, something
906 * horrible happened. */
907 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
910 /* due to the nature of afp packets, we have to exit if we get
911 an error. we can't do this with translation on. */
916 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
917 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
918 if (errno == EINVAL || errno == ENOSYS)
921 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
933 /* fill up our buffer. */
934 while (*rbuflen > 0) {
935 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
940 /* dsi_read() also returns buffer size of next allocation */
941 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
950 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
952 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
953 obj->exit(EXITERR_CLNT);
957 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
965 /* ---------------------- */
966 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
968 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
971 /* ---------------------- */
972 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
974 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
977 /* ---------------------- */
978 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
986 memcpy(&vid, ibuf, sizeof(vid));
987 if (NULL == ( vol = getvolbyvid( vid )) ) {
988 return( AFPERR_PARAM );
995 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1002 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1004 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1005 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1006 return( AFPERR_PARAM );
1009 LOG(log_debug, logtype_afpd,
1010 "afp_flushfork(\"%s\", fork: %s)",
1011 cfrombstr(ofork->of_ad->ad_fullpath),
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,
1044 "afp_syncfork(\"%s\", fork: %s)",
1045 cfrombstr(ofork->of_ad->ad_fullpath),
1046 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1048 if ( flushfork( ofork ) < 0 ) {
1049 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1056 /* this is very similar to closefork */
1057 int flushfork(struct ofork *ofork)
1061 int err = 0, doflush = 0;
1063 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1064 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1065 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1066 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1070 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1071 (ofork->of_flags & AFPFORK_RSRC)) {
1073 /* read in the rfork length */
1074 ad_refresh(ofork->of_ad);
1076 /* set the date if we're dirty */
1077 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1078 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1079 ofork->of_flags &= ~AFPFORK_DIRTY;
1083 /* flush the header */
1084 if (doflush && ad_flush(ofork->of_ad) < 0)
1087 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1091 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1092 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1098 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1100 struct ofork *ofork;
1105 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1107 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1108 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1109 return( AFPERR_PARAM );
1112 LOG(log_debug, logtype_afpd,
1113 "afp_closefork(\"%s\", fork: %s)",
1114 cfrombstr(ofork->of_ad->ad_fullpath),
1115 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1117 if ( of_closefork( ofork ) < 0 ) {
1118 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1119 return( AFPERR_PARAM );
1126 static ssize_t write_file(struct ofork *ofork, int eid,
1127 off_t offset, char *rbuf,
1128 size_t rbuflen, const int xlate)
1134 * If this file is of type TEXT, swap \015 to \012.
1137 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1138 if ( *p == '\015' ) {
1140 } else if ( *p == '\012' ) {
1146 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1147 rbuf, rbuflen)) < 0 ) {
1152 return( AFPERR_DFULL );
1154 return AFPERR_ACCESS;
1156 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1157 return( AFPERR_PARAM );
1165 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1166 * the client may have sent us a bunch of data that's not reflected
1167 * in reqcount et al. */
1168 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1170 struct ofork *ofork;
1171 off_t offset, saveoff, reqcount;
1172 int endflag, eid, xlate = 0, err = AFP_OK;
1176 /* figure out parameters */
1178 endflag = ENDBIT(*ibuf);
1180 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1181 ibuf += sizeof( ofrefnum );
1183 offset = get_off_t(&ibuf, is64);
1184 reqcount = get_off_t(&ibuf, is64);
1186 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1187 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1192 LOG(log_debug, logtype_afpd,
1193 "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1194 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
1195 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1197 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1198 err = AFPERR_ACCESS;
1203 writtenfork = ofork;
1206 if ( ofork->of_flags & AFPFORK_DATA) {
1208 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1209 } else if (ofork->of_flags & AFPFORK_RSRC) {
1212 err = AFPERR_ACCESS; /* should never happen */
1217 offset += ad_size(ofork->of_ad, eid);
1219 /* handle bogus parameters */
1220 if (reqcount < 0 || offset < 0) {
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;
1251 /* find out what we have already and write it out. */
1252 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);
1261 #if 0 /*def HAVE_SENDFILE_WRITE*/
1262 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1263 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1264 offset, dsi->datasize)) < 0) {
1272 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1273 goto afp_write_loop;
1275 dsi_writeflush(dsi);
1277 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1278 reqcount, ofork->of_refnum);
1283 goto afp_write_done;
1285 #endif /* 0, was HAVE_SENDFILE_WRITE */
1287 /* loop until everything gets written. currently
1288 * dsi_write handles the end case by itself. */
1289 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1290 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1291 dsi_writeflush(dsi);
1293 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1294 reqcount, ofork->of_refnum);
1303 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1304 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1305 ofork->of_flags |= AFPFORK_DIRTY;
1307 *rbuflen = set_off_t (offset, rbuf, is64);
1311 if (obj->proto == AFPPROTO_DSI) {
1312 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1313 dsi_writeflush(obj->handle);
1315 if (err != AFP_OK) {
1321 /* ---------------------------- */
1322 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1324 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1327 /* ----------------------------
1328 * FIXME need to deal with SIGXFSZ signal
1330 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1332 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1335 /* ---------------------------- */
1336 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1338 struct ofork *ofork;
1340 u_int16_t ofrefnum, bitmap;
1343 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1344 ibuf += sizeof( ofrefnum );
1345 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1346 bitmap = ntohs( bitmap );
1347 ibuf += sizeof( bitmap );
1350 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1351 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1352 return( AFPERR_PARAM );
1355 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1356 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1357 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1358 return( AFPERR_PARAM );
1362 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1363 rbuf + sizeof( u_short ), &buflen ))) {
1367 *rbuflen = buflen + sizeof( u_short );
1368 bitmap = htons( bitmap );
1369 memcpy(rbuf, &bitmap, sizeof( bitmap ));