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 static off_t get_off_t(char **ibuf, int is64)
105 memcpy(&temp, *ibuf, sizeof( temp ));
106 ret = ntohl(temp); /* ntohl is unsigned */
107 *ibuf += sizeof(temp);
110 memcpy(&temp, *ibuf, sizeof( temp ));
111 *ibuf += sizeof(temp);
112 ret = ntohl(temp)| (ret << 32);
115 ret = (int)ret; /* sign extend */
120 static int set_off_t(off_t offset, char *rbuf, int is64)
127 temp = htonl(offset >> 32);
128 memcpy(rbuf, &temp, sizeof( temp ));
129 rbuf += sizeof(temp);
130 ret = sizeof( temp );
131 offset &= 0xffffffff;
133 temp = htonl(offset);
134 memcpy(rbuf, &temp, sizeof( temp ));
135 ret += sizeof( temp );
140 static int is_neg(int is64, off_t val)
142 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
147 static int sum_neg(int is64, off_t offset, off_t reqcount)
149 if (is_neg(is64, offset +reqcount) )
154 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
162 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
163 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_NONE, 1, ofrefnum);
166 if ((access & (OPENACC_RD | OPENACC_DRD))) {
167 if ((readset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
169 if ((denyreadset = ad_testlock(adp, eid, AD_FILELOCK_DENY_RD)) <0)
172 if ((access & OPENACC_RD) && denyreadset) {
176 if ((access & OPENACC_DRD) && readset) {
180 /* boolean logic is not enough, because getforkmode is not always telling the
183 if ((access & OPENACC_RD)) {
184 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_RD, 1, ofrefnum);
188 if ((access & OPENACC_DRD)) {
189 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_RD, 1, ofrefnum);
194 /* ------------same for writing -------------- */
195 if ((access & (OPENACC_WR | OPENACC_DWR))) {
196 if ((writeset = ad_testlock(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
198 if ((denywriteset = ad_testlock(adp, eid, AD_FILELOCK_DENY_WR)) <0)
201 if ((access & OPENACC_WR) && denywriteset) {
205 if ((access & OPENACC_DWR) && writeset) {
209 if ((access & OPENACC_WR)) {
210 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_OPEN_WR, 1, ofrefnum);
214 if ((access & OPENACC_DWR)) {
215 ret = ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, AD_FILELOCK_DENY_WR, 1, ofrefnum);
220 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
221 return ad_excl_lock(adp, eid);
226 /* ----------------------- */
227 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
231 struct ofork *ofork, *opened;
232 struct adouble *adsame = NULL;
234 int ret, adflags, eid;
236 uint16_t vid, bitmap, access, ofrefnum;
237 char fork, *path, *upath;
244 memcpy(&vid, ibuf, sizeof( vid ));
248 if (NULL == ( vol = getvolbyvid( vid ))) {
249 return( AFPERR_PARAM );
252 memcpy(&did, ibuf, sizeof( did ));
253 ibuf += sizeof( int );
255 if (NULL == ( dir = dirlookup( vol, did ))) {
259 memcpy(&bitmap, ibuf, sizeof( bitmap ));
260 bitmap = ntohs( bitmap );
261 ibuf += sizeof( bitmap );
262 memcpy(&access, ibuf, sizeof( access ));
263 access = ntohs( access );
264 ibuf += sizeof( access );
266 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
270 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
271 return get_afp_errno(AFPERR_PARAM);
274 if (*s_path->m_name == '\0') {
276 return AFPERR_BADTYPE;
279 LOG(log_debug, logtype_afpd,
280 "afp_openfork(\"%s\", %s)",
281 abspath(s_path->u_name),
282 (fork & OPENFORK_RSCS) ? "OPENFORK_RSCS" : "OPENFORK_DATA");
284 /* stat() data fork st is set because it's not a dir */
285 switch ( s_path->st_errno ) {
291 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
293 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
296 /* FIXME should we check it first ? */
297 upath = s_path->u_name;
298 if (!vol_unix_priv(vol)) {
299 if (check_access(upath, access ) < 0) {
300 return AFPERR_ACCESS;
303 if (file_access(s_path, access ) < 0) {
304 return AFPERR_ACCESS;
309 /* XXX: this probably isn't the best way to do this. the already
310 open bits should really be set if the fork is opened by any
311 program, not just this one. however, that's problematic to do
312 if we can't write lock files somewhere. opened is also passed to
313 ad_open so that we can keep file locks together.
314 FIXME: add the fork we are opening?
316 if ((opened = of_findname(s_path))) {
317 adsame = opened->of_ad;
320 if ( fork == OPENFORK_DATA ) {
322 adflags = ADFLAGS_DF | ADFLAGS_HF ;
325 adflags = ADFLAGS_RF | ADFLAGS_HF;
328 path = s_path->m_name;
329 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
330 adsame, st)) == NULL ) {
331 return( AFPERR_NFILE );
335 if (access & OPENACC_WR) {
336 /* try opening in read-write mode */
337 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
345 if (fork == OPENFORK_DATA) {
346 /* try to open only the data fork */
347 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
350 adflags = ADFLAGS_DF;
352 /* here's the deal. we only try to create the resource
353 * fork if the user wants to open it for write acess. */
354 if (ad_open(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
356 ofork->of_flags |= AFPFORK_OPEN;
365 ret = AFPERR_BADTYPE;
369 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) );
376 /* the ressource fork is open too */
377 ofork->of_flags |= AFPFORK_OPEN;
380 /* try opening in read-only mode */
382 if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
390 /* see if client asked for a read only data fork */
391 if (fork == OPENFORK_DATA) {
392 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
395 adflags = ADFLAGS_DF;
397 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
398 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
399 * then create in open read-write.
400 * FIXME , it doesn't play well with byte locking example:
401 * ressource fork open read only
402 * locking set on it (no effect, there's no file!)
403 * ressource fork open read write now
412 ret = AFPERR_BADTYPE;
416 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
417 abspath(s_path->m_name), strerror(errno) );
423 /* the ressource fork is open too */
424 ofork->of_flags |= AFPFORK_OPEN;
428 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
429 if (ad_setname(ofork->of_ad, path)) {
430 ad_flush( ofork->of_ad );
434 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
435 ad_close( ofork->of_ad, adflags );
439 *rbuflen = buflen + 2 * sizeof( u_int16_t );
440 bitmap = htons( bitmap );
441 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
442 rbuf += sizeof( u_int16_t );
444 /* check WriteInhibit bit if we have a ressource fork
445 * the test is done here, after some Mac trafic capture
447 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
448 ad_getattr(ofork->of_ad, &bshort);
449 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
450 ad_close( ofork->of_ad, adflags );
453 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
454 return(AFPERR_OLOCK);
459 * synchronization locks:
462 /* don't try to lock non-existent rforks. */
463 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
465 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
466 /* can we access the fork? */
469 ad_close( ofork->of_ad, adflags );
472 case EAGAIN: /* return data anyway */
476 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
477 return( AFPERR_DENYCONF );
481 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
482 return( AFPERR_PARAM );
485 if ((access & OPENACC_WR))
486 ofork->of_flags |= AFPFORK_ACCWR;
488 /* the file may be open read only without ressource fork */
489 if ((access & OPENACC_RD))
490 ofork->of_flags |= AFPFORK_ACCRD;
492 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
498 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
502 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
506 u_int16_t ofrefnum, bitmap;
514 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
515 ibuf += sizeof( ofrefnum );
517 memcpy(&bitmap, ibuf, sizeof(bitmap));
518 bitmap = ntohs(bitmap);
519 ibuf += sizeof( bitmap );
522 if (NULL == ( ofork = of_find( ofrefnum )) ) {
523 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
524 return( AFPERR_PARAM );
527 if (ofork->of_vol->v_flags & AFPVOL_RO)
530 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
531 return AFPERR_ACCESS;
533 if ( ofork->of_flags & AFPFORK_DATA) {
535 } else if (ofork->of_flags & AFPFORK_RSRC) {
540 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
541 && eid == ADEID_RFORK
543 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
544 && eid == ADEID_DFORK)) {
545 return AFPERR_BITMAP;
549 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
550 if (afp_version >= 30) {
554 return AFPERR_BITMAP;
557 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
558 return AFPERR_PARAM ;
560 size = get_off_t(&ibuf, is64);
563 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
566 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
567 st_size = ad_size(ofork->of_ad, eid);
569 if (st_size > size &&
570 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
571 goto afp_setfork_err;
573 err = ad_dtruncate( ofork->of_ad, size );
575 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
577 goto afp_setfork_err;
578 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
579 ad_refresh( ofork->of_ad );
581 st_size = ad_size(ofork->of_ad, eid);
583 if (st_size > size &&
584 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
585 goto afp_setfork_err;
587 err = ad_rtruncate(ofork->of_ad, size);
589 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
591 goto afp_setfork_err;
593 if (ad_flush( ofork->of_ad ) < 0) {
594 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
598 return AFPERR_BITMAP;
601 if ( flushfork( ofork ) < 0 ) {
602 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
617 return AFPERR_ACCESS;
628 /* for this to work correctly, we need to check for locks before each
629 * read and write. that's most easily handled by always doing an
630 * appropriate check before each ad_read/ad_write. other things
631 * that can change files like truncate are handled internally to those
634 #define ENDBIT(a) ((a) & 0x80)
635 #define UNLOCKBIT(a) ((a) & 0x01)
638 /* ---------------------- */
639 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
642 off_t offset, length;
650 /* figure out parameters */
652 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
654 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
655 ibuf += sizeof(ofrefnum);
657 if (NULL == ( ofork = of_find( ofrefnum )) ) {
658 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
659 return( AFPERR_PARAM );
662 if ( ofork->of_flags & AFPFORK_DATA) {
664 } else if (ofork->of_flags & AFPFORK_RSRC) {
669 offset = get_off_t(&ibuf, is64);
670 length = get_off_t(&ibuf, is64);
672 /* FIXME AD_FILELOCK test is surely wrong */
674 length = BYTELOCK_MAX;
675 else if (!length || is_neg(is64, length)) {
677 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
682 offset += ad_size(ofork->of_ad, eid);
683 /* FIXME what do we do if file size > 2 GB and
684 it's not byte_lock_ext?
687 if (offset < 0) /* error if we have a negative offset */
690 /* if the file is a read-only file, we use read locks instead of
691 * write locks. that way, we can prevent anyone from initiating
693 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
694 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
695 ofork->of_refnum) < 0) {
699 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
705 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
713 *rbuflen = set_off_t (offset, rbuf, is64);
717 /* --------------------------- */
718 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
720 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
723 /* --------------------------- */
724 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
726 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
731 /* --------------------------- */
732 static int crlf(struct ofork *of)
736 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
737 /* no resource fork or no finderinfo, use our files extension mapping */
738 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
741 /* file type is TEXT */
744 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
751 static ssize_t read_file(struct ofork *ofork, int eid,
752 off_t offset, u_char nlmask,
753 u_char nlchar, char *rbuf,
754 size_t *rbuflen, const int xlate)
760 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
762 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
764 return( AFPERR_PARAM );
766 if ( (size_t)cc < *rbuflen ) {
774 for ( p = rbuf, q = p + cc; p < q; ) {
775 if (( *p++ & nlmask ) == nlchar ) {
786 * If this file is of type TEXT, then swap \012 to \015.
789 for ( p = rbuf, q = p + cc; p < q; p++ ) {
790 if ( *p == '\012' ) {
792 } else if ( *p == '\015' ) {
801 return( AFPERR_EOF );
806 /* -----------------------------
807 * with ddp, afp_read can return fewer bytes than in reqcount
808 * so return EOF only if read actually past end of file not
809 * if offset +reqcount > size of file
811 * getfork size ==> 10430
812 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
813 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
814 * read fork offset 9248 size 1508 ==> 1182 (EOF)
815 * 10752 is a bug in Mac 7.5.x finder
817 * with dsi, should we check that reqcount < server quantum?
819 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
822 off_t offset, saveoff, reqcount, savereqcount;
826 u_char nlmask, nlchar;
829 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
830 ibuf += sizeof( u_short );
832 if (NULL == ( ofork = of_find( ofrefnum )) ) {
833 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
838 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
842 offset = get_off_t(&ibuf, is64);
843 reqcount = get_off_t(&ibuf, is64);
845 LOG(log_debug, logtype_afpd,
846 "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
847 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
848 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
857 /* if we wanted to be picky, we could add in the following
858 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
860 if (reqcount < 0 || offset < 0) {
865 if ( ofork->of_flags & AFPFORK_DATA) {
867 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
868 } else if (ofork->of_flags & AFPFORK_RSRC) {
870 } else { /* fork wasn't opened. this should never really happen. */
875 /* zero request count */
881 savereqcount = reqcount;
883 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
888 #define min(a,b) ((a)<(b)?(a):(b))
889 *rbuflen = min( reqcount, *rbuflen );
890 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
894 /* dsi can stream requests. we can only do this if we're not checking
895 * for an end-of-line character. oh well. */
896 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
897 DSI *dsi = obj->handle;
900 /* reqcount isn't always truthful. we need to deal with that. */
901 size = ad_size(ofork->of_ad, eid);
903 /* subtract off the offset */
905 if (reqcount > size) {
912 /* dsi_readinit() returns size of next read buffer. by this point,
913 * we know that we're sending some data. if we fail, something
914 * horrible happened. */
915 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
918 /* due to the nature of afp packets, we have to exit if we get
919 an error. we can't do this with translation on. */
921 if (!(xlate || Debug(obj) )) {
924 fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
925 if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
926 if (errno == EINVAL || errno == ENOSYS)
929 LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno));
941 /* fill up our buffer. */
942 while (*rbuflen > 0) {
943 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,rbuflen, xlate);
949 if (obj->options.flags & OPTION_DEBUG) {
950 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
951 bprint(rbuf, *rbuflen);
954 /* dsi_read() also returns buffer size of next allocation */
955 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
964 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
966 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
967 obj->exit(EXITERR_CLNT);
971 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
979 /* ---------------------- */
980 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
982 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
985 /* ---------------------- */
986 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
988 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
991 /* ---------------------- */
992 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1000 memcpy(&vid, ibuf, sizeof(vid));
1001 if (NULL == ( vol = getvolbyvid( vid )) ) {
1002 return( AFPERR_PARAM );
1009 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1011 struct ofork *ofork;
1016 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1018 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1019 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1020 return( AFPERR_PARAM );
1023 LOG(log_debug, logtype_afpd,
1024 "afp_flushfork(\"%s\", fork: %s)",
1025 cfrombstr(ofork->of_ad->ad_fullpath),
1026 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1028 if ( flushfork( ofork ) < 0 ) {
1029 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1037 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1038 fsync(2) on OSX is implemented differently than on other platforms.
1039 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1041 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1043 struct ofork *ofork;
1049 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1050 ibuf += sizeof( ofrefnum );
1052 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1053 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1054 return( AFPERR_PARAM );
1057 LOG(log_debug, logtype_afpd,
1058 "afp_syncfork(\"%s\", fork: %s)",
1059 cfrombstr(ofork->of_ad->ad_fullpath),
1060 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1062 if ( flushfork( ofork ) < 0 ) {
1063 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1070 /* this is very similar to closefork */
1071 int flushfork(struct ofork *ofork)
1075 int err = 0, doflush = 0;
1077 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1078 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1079 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1080 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1084 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1085 (ofork->of_flags & AFPFORK_RSRC)) {
1087 /* read in the rfork length */
1088 ad_refresh(ofork->of_ad);
1090 /* set the date if we're dirty */
1091 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1092 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1093 ofork->of_flags &= ~AFPFORK_DIRTY;
1097 /* flush the header */
1098 if (doflush && ad_flush(ofork->of_ad) < 0)
1101 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1105 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1106 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1112 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1114 struct ofork *ofork;
1119 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1121 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1122 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1123 return( AFPERR_PARAM );
1126 LOG(log_debug, logtype_afpd,
1127 "afp_closefork(\"%s\", fork: %s)",
1128 cfrombstr(ofork->of_ad->ad_fullpath),
1129 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1131 if ( of_closefork( ofork ) < 0 ) {
1132 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1133 return( AFPERR_PARAM );
1140 static ssize_t write_file(struct ofork *ofork, int eid,
1141 off_t offset, char *rbuf,
1142 size_t rbuflen, const int xlate)
1148 * If this file is of type TEXT, swap \015 to \012.
1151 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1152 if ( *p == '\015' ) {
1154 } else if ( *p == '\012' ) {
1160 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1161 rbuf, rbuflen)) < 0 ) {
1166 return( AFPERR_DFULL );
1168 return AFPERR_ACCESS;
1170 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1171 return( AFPERR_PARAM );
1179 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1180 * the client may have sent us a bunch of data that's not reflected
1181 * in reqcount et al. */
1182 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1184 struct ofork *ofork;
1185 off_t offset, saveoff, reqcount;
1186 int endflag, eid, xlate = 0, err = AFP_OK;
1190 /* figure out parameters */
1192 endflag = ENDBIT(*ibuf);
1194 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1195 ibuf += sizeof( ofrefnum );
1197 offset = get_off_t(&ibuf, is64);
1198 reqcount = get_off_t(&ibuf, is64);
1200 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1201 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1206 LOG(log_debug, logtype_afpd,
1207 "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1208 cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
1209 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1211 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1212 err = AFPERR_ACCESS;
1217 writtenfork = ofork;
1220 if ( ofork->of_flags & AFPFORK_DATA) {
1222 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1223 } else if (ofork->of_flags & AFPFORK_RSRC) {
1226 err = AFPERR_ACCESS; /* should never happen */
1231 offset += ad_size(ofork->of_ad, eid);
1233 /* handle bogus parameters */
1234 if (reqcount < 0 || offset < 0) {
1239 /* offset can overflow on 64-bit capable filesystems.
1240 * report disk full if that's going to happen. */
1241 if (sum_neg(is64, offset, reqcount)) {
1246 if (!reqcount) { /* handle request counts of 0 */
1248 *rbuflen = set_off_t (offset, rbuf, is64);
1253 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1254 reqcount, ofork->of_refnum) < 0) {
1259 /* this is yucky, but dsi can stream i/o and asp can't */
1260 switch (obj->proto) {
1263 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1265 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1266 return( AFPERR_PARAM );
1270 if (obj->options.flags & OPTION_DEBUG) {
1271 printf("(write) len: %d\n", *rbuflen);
1272 bprint(rbuf, *rbuflen);
1275 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1278 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1283 #endif /* no afp/asp */
1287 DSI *dsi = obj->handle;
1289 /* find out what we have already and write it out. */
1290 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1291 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1292 dsi_writeflush(dsi);
1294 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1299 #if 0 /*def HAVE_SENDFILE_WRITE*/
1300 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1301 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1302 offset, dsi->datasize)) < 0) {
1310 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1311 goto afp_write_loop;
1313 dsi_writeflush(dsi);
1315 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1316 reqcount, ofork->of_refnum);
1321 goto afp_write_done;
1323 #endif /* 0, was HAVE_SENDFILE_WRITE */
1325 /* loop until everything gets written. currently
1326 * dsi_write handles the end case by itself. */
1327 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1328 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1329 dsi_writeflush(dsi);
1331 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1332 reqcount, ofork->of_refnum);
1341 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1342 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1343 ofork->of_flags |= AFPFORK_DIRTY;
1345 *rbuflen = set_off_t (offset, rbuf, is64);
1349 if (obj->proto == AFPPROTO_DSI) {
1350 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1351 dsi_writeflush(obj->handle);
1353 if (err != AFP_OK) {
1359 /* ---------------------------- */
1360 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1362 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1365 /* ----------------------------
1366 * FIXME need to deal with SIGXFSZ signal
1368 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1370 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1373 /* ---------------------------- */
1374 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1376 struct ofork *ofork;
1378 u_int16_t ofrefnum, bitmap;
1381 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1382 ibuf += sizeof( ofrefnum );
1383 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1384 bitmap = ntohs( bitmap );
1385 ibuf += sizeof( bitmap );
1388 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1389 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1390 return( AFPERR_PARAM );
1393 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1394 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1395 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1396 return( AFPERR_PARAM );
1400 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1401 rbuf + sizeof( u_short ), &buflen ))) {
1405 *rbuflen = buflen + sizeof( u_short );
1406 bitmap = htons( bitmap );
1407 memcpy(rbuf, &bitmap, sizeof( bitmap ));