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, "afp_openfork(\"%s\", %s)",
271 fullpathname(s_path->u_name), (fork & OPENFORK_RSCS) ? "RSRC" : "DATA");
273 /* stat() data fork st is set because it's not a dir */
274 switch ( s_path->st_errno ) {
280 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
282 LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno));
285 /* FIXME should we check it first ? */
286 upath = s_path->u_name;
287 if (!vol_unix_priv(vol)) {
288 if (check_access(upath, access ) < 0) {
289 return AFPERR_ACCESS;
292 if (file_access(s_path, access ) < 0) {
293 return AFPERR_ACCESS;
298 /* XXX: this probably isn't the best way to do this. the already
299 open bits should really be set if the fork is opened by any
300 program, not just this one. however, that's problematic to do
301 if we can't write lock files somewhere. opened is also passed to
302 ad_open so that we can keep file locks together.
303 FIXME: add the fork we are opening?
305 if ((opened = of_findname(s_path))) {
306 adsame = opened->of_ad;
309 if ( fork == OPENFORK_DATA ) {
311 adflags = ADFLAGS_DF | ADFLAGS_HF ;
314 adflags = ADFLAGS_RF | ADFLAGS_HF;
317 path = s_path->m_name;
318 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
319 adsame, st)) == NULL ) {
320 return( AFPERR_NFILE );
324 if (access & OPENACC_WR) {
325 /* try opening in read-write mode */
326 if (ad_open(ofork->of_ad, upath,
327 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) {
335 if (fork == OPENFORK_DATA) {
336 /* try to open only the data fork */
337 if (ad_open(ofork->of_ad, upath,
338 ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 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,
346 adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 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 /* we need w access for setting deny mode fcntl excl lock */
375 if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
383 /* see if client asked for a read only data fork */
384 if (fork == OPENFORK_DATA) {
385 if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) {
388 adflags = ADFLAGS_DF;
390 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
391 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
392 * then create in open read-write.
393 * FIXME , it doesn't play well with byte locking example:
394 * ressource fork open read only
395 * locking set on it (no effect, there's no file!)
396 * ressource fork open read write now
405 ret = AFPERR_BADTYPE;
409 LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
410 fullpathname(s_path->m_name), strerror(errno) );
416 /* the ressource fork is open too */
417 ofork->of_flags |= AFPFORK_OPEN;
421 if ((adflags & ADFLAGS_RF) && (ad_get_RF_flags( ofork->of_ad) & O_CREAT)) {
422 if (ad_setname(ofork->of_ad, path)) {
423 ad_flush( ofork->of_ad );
427 if ((ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof(int16_t), &buflen)) != AFP_OK) {
428 ad_close( ofork->of_ad, adflags );
432 *rbuflen = buflen + 2 * sizeof( uint16_t );
433 bitmap = htons( bitmap );
434 memcpy(rbuf, &bitmap, sizeof( uint16_t ));
435 rbuf += sizeof( uint16_t );
437 /* check WriteInhibit bit if we have a ressource fork
438 * the test is done here, after some Mac trafic capture
440 if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
441 ad_getattr(ofork->of_ad, &bshort);
442 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
443 ad_close( ofork->of_ad, adflags );
446 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
447 return(AFPERR_OLOCK);
452 * synchronization locks:
455 /* don't try to lock non-existent rforks. */
456 if ((eid == ADEID_DFORK) || (ad_meta_fileno(ofork->of_ad) != -1)) { /* META */
458 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
459 /* can we access the fork? */
462 ad_close( ofork->of_ad, adflags );
465 case EAGAIN: /* return data anyway */
469 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
470 return( AFPERR_DENYCONF );
474 LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_lock: %s", s_path->m_name, strerror(ret) );
475 return( AFPERR_PARAM );
478 if ((access & OPENACC_WR))
479 ofork->of_flags |= AFPFORK_ACCWR;
481 /* the file may be open read only without ressource fork */
482 if ((access & OPENACC_RD))
483 ofork->of_flags |= AFPFORK_ACCRD;
485 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
491 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
495 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
499 uint16_t ofrefnum, bitmap;
507 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
508 ibuf += sizeof( ofrefnum );
510 memcpy(&bitmap, ibuf, sizeof(bitmap));
511 bitmap = ntohs(bitmap);
512 ibuf += sizeof( bitmap );
515 if (NULL == ( ofork = of_find( ofrefnum )) ) {
516 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find(%d) could not locate fork", ofrefnum );
517 return( AFPERR_PARAM );
520 if (ofork->of_vol->v_flags & AFPVOL_RO)
523 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
524 return AFPERR_ACCESS;
526 if ( ofork->of_flags & AFPFORK_DATA) {
528 } else if (ofork->of_flags & AFPFORK_RSRC) {
533 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
534 && eid == ADEID_RFORK
536 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
537 && eid == ADEID_DFORK)) {
538 return AFPERR_BITMAP;
542 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
543 if (afp_version >= 30) {
547 return AFPERR_BITMAP;
550 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
551 return AFPERR_PARAM ;
553 size = get_off_t(&ibuf, is64);
556 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
559 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
560 st_size = ad_size(ofork->of_ad, eid);
562 if (st_size > size &&
563 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
564 goto afp_setfork_err;
566 err = ad_dtruncate( ofork->of_ad, size );
568 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
570 goto afp_setfork_err;
571 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
572 ad_refresh( ofork->of_ad );
574 st_size = ad_size(ofork->of_ad, eid);
576 if (st_size > size &&
577 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
578 goto afp_setfork_err;
580 err = ad_rtruncate(ofork->of_ad, size);
582 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
584 goto afp_setfork_err;
586 if (ad_flush( ofork->of_ad ) < 0) {
587 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): ad_flush: %s", of_name(ofork), strerror(errno) );
591 return AFPERR_BITMAP;
594 if ( flushfork( ofork ) < 0 ) {
595 LOG(log_error, logtype_afpd, "afp_setforkparams(%s): flushfork: %s", of_name(ofork), strerror(errno) );
610 return AFPERR_ACCESS;
621 /* for this to work correctly, we need to check for locks before each
622 * read and write. that's most easily handled by always doing an
623 * appropriate check before each ad_read/ad_write. other things
624 * that can change files like truncate are handled internally to those
627 #define ENDBIT(a) ((a) & 0x80)
628 #define UNLOCKBIT(a) ((a) & 0x01)
631 /* ---------------------- */
632 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
635 off_t offset, length;
643 /* figure out parameters */
645 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
647 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
648 ibuf += sizeof(ofrefnum);
650 if (NULL == ( ofork = of_find( ofrefnum )) ) {
651 LOG(log_error, logtype_afpd, "afp_bytelock: of_find(%d) could not locate fork", ofrefnum );
652 return( AFPERR_PARAM );
655 if ( ofork->of_flags & AFPFORK_DATA) {
657 } else if (ofork->of_flags & AFPFORK_RSRC) {
662 offset = get_off_t(&ibuf, is64);
663 length = get_off_t(&ibuf, is64);
665 /* FIXME AD_FILELOCK test is surely wrong */
667 length = BYTELOCK_MAX;
668 else if (!length || is_neg(is64, length)) {
670 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
675 offset += ad_size(ofork->of_ad, eid);
676 /* FIXME what do we do if file size > 2 GB and
677 it's not byte_lock_ext?
680 if (offset < 0) /* error if we have a negative offset */
683 /* if the file is a read-only file, we use read locks instead of
684 * write locks. that way, we can prevent anyone from initiating
686 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
687 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
688 ofork->of_refnum) < 0) {
692 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
698 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
706 *rbuflen = set_off_t (offset, rbuf, is64);
710 /* --------------------------- */
711 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
713 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
716 /* --------------------------- */
717 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
719 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
724 /* --------------------------- */
725 static int crlf(struct ofork *of)
729 if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
730 /* no resource fork or no finderinfo, use our files extension mapping */
731 if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
734 /* file type is TEXT */
737 } else if ( !memcmp( "TEXT", ad_entry( of->of_ad, ADEID_FINDERI ), 4 )) {
744 static ssize_t read_file(struct ofork *ofork, int eid,
745 off_t offset, u_char nlmask,
746 u_char nlchar, char *rbuf,
747 size_t *rbuflen, const int xlate)
753 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
755 LOG(log_error, logtype_afpd, "afp_read(%s): ad_read: %s", of_name(ofork), strerror(errno) );
757 return( AFPERR_PARAM );
759 if ( (size_t)cc < *rbuflen ) {
767 for ( p = rbuf, q = p + cc; p < q; ) {
768 if (( *p++ & nlmask ) == nlchar ) {
779 * If this file is of type TEXT, then swap \012 to \015.
782 for ( p = rbuf, q = p + cc; p < q; p++ ) {
783 if ( *p == '\012' ) {
785 } else if ( *p == '\015' ) {
794 return( AFPERR_EOF );
799 /* -----------------------------
800 * with ddp, afp_read can return fewer bytes than in reqcount
801 * so return EOF only if read actually past end of file not
802 * if offset +reqcount > size of file
804 * getfork size ==> 10430
805 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
806 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
807 * read fork offset 9248 size 1508 ==> 1182 (EOF)
808 * 10752 is a bug in Mac 7.5.x finder
810 * with dsi, should we check that reqcount < server quantum?
812 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
815 off_t offset, saveoff, reqcount, savereqcount;
819 u_char nlmask, nlchar;
822 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
823 ibuf += sizeof( u_short );
825 if (NULL == ( ofork = of_find( ofrefnum )) ) {
826 LOG(log_error, logtype_afpd, "afp_read: of_find(%d) could not locate fork", ofrefnum );
831 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
835 offset = get_off_t(&ibuf, is64);
836 reqcount = get_off_t(&ibuf, is64);
838 LOG(log_debug, logtype_afpd,
839 "afp_read(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", 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 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)",
874 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount);
876 savereqcount = reqcount;
878 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
883 *rbuflen = MIN(reqcount, *rbuflen);
884 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): reading %jd bytes from file",
885 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
887 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
890 LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file",
891 of_name(ofork), (intmax_t)offset, (intmax_t)reqcount, (intmax_t)*rbuflen);
893 /* dsi can stream requests. we can only do this if we're not checking
894 * for an end-of-line character. oh well. */
895 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
896 DSI *dsi = obj->handle;
899 /* reqcount isn't always truthful. we need to deal with that. */
900 size = ad_size(ofork->of_ad, eid);
902 /* subtract off the offset */
904 if (reqcount > size) {
911 /* dsi_readinit() returns size of next read buffer. by this point,
912 * we know that we're sending some data. if we fail, something
913 * horrible happened. */
914 if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
917 /* due to the nature of afp packets, we have to exit if we get
918 an error. we can't do this with translation on. */
923 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);
948 /* dsi_read() also returns buffer size of next allocation */
949 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
958 LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
960 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
961 obj->exit(EXITERR_CLNT);
965 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
973 /* ---------------------- */
974 int afp_read(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
976 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
979 /* ---------------------- */
980 int afp_read_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
982 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
985 /* ---------------------- */
986 int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
994 memcpy(&vid, ibuf, sizeof(vid));
995 if (NULL == ( vol = getvolbyvid( vid )) ) {
996 return( AFPERR_PARAM );
1003 int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1005 struct ofork *ofork;
1010 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1012 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1013 LOG(log_error, logtype_afpd, "afp_flushfork: of_find(%d) could not locate fork", ofrefnum );
1014 return( AFPERR_PARAM );
1017 LOG(log_debug, logtype_afpd, "afp_flushfork(fork: %s)",
1018 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1020 if ( flushfork( ofork ) < 0 ) {
1021 LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
1029 There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
1030 fsync(2) on OSX is implemented differently than on other platforms.
1031 see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
1033 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1035 struct ofork *ofork;
1041 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
1042 ibuf += sizeof( ofrefnum );
1044 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1045 LOG(log_error, logtype_afpd, "afpd_syncfork: of_find(%d) could not locate fork", ofrefnum );
1046 return( AFPERR_PARAM );
1049 LOG(log_debug, logtype_afpd, "afp_syncfork(fork: %s)",
1050 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1052 if ( flushfork( ofork ) < 0 ) {
1053 LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
1060 /* this is very similar to closefork */
1061 int flushfork(struct ofork *ofork)
1065 int err = 0, doflush = 0;
1067 if ( ad_data_fileno( ofork->of_ad ) != -1 &&
1068 fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
1069 LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
1070 of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
1074 if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
1075 (ofork->of_flags & AFPFORK_RSRC)) {
1077 /* read in the rfork length */
1078 ad_refresh(ofork->of_ad);
1080 /* set the date if we're dirty */
1081 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1082 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1083 ofork->of_flags &= ~AFPFORK_DIRTY;
1087 /* flush the header */
1088 if (doflush && ad_flush(ofork->of_ad) < 0)
1091 if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
1095 LOG(log_error, logtype_afpd, "flushfork(%s): hfile(%d) %s",
1096 of_name(ofork), ad_reso_fileno(ofork->of_ad), strerror(errno) );
1102 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1104 struct ofork *ofork;
1109 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1111 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1112 LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
1113 return( AFPERR_PARAM );
1116 LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)",
1117 (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
1119 if ( of_closefork( ofork ) < 0 ) {
1120 LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
1121 return( AFPERR_PARAM );
1128 static ssize_t write_file(struct ofork *ofork, int eid,
1129 off_t offset, char *rbuf,
1130 size_t rbuflen, const int xlate)
1136 * If this file is of type TEXT, swap \015 to \012.
1139 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1140 if ( *p == '\015' ) {
1142 } else if ( *p == '\012' ) {
1148 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1149 rbuf, rbuflen)) < 0 ) {
1154 return( AFPERR_DFULL );
1156 return AFPERR_ACCESS;
1158 LOG(log_error, logtype_afpd, "afp_write(%s): ad_write: %s", of_name(ofork), strerror(errno) );
1159 return( AFPERR_PARAM );
1167 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1168 * the client may have sent us a bunch of data that's not reflected
1169 * in reqcount et al. */
1170 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
1172 struct ofork *ofork;
1173 off_t offset, saveoff, reqcount, oldsize, newsize;
1174 int endflag, eid, xlate = 0, err = AFP_OK;
1178 /* figure out parameters */
1180 endflag = ENDBIT(*ibuf);
1182 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1183 ibuf += sizeof( ofrefnum );
1185 offset = get_off_t(&ibuf, is64);
1186 reqcount = get_off_t(&ibuf, is64);
1188 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1189 LOG(log_error, logtype_afpd, "afp_write: of_find(%d) could not locate fork", ofrefnum );
1194 LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
1195 offset, reqcount, (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 */
1216 oldsize = ad_size(ofork->of_ad, eid);
1220 /* handle bogus parameters */
1221 if (reqcount < 0 || offset < 0) {
1226 newsize = ((offset + reqcount) > oldsize) ? (offset + reqcount) : oldsize;
1228 /* offset can overflow on 64-bit capable filesystems.
1229 * report disk full if that's going to happen. */
1230 if (sum_neg(is64, offset, reqcount)) {
1235 if (!reqcount) { /* handle request counts of 0 */
1237 *rbuflen = set_off_t (offset, rbuf, is64);
1242 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1243 reqcount, ofork->of_refnum) < 0) {
1248 /* this is yucky, but dsi can stream i/o and asp can't */
1249 switch (obj->proto) {
1252 DSI *dsi = obj->handle;
1254 /* find out what we have already and write it out. */
1255 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1256 if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1257 dsi_writeflush(dsi);
1259 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1264 #if 0 /*def HAVE_SENDFILE_WRITE*/
1265 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1266 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1267 offset, dsi->datasize)) < 0) {
1275 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1276 goto afp_write_loop;
1278 dsi_writeflush(dsi);
1280 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1281 reqcount, ofork->of_refnum);
1286 goto afp_write_done;
1288 #endif /* 0, was HAVE_SENDFILE_WRITE */
1290 /* loop until everything gets written. currently
1291 * dsi_write handles the end case by itself. */
1292 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1293 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1294 dsi_writeflush(dsi);
1296 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1297 reqcount, ofork->of_refnum);
1306 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1307 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */
1308 ofork->of_flags |= AFPFORK_DIRTY;
1310 /* we have modified any fork, remember until close_fork */
1311 ofork->of_flags |= AFPFORK_MODIFIED;
1313 /* update write count */
1314 ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0;
1316 *rbuflen = set_off_t (offset, rbuf, is64);
1320 if (obj->proto == AFPPROTO_DSI) {
1321 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1322 dsi_writeflush(obj->handle);
1324 if (err != AFP_OK) {
1330 /* ---------------------------- */
1331 int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1333 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1336 /* ----------------------------
1337 * FIXME need to deal with SIGXFSZ signal
1339 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
1341 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1344 /* ---------------------------- */
1345 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
1347 struct ofork *ofork;
1349 uint16_t ofrefnum, bitmap;
1352 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1353 ibuf += sizeof( ofrefnum );
1354 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1355 bitmap = ntohs( bitmap );
1356 ibuf += sizeof( bitmap );
1359 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1360 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find(%d) could not locate fork", ofrefnum );
1361 return( AFPERR_PARAM );
1364 if ( ad_meta_fileno( ofork->of_ad ) != -1 ) { /* META */
1365 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1366 LOG(log_error, logtype_afpd, "getforkparams(%s): ad_refresh: %s", of_name(ofork), strerror(errno) );
1367 return( AFPERR_PARAM );
1371 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1372 rbuf + sizeof( u_short ), &buflen ))) {
1376 *rbuflen = buflen + sizeof( u_short );
1377 bitmap = htons( bitmap );
1378 memcpy(rbuf, &bitmap, sizeof( bitmap ));