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/atp.h>
22 #include <atalk/asp.h>
23 #include <atalk/afp.h>
24 #include <atalk/adouble.h>
25 #include <atalk/logger.h>
26 #include <atalk/util.h>
27 #include <atalk/cnid.h>
28 #include <atalk/bstradd.h>
33 #include "directory.h"
38 #define Debug(a) ((a)->options.flags & OPTION_DEBUG)
44 struct ofork *writtenfork;
47 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
57 /* can only get the length of the opened fork */
58 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
59 && (ofork->of_flags & AFPFORK_RSRC))
61 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
62 && (ofork->of_flags & AFPFORK_DATA))) {
63 return( AFPERR_BITMAP );
66 if ( ad_reso_fileno( ofork->of_ad ) == -1 ) { /* META ? */
73 dir = dirlookup(vol, ofork->of_did);
75 if (NULL == (path.u_name = mtoupath(vol, of_name(ofork), dir->d_did, utf8_encoding()))) {
76 return( AFPERR_MISC );
78 path.m_name = of_name(ofork);
81 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
82 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
83 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
84 if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
85 /* 0 is for symlink */
86 if (movecwd(vol, dir) < 0)
87 return( AFPERR_NOOBJ );
88 if ( lstat( path.u_name, st ) < 0 )
89 return( AFPERR_NOOBJ );
91 if ( fstat( ad_data_fileno( ofork->of_ad ), st ) < 0 ) {
92 return( AFPERR_BITMAP );
96 return getmetadata(vol, bitmap, &path, dir, buf, buflen, adp );
99 /* ---------------------------- */
100 static off_t get_off_t(char **ibuf, int is64)
106 memcpy(&temp, *ibuf, sizeof( temp ));
107 ret = ntohl(temp); /* ntohl is unsigned */
108 *ibuf += sizeof(temp);
111 memcpy(&temp, *ibuf, sizeof( temp ));
112 *ibuf += sizeof(temp);
113 ret = ntohl(temp)| (ret << 32);
116 ret = (int)ret; /* sign extend */
121 /* ---------------------- */
122 static int set_off_t(off_t offset, char *rbuf, int is64)
129 temp = htonl(offset >> 32);
130 memcpy(rbuf, &temp, sizeof( temp ));
131 rbuf += sizeof(temp);
132 ret = sizeof( temp );
133 offset &= 0xffffffff;
135 temp = htonl(offset);
136 memcpy(rbuf, &temp, sizeof( temp ));
137 ret += sizeof( temp );
142 /* ------------------------
144 static int is_neg(int is64, off_t val)
146 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
151 static int sum_neg(int is64, off_t offset, off_t reqcount)
153 if (is_neg(is64, offset +reqcount) )
158 /* -------------------------
160 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
162 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
165 /* -------------------------
167 int getforkmode(struct adouble *adp, int eid, int what)
169 return ad_testlock(adp, eid, what);
172 /* -------------------------
174 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
182 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
183 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
186 if ((access & (OPENACC_RD | OPENACC_DRD))) {
187 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
189 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
192 if ((access & OPENACC_RD) && denyreadset) {
196 if ((access & OPENACC_DRD) && readset) {
200 /* boolean logic is not enough, because getforkmode is not always telling the
203 if ((access & OPENACC_RD)) {
204 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
208 if ((access & OPENACC_DRD)) {
209 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
214 /* ------------same for writing -------------- */
215 if ((access & (OPENACC_WR | OPENACC_DWR))) {
216 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
218 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
221 if ((access & OPENACC_WR) && denywriteset) {
225 if ((access & OPENACC_DWR) && writeset) {
229 if ((access & OPENACC_WR)) {
230 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
234 if ((access & OPENACC_DWR)) {
235 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
240 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
241 return ad_excl_lock(adp, eid);
246 /* ----------------------- */
247 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
251 struct ofork *ofork, *opened;
252 struct adouble *adsame = NULL;
254 int ret, adflags, eid;
256 uint16_t vid, bitmap, access, ofrefnum;
257 char fork, *path, *upath;
264 memcpy(&vid, ibuf, sizeof( vid ));
268 if (NULL == ( vol = getvolbyvid( vid ))) {
269 return( AFPERR_PARAM );
272 memcpy(&did, ibuf, sizeof( did ));
273 ibuf += sizeof( int );
275 if (NULL == ( dir = dirlookup( vol, did ))) {
279 memcpy(&bitmap, ibuf, sizeof( bitmap ));
280 bitmap = ntohs( bitmap );
281 ibuf += sizeof( bitmap );
282 memcpy(&access, ibuf, sizeof( access ));
283 access = ntohs( access );
284 ibuf += sizeof( access );
286 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
290 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
291 return get_afp_errno(AFPERR_PARAM);
294 if (*s_path->m_name == '\0') {
296 return AFPERR_BADTYPE;
299 LOG(log_debug, logtype_afpd,
300 "afp_openfork(\"%s\", %s)",
301 abspath(s_path->u_name),
302 (fork & OPENFORK_RSCS) ? "OPENFORK_RSCS" : "OPENFORK_DATA");
304 /* stat() data fork st is set because it's not a dir */
305 switch ( s_path->st_errno ) {
311 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
313 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
316 /* FIXME should we check it first ? */
317 upath = s_path->u_name;
318 if (!vol_unix_priv(vol)) {
319 if (check_access(upath, access ) < 0) {
320 return AFPERR_ACCESS;
323 if (file_access(s_path, access ) < 0) {
324 return AFPERR_ACCESS;
329 /* XXX: this probably isn't the best way to do this. the already
330 open bits should really be set if the fork is opened by any
331 program, not just this one. however, that's problematic to do
332 if we can't write lock files somewhere. opened is also passed to
333 ad_open so that we can keep file locks together.
334 FIXME: add the fork we are opening?
336 if ((opened = of_findname(s_path))) {
337 adsame = opened->of_ad;
340 if ( fork == OPENFORK_DATA ) {
342 adflags = ADFLAGS_DF | ADFLAGS_HF ;
345 adflags = ADFLAGS_RF | ADFLAGS_HF;
348 path = s_path->m_name;
349 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
350 adsame, st)) == NULL ) {
351 return( AFPERR_NFILE );
355 if (access & OPENACC_WR) {
356 /* try opening in read-write mode */
357 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
365 if (fork == OPENFORK_DATA) {
366 /* try to open only the data fork */
367 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
370 adflags = ADFLAGS_DF;
372 /* here's the deal. we only try to create the resource
373 * fork if the user wants to open it for write acess. */
374 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
376 ofork->of_flags |= AFPFORK_OPEN;
385 ret = AFPERR_BADTYPE;
389 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
396 /* the ressource fork is open too */
397 ofork->of_flags |= AFPFORK_OPEN;
400 /* try opening in read-only mode */
402 if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
410 /* see if client asked for a read only data fork */
411 if (fork == OPENFORK_DATA) {
412 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
415 adflags = ADFLAGS_DF;
417 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
418 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
419 * then create in open read-write.
420 * FIXME , it doesn't play well with byte locking example:
421 * ressource fork open read only
422 * locking set on it (no effect, there's no file!)
423 * ressource fork open read write now
432 ret = AFPERR_BADTYPE;
436 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
437 abspath(s_path->m_name), strerror(errno) );
443 /* the ressource fork is open too */
444 ofork->of_flags |= AFPFORK_OPEN;
448 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
449 if (ad_setname(ofork->of_ad, path)) {
450 ad_flush( ofork->of_ad );
454 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
455 ad_close( ofork->of_ad, adflags );
459 *rbuflen = buflen + 2 * sizeof( u_int16_t );
460 bitmap = htons( bitmap );
461 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
462 rbuf += sizeof( u_int16_t );
464 /* check WriteInhibit bit if we have a ressource fork
465 * the test is done here, after some Mac trafic capture
467 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
468 ad_getattr(ofork->of_ad, &bshort);
469 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
470 ad_close( ofork->of_ad, adflags );
473 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
474 return(AFPERR_OLOCK);
479 * synchronization locks:
482 /* don't try to lock non-existent rforks. */
483 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
485 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
486 /* can we access the fork? */
489 ad_close( ofork->of_ad, adflags );
492 case EAGAIN: /* return data anyway */
496 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
497 return( AFPERR_DENYCONF );
501 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
502 return( AFPERR_PARAM );
505 if ((access & OPENACC_WR))
506 ofork->of_flags |= AFPFORK_ACCWR;
508 /* the file may be open read only without ressource fork */
509 if ((access & OPENACC_RD))
510 ofork->of_flags |= AFPFORK_ACCRD;
512 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
518 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
522 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
526 u_int16_t ofrefnum, bitmap;
534 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
535 ibuf += sizeof( ofrefnum );
537 memcpy(&bitmap, ibuf, sizeof(bitmap));
538 bitmap = ntohs(bitmap);
539 ibuf += sizeof( bitmap );
542 if (NULL == ( ofork = of_find( ofrefnum )) ) {
543 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
544 return( AFPERR_PARAM );
547 if (ofork->of_vol->v_flags & AFPVOL_RO)
550 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
551 return AFPERR_ACCESS;
553 if ( ofork->of_flags & AFPFORK_DATA) {
555 } else if (ofork->of_flags & AFPFORK_RSRC) {
560 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
561 && eid == ADEID_RFORK
563 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
564 && eid == ADEID_DFORK)) {
565 return AFPERR_BITMAP;
569 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
570 if (afp_version >= 30) {
574 return AFPERR_BITMAP;
577 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
578 return AFPERR_PARAM ;
580 size = get_off_t(&ibuf, is64);
583 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
586 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
587 st_size = ad_size(ofork->of_ad, eid);
589 if (st_size > size &&
590 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
591 goto afp_setfork_err;
593 err = ad_dtruncate( ofork->of_ad, size );
595 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
597 goto afp_setfork_err;
598 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
599 ad_refresh( ofork->of_ad );
601 st_size = ad_size(ofork->of_ad, eid);
603 if (st_size > size &&
604 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
605 goto afp_setfork_err;
607 err = ad_rtruncate(ofork->of_ad, size);
609 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
611 goto afp_setfork_err;
613 if (ad_flush( ofork->of_ad ) < 0) {
614 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
618 return AFPERR_BITMAP;
621 if ( flushfork( ofork ) < 0 ) {
622 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
637 return AFPERR_ACCESS;
648 /* for this to work correctly, we need to check for locks before each
649 * read and write. that's most easily handled by always doing an
650 * appropriate check before each ad_read/ad_write. other things
651 * that can change files like truncate are handled internally to those
654 #define ENDBIT(a) ((a) & 0x80)
655 #define UNLOCKBIT(a) ((a) & 0x01)
658 /* ---------------------- */
659 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
662 off_t offset, length;
670 /* figure out parameters */
672 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
674 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
675 ibuf += sizeof(ofrefnum);
677 if (NULL == ( ofork = of_find( ofrefnum )) ) {
678 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
679 return( AFPERR_PARAM );
682 if ( ofork->of_flags & AFPFORK_DATA) {
684 } else if (ofork->of_flags & AFPFORK_RSRC) {
689 offset = get_off_t(&ibuf, is64);
690 length = get_off_t(&ibuf, is64);
692 /* FIXME AD_FILELOCK test is surely wrong */
694 length = BYTELOCK_MAX;
695 else if (!length || is_neg(is64, length)) {
697 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
702 offset += ad_size(ofork->of_ad, eid);
703 /* FIXME what do we do if file size > 2 GB and
704 it's not byte_lock_ext?
707 if (offset < 0) /* error if we have a negative offset */
710 /* if the file is a read-only file, we use read locks instead of
711 * write locks. that way, we can prevent anyone from initiating
713 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
714 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
715 ofork->of_refnum) < 0) {
719 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
725 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
733 *rbuflen = set_off_t (offset, rbuf, is64);
737 /* --------------------------- */
738 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
740 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
743 /* --------------------------- */
744 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
746 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
751 /* --------------------------- */
752 static int crlf(struct ofork *of)
756 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
757 /* no resource fork or no finderinfo, use our files extension mapping */
758 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
761 /* file type is TEXT */
764 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
771 static ssize_t read_file(struct ofork *ofork, int eid,
772 off_t offset, u_char nlmask,
773 u_char nlchar, char *rbuf,
774 size_t *rbuflen, const int xlate)
780 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
782 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
784 return( AFPERR_PARAM );
786 if ( (size_t)cc < *rbuflen ) {
794 for ( p = rbuf, q = p + cc; p < q; ) {
795 if (( *p++ & nlmask ) == nlchar ) {
806 * If this file is of type TEXT, then swap \012 to \015.
809 for ( p = rbuf, q = p + cc; p < q; p++ ) {
810 if ( *p == '\012' ) {
812 } else if ( *p == '\015' ) {
821 return( AFPERR_EOF );
826 /* -----------------------------
827 * with ddp, afp_read can return fewer bytes than in reqcount
828 * so return EOF only if read actually past end of file not
829 * if offset +reqcount > size of file
831 * getfork size ==> 10430
832 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
833 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
834 * read fork offset 9248 size 1508 ==> 1182 (EOF)
835 * 10752 is a bug in Mac 7.5.x finder
837 * with dsi, should we check that reqcount < server quantum?
839 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
842 off_t offset, saveoff, reqcount, savereqcount;
846 u_char nlmask, nlchar;
849 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
850 ibuf += sizeof( u_short );
852 if (NULL == ( ofork = of_find( ofrefnum )) ) {
853 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
858 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
862 offset = get_off_t(&ibuf, is64);
863 reqcount = get_off_t(&ibuf, is64);
865 LOG(log_debug, logtype_afpd,
866 "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
867 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
868 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
877 /* if we wanted to be picky, we could add in the following
878 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
880 if (reqcount < 0 || offset < 0) {
885 if ( ofork->of_flags & AFPFORK_DATA) {
887 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
888 } else if (ofork->of_flags & AFPFORK_RSRC) {
890 } else { /* fork wasn't opened. this should never really happen. */
895 /* zero request count */
901 savereqcount = reqcount;
903 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
908 #define min(a,b) ((a)<(b)?(a):(b))
909 *rbuflen = min( reqcount, *rbuflen );
910 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
914 /* dsi can stream requests. we can only do this if we're not checking
915 * for an end-of-line character. oh well. */
916 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
917 DSI *dsi = obj->handle;
920 /* reqcount isn't always truthful. we need to deal with that. */
921 size = ad_size(ofork->of_ad, eid);
923 /* subtract off the offset */
925 if (reqcount > size) {
932 /* dsi_readinit() returns size of next read buffer. by this point,
933 * we know that we're sending some data. if we fail, something
934 * horrible happened. */
935 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
938 /* due to the nature of afp packets, we have to exit if we get
939 an error. we can't do this with translation on. */
941 if (!(xlate || Debug(obj) )) {
944 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
945 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
946 if (errno == EINVAL || errno == ENOSYS)
949 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
961 /* fill up our buffer. */
962 while (*rbuflen > 0) {
963 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
969 if (obj->options.flags & OPTION_DEBUG) {
970 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
971 bprint(rbuf, *rbuflen);
974 /* dsi_read() also returns buffer size of next allocation */
975 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
984 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
986 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
987 obj->exit(EXITERR_CLNT);
991 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
999 /* ---------------------- */
1000 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1002 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1005 /* ---------------------- */
1006 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1008 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1011 /* ---------------------- */
1012 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1020 memcpy(&vid, ibuf, sizeof(vid));
1021 if (NULL == ( vol = getvolbyvid( vid )) ) {
1022 return( AFPERR_PARAM );
1029 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1031 struct ofork *ofork;
1036 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1038 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1039 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1040 return( AFPERR_PARAM );
1043 LOG(log_debug, logtype_afpd,
1044 "afp_flushfork(\"%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, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1057 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1058 fsync(2) on OSX is implemented differently than on other platforms.
1059 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1061 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1063 struct ofork *ofork;
1069 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1070 ibuf += sizeof( ofrefnum );
1072 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1073 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1074 return( AFPERR_PARAM );
1077 LOG(log_debug, logtype_afpd,
1078 "afp_syncfork(\"%s\", fork: %s)",
1079 cfrombstr(ofork->of_ad->ad_fullpath),
1080 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1082 if ( flushfork( ofork ) < 0 ) {
1083 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1090 /* this is very similar to closefork */
1091 int flushfork(struct ofork *ofork)
1095 int err = 0, doflush = 0;
1097 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1098 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1099 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1100 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1104 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1105 (ofork->of_flags & AFPFORK_RSRC)) {
1107 /* read in the rfork length */
1108 ad_refresh(ofork->of_ad);
1110 /* set the date if we're dirty */
1111 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1112 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1113 ofork->of_flags &= ~AFPFORK_DIRTY;
1117 /* flush the header */
1118 if (doflush && ad_flush(ofork->of_ad) < 0)
1121 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1125 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1126 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1132 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1134 struct ofork *ofork;
1139 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1141 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1142 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1143 return( AFPERR_PARAM );
1146 LOG(log_debug, logtype_afpd,
1147 "afp_closefork(\"%s\", fork: %s)",
1148 cfrombstr(ofork->of_ad->ad_fullpath),
1149 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1151 if ( of_closefork( ofork ) < 0 ) {
1152 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1153 return( AFPERR_PARAM );
1160 static ssize_t write_file(struct ofork *ofork, int eid,
1161 off_t offset, char *rbuf,
1162 size_t rbuflen, const int xlate)
1168 * If this file is of type TEXT, swap \015 to \012.
1171 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1172 if ( *p == '\015' ) {
1174 } else if ( *p == '\012' ) {
1180 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1181 rbuf, rbuflen)) < 0 ) {
1186 return( AFPERR_DFULL );
1188 return AFPERR_ACCESS;
1190 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1191 return( AFPERR_PARAM );
1199 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1200 * the client may have sent us a bunch of data that's not reflected
1201 * in reqcount et al. */
1202 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1204 struct ofork *ofork;
1205 off_t offset, saveoff, reqcount;
1206 int endflag, eid, xlate = 0, err = AFP_OK;
1210 /* figure out parameters */
1212 endflag = ENDBIT(*ibuf);
1214 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1215 ibuf += sizeof( ofrefnum );
1217 offset = get_off_t(&ibuf, is64);
1218 reqcount = get_off_t(&ibuf, is64);
1220 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1221 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1226 LOG(log_debug, logtype_afpd,
1227 "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1228 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
1229 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1231 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1232 err = AFPERR_ACCESS;
1237 writtenfork = ofork;
1240 if ( ofork->of_flags & AFPFORK_DATA) {
1242 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1243 } else if (ofork->of_flags & AFPFORK_RSRC) {
1246 err = AFPERR_ACCESS; /* should never happen */
1251 offset += ad_size(ofork->of_ad, eid);
1253 /* handle bogus parameters */
1254 if (reqcount < 0 || offset < 0) {
1259 /* offset can overflow on 64-bit capable filesystems.
1260 * report disk full if that's going to happen. */
1261 if (sum_neg(is64, offset, reqcount)) {
1266 if (!reqcount) { /* handle request counts of 0 */
1268 *rbuflen = set_off_t (offset, rbuf, is64);
1273 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1274 reqcount, ofork->of_refnum) < 0) {
1279 /* this is yucky, but dsi can stream i/o and asp can't */
1280 switch (obj->proto) {
1283 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1285 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1286 return( AFPERR_PARAM );
1290 if (obj->options.flags & OPTION_DEBUG) {
1291 printf("(write) len: %d\n", *rbuflen);
1292 bprint(rbuf, *rbuflen);
1295 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1298 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1303 #endif /* no afp/asp */
1307 DSI *dsi = obj->handle;
1309 /* find out what we have already and write it out. */
1310 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1311 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1312 dsi_writeflush(dsi);
1314 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1319 #if 0 /*def HAVE_SENDFILE_WRITE*/
1320 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1321 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1322 offset, dsi->datasize)) < 0) {
1330 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1331 goto afp_write_loop;
1333 dsi_writeflush(dsi);
1335 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1336 reqcount, ofork->of_refnum);
1341 goto afp_write_done;
1343 #endif /* 0, was HAVE_SENDFILE_WRITE */
1345 /* loop until everything gets written. currently
1346 * dsi_write handles the end case by itself. */
1347 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1348 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1349 dsi_writeflush(dsi);
1351 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1352 reqcount, ofork->of_refnum);
1361 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1362 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1363 ofork->of_flags |= AFPFORK_DIRTY;
1365 *rbuflen = set_off_t (offset, rbuf, is64);
1369 if (obj->proto == AFPPROTO_DSI) {
1370 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1371 dsi_writeflush(obj->handle);
1373 if (err != AFP_OK) {
1379 /* ---------------------------- */
1380 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1382 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1385 /* ----------------------------
1386 * FIXME need to deal with SIGXFSZ signal
1388 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1390 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1393 /* ---------------------------- */
1394 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1396 struct ofork *ofork;
1398 u_int16_t ofrefnum, bitmap;
1401 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1402 ibuf += sizeof( ofrefnum );
1403 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1404 bitmap = ntohs( bitmap );
1405 ibuf += sizeof( bitmap );
1408 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1409 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1410 return( AFPERR_PARAM );
1413 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1414 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1415 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1416 return( AFPERR_PARAM );
1420 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1421 rbuf + sizeof( u_short ), &buflen ))) {
1425 *rbuflen = buflen + sizeof( u_short );
1426 bitmap = htons( bitmap );
1427 memcpy(rbuf, &bitmap, sizeof( bitmap ));