2 * $Id: fork.c,v 1.48 2003-01-31 17:38:01 didg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
15 #endif /* HAVE_UNISTD_H */
18 #endif /* HAVE_FCNTL_H */
22 #include <atalk/logger.h>
24 #include <sys/param.h>
26 #include <sys/types.h>
28 #include <sys/socket.h>
30 #include <netatalk/endian.h>
31 #include <netatalk/at.h>
33 #include <atalk/dsi.h>
34 #include <atalk/atp.h>
35 #include <atalk/asp.h>
36 #include <atalk/afp.h>
37 #include <atalk/adouble.h>
38 #include <atalk/util.h>
40 #include <atalk/cnid.h>
46 #include "directory.h"
50 struct ofork *writtenfork;
51 extern int getmetadata(struct vol *vol,
53 char *path, struct dir *dir, struct stat *st,
54 char *buf, int *buflen, struct adouble *adp, int attrbits );
56 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
61 const u_int16_t attrbits;
71 /* can only get the length of the opened fork */
72 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
73 && (ofork->of_flags & AFPFORK_RSRC))
75 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
76 && (ofork->of_flags & AFPFORK_DATA))) {
77 return( AFPERR_BITMAP );
80 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
89 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
90 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
91 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
92 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
93 upath = mtoupath(vol, ofork->of_name);
94 if (movecwd(vol, dir) < 0)
95 return( AFPERR_NOOBJ );
96 if ( stat( upath, &st ) < 0 )
97 return( AFPERR_NOOBJ );
99 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
100 return( AFPERR_BITMAP );
104 return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
107 /* ---------------------------- */
108 static off_t get_off_t(ibuf, is64)
116 memcpy(&temp, *ibuf, sizeof( temp ));
117 ret = ntohl(temp); /* ntohl is unsigned */
118 *ibuf += sizeof(temp);
121 memcpy(&temp, *ibuf, sizeof( temp ));
122 *ibuf += sizeof(temp);
123 ret = ntohl(temp)| (ret << 32);
126 ret = (int)ret; /* sign extend */
131 /* ---------------------- */
132 static int set_off_t(offset, rbuf, is64)
142 temp = htonl(offset >> 32);
143 memcpy(rbuf, &temp, sizeof( temp ));
144 rbuf += sizeof(temp);
145 ret = sizeof( temp );
146 offset &= 0xffffffff;
148 temp = htonl(offset);
149 memcpy(rbuf, &temp, sizeof( temp ));
150 ret += sizeof( temp );
155 /* ------------------------
157 static int is_neg(int is64, off_t val)
159 if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
164 static __inline__ int sum_neg(int is64, off_t offset, off_t reqcount)
166 if (is_neg(is64, offset +reqcount) )
171 /* -------------------------
173 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
175 return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
178 /* -------------------------
180 extern int ad_testlock(struct adouble *adp, int eid, int off);
182 static int getforkmode(struct adouble *adp, int eid, int what)
184 return ad_testlock(adp, eid, what);
187 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
195 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
196 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
199 if ((access & (OPENACC_RD | OPENACC_DRD))) {
200 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
202 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
205 if ((access & OPENACC_RD) && denyreadset) {
209 if ((access & OPENACC_DRD) && readset) {
213 /* boolean logic is not enough, because getforkmode is not always telling the
216 if ((access & OPENACC_RD)) {
217 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
221 if ((access & OPENACC_DRD)) {
222 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
227 /* ------------same for writing -------------- */
228 if ((access & (OPENACC_WR | OPENACC_DWR))) {
229 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
231 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
234 if ((access & OPENACC_WR) && denywriteset) {
238 if ((access & OPENACC_DWR) && writeset) {
242 if ((access & OPENACC_WR)) {
243 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
247 if ((access & OPENACC_DWR)) {
248 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
254 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
255 return ad_excl_lock(adp, eid);
261 /* ----------------------- */
262 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
265 int ibuflen, *rbuflen;
269 struct ofork *ofork, *opened;
270 struct adouble *adsame = NULL;
271 int buflen, ret, adflags, eid;
273 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
274 char fork, *path, *upath;
281 memcpy(&vid, ibuf, sizeof( vid ));
285 if (NULL == ( vol = getvolbyvid( vid ))) {
286 return( AFPERR_PARAM );
289 memcpy(&did, ibuf, sizeof( did ));
290 ibuf += sizeof( int );
292 if (NULL == ( dir = dirlookup( vol, did ))) {
296 memcpy(&bitmap, ibuf, sizeof( bitmap ));
297 bitmap = ntohs( bitmap );
298 ibuf += sizeof( bitmap );
299 memcpy(&access, ibuf, sizeof( access ));
300 access = ntohs( access );
301 ibuf += sizeof( access );
303 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
307 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
311 if (*s_path->m_name == '\0') {
313 return AFPERR_BADTYPE;
316 /* stat() data fork st is set because it's not a dir */
317 switch ( s_path->st_errno ) {
323 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
325 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
328 /* FIXME should we check it first ? */
329 upath = s_path->u_name;
330 if (check_access(upath, access ) < 0) {
331 return AFPERR_ACCESS;
335 /* XXX: this probably isn't the best way to do this. the already
336 open bits should really be set if the fork is opened by any
337 program, not just this one. however, that's problematic to do
338 if we can't write lock files somewhere. opened is also passed to
339 ad_open so that we can keep file locks together.
340 FIXME: add the fork we are opening?
342 if ((opened = of_findname(s_path))) {
343 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
344 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
346 adsame = opened->of_ad;
349 if ( fork == OPENFORK_DATA ) {
351 adflags = ADFLAGS_DF|ADFLAGS_HF;
354 adflags = ADFLAGS_HF;
357 path = s_path->m_name;
358 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
359 adsame, st)) == NULL ) {
360 return( AFPERR_NFILE );
364 if (access & OPENACC_WR) {
365 /* try opening in read-write mode */
366 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
374 if (fork == OPENFORK_DATA) {
375 /* try to open only the data fork */
376 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
379 adflags = ADFLAGS_DF;
382 /* here's the deal. we only try to create the resource
383 * fork if the user wants to open it for write acess. */
384 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
394 ret = AFPERR_BADTYPE;
398 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
404 /* the fork is open */
405 ofork->of_flags |= AFPFORK_OPEN;
407 /* try opening in read-only mode */
409 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
417 /* see if client asked for a read only data fork */
418 if (fork == OPENFORK_DATA) {
419 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
422 adflags = ADFLAGS_DF;
423 ofork->of_flags |= AFPFORK_OPEN;
425 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
426 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
427 * then create in open read-write.
436 ret = AFPERR_BADTYPE;
440 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
446 /* the fork is open */
447 ofork->of_flags |= AFPFORK_OPEN;
451 if ((adflags & ADFLAGS_HF) && (ad_get_HF_flags( ofork->of_ad) & O_CREAT)) {
452 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
453 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
454 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
455 ad_flush( ofork->of_ad, adflags );
458 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
459 &buflen, attrbits )) != AFP_OK ) {
460 ad_close( ofork->of_ad, adflags );
464 *rbuflen = buflen + 2 * sizeof( u_int16_t );
465 bitmap = htons( bitmap );
466 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
467 rbuf += sizeof( u_int16_t );
469 /* check WriteInhibit bit if we have a ressource fork
470 * the test is done here, after some Mac trafic capture
472 if (ad_hfileno(ofork->of_ad) != -1) {
473 ad_getattr(ofork->of_ad, &bshort);
474 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
475 ad_close( ofork->of_ad, adflags );
478 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
479 return(AFPERR_OLOCK);
484 * synchronization locks:
487 /* don't try to lock non-existent rforks. */
488 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
490 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
491 /* can we access the fork? */
494 ad_close( ofork->of_ad, adflags );
497 case EAGAIN: /* return data anyway */
501 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
502 return( AFPERR_DENYCONF );
506 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
507 return( AFPERR_PARAM );
510 if ((access & OPENACC_WR))
511 ofork->of_flags |= AFPFORK_ACCWR;
513 /* the file may be open read only without ressource fork */
514 if ((access & OPENACC_RD))
515 ofork->of_flags |= AFPFORK_ACCRD;
517 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
523 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
527 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
530 int ibuflen, *rbuflen;
534 u_int16_t ofrefnum, bitmap;
542 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
543 ibuf += sizeof( ofrefnum );
545 memcpy(&bitmap, ibuf, sizeof(bitmap));
546 bitmap = ntohs(bitmap);
547 ibuf += sizeof( bitmap );
550 if (NULL == ( ofork = of_find( ofrefnum )) ) {
551 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
552 return( AFPERR_PARAM );
555 if (ofork->of_vol->v_flags & AFPVOL_RO)
558 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
559 return AFPERR_ACCESS;
561 if ( ofork->of_flags & AFPFORK_DATA) {
563 } else if (ofork->of_flags & AFPFORK_RSRC) {
568 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
569 && eid == ADEID_RFORK
571 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
572 && eid == ADEID_DFORK)) {
573 return AFPERR_BITMAP;
577 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
578 if (afp_version >= 30) {
582 return AFPERR_BITMAP;
585 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
586 return AFPERR_PARAM ;
588 size = get_off_t(&ibuf, is64);
591 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
594 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
595 st_size = ad_size(ofork->of_ad, eid);
597 if (st_size > size &&
598 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
599 goto afp_setfork_err;
601 err = ad_dtruncate( ofork->of_ad, size );
603 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
605 goto afp_setfork_err;
606 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
607 ad_refresh( ofork->of_ad );
609 st_size = ad_size(ofork->of_ad, eid);
611 if (st_size > size &&
612 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
613 goto afp_setfork_err;
615 err = ad_rtruncate(ofork->of_ad, size);
617 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
619 goto afp_setfork_err;
621 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
622 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
626 return AFPERR_BITMAP;
629 if ( flushfork( ofork ) < 0 ) {
630 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
645 return AFPERR_ACCESS;
656 /* for this to work correctly, we need to check for locks before each
657 * read and write. that's most easily handled by always doing an
658 * appropriate check before each ad_read/ad_write. other things
659 * that can change files like truncate are handled internally to those
662 #define ENDBIT(a) ((a) & 0x80)
663 #define UNLOCKBIT(a) ((a) & 0x01)
666 /* ---------------------- */
667 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
670 int ibuflen, *rbuflen;
674 off_t offset, length;
682 /* figure out parameters */
684 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
686 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
687 ibuf += sizeof(ofrefnum);
689 if (NULL == ( ofork = of_find( ofrefnum )) ) {
690 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
691 return( AFPERR_PARAM );
694 if ( ofork->of_flags & AFPFORK_DATA) {
696 } else if (ofork->of_flags & AFPFORK_RSRC) {
701 offset = get_off_t(&ibuf, is64);
702 length = get_off_t(&ibuf, is64);
704 /* FIXME AD_FILELOCK test is surely wrong */
706 length = BYTELOCK_MAX;
707 else if (!length || is_neg(is64, length)) {
709 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
714 offset += ad_size(ofork->of_ad, eid);
715 /* FIXME what do we do if file size > 2 GB and
716 it's not byte_lock_ext?
719 if (offset < 0) /* error if we have a negative offset */
722 /* if the file is a read-only file, we use read locks instead of
723 * write locks. that way, we can prevent anyone from initiating
725 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
726 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
727 ofork->of_refnum) < 0) {
731 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
737 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
745 *rbuflen = set_off_t (offset, rbuf, is64);
749 /* --------------------------- */
750 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
753 int ibuflen, *rbuflen;
755 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
758 /* --------------------------- */
759 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
762 int ibuflen, *rbuflen;
764 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
769 /* --------------------------- */
770 static __inline__ int crlf( of )
775 if ( ad_hfileno( of->of_ad ) == -1 ||
776 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
778 if (( em = getextmap( of->of_name )) == NULL ||
779 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
785 if ( memcmp( ufinderi,
786 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
795 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
796 off_t offset, u_char nlmask,
797 u_char nlchar, char *rbuf,
798 int *rbuflen, const int xlate)
804 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
806 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
808 return( AFPERR_PARAM );
810 if ( cc < *rbuflen ) {
818 for ( p = rbuf, q = p + cc; p < q; ) {
819 if (( *p++ & nlmask ) == nlchar ) {
830 * If this file is of type TEXT, then swap \012 to \015.
833 for ( p = rbuf, q = p + cc; p < q; p++ ) {
834 if ( *p == '\012' ) {
836 } else if ( *p == '\015' ) {
845 return( AFPERR_EOF );
850 /* -----------------------------
851 * with ddp, afp_read can return fewer bytes than in reqcount
852 * so return EOF only if read actually past end of file not
853 * if offset +reqcount > size of file
855 * getfork size ==> 10430
856 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
857 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
858 * read fork offset 9248 size 1508 ==> 1182 (EOF)
859 * 10752 is a bug in Mac 7.5.x finder
861 * with dsi, should we check that reqcount < server quantum?
863 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
866 int ibuflen, *rbuflen;
871 off_t offset, saveoff, reqcount, savereqcount;
872 int cc, err, eid, xlate = 0;
874 u_char nlmask, nlchar;
877 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
878 ibuf += sizeof( u_short );
880 if (NULL == ( ofork = of_find( ofrefnum )) ) {
881 LOG(log_error, logtype_afpd, "afp_read: of_find");
886 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
890 offset = get_off_t(&ibuf, is64);
891 reqcount = get_off_t(&ibuf, is64);
900 /* if we wanted to be picky, we could add in the following
901 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
903 if (reqcount < 0 || offset < 0) {
908 if ( ofork->of_flags & AFPFORK_DATA) {
910 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
911 } else if (ofork->of_flags & AFPFORK_RSRC) {
913 } else { /* fork wasn't opened. this should never really happen. */
918 /* zero request count */
924 /* reqcount isn't always truthful. we need to deal with that. */
925 size = ad_size(ofork->of_ad, eid);
927 if (offset >= size) {
932 savereqcount = reqcount;
934 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
939 #define min(a,b) ((a)<(b)?(a):(b))
940 *rbuflen = min( reqcount, *rbuflen );
941 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
946 /* dsi can stream requests. we can only do this if we're not checking
947 * for an end-of-line character. oh well. */
948 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
949 DSI *dsi = obj->handle;
951 if (obj->options.flags & OPTION_DEBUG) {
952 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
953 (int) reqcount, dsi->clientID);
954 bprint(rbuf, *rbuflen);
956 /* subtract off the offset */
958 if (reqcount > size) {
965 /* dsi_readinit() returns size of next read buffer. by this point,
966 * we know that we're sending some data. if we fail, something
967 * horrible happened. */
968 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
971 /* due to the nature of afp packets, we have to exit if we get
972 an error. we can't do this with translation on. */
973 #ifdef HAVE_SENDFILE_READ
974 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
975 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
976 dsi->datasize) < 0) {
980 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
990 #endif /* HAVE_SENDFILE_READ */
992 /* fill up our buffer. */
993 while (*rbuflen > 0) {
994 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
1000 if (obj->options.flags & OPTION_DEBUG) {
1001 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1002 bprint(rbuf, *rbuflen);
1005 /* dsi_read() also returns buffer size of next allocation */
1006 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1015 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1017 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1022 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1030 /* ---------------------- */
1031 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1034 int ibuflen, *rbuflen;
1036 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1039 /* ---------------------- */
1040 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1043 int ibuflen, *rbuflen;
1045 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1048 /* ---------------------- */
1049 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1052 int ibuflen, *rbuflen;
1060 memcpy(&vid, ibuf, sizeof(vid));
1061 if (NULL == ( vol = getvolbyvid( vid )) ) {
1062 return( AFPERR_PARAM );
1069 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1072 int ibuflen, *rbuflen;
1074 struct ofork *ofork;
1079 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1081 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1082 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1083 return( AFPERR_PARAM );
1086 if ( flushfork( ofork ) < 0 ) {
1087 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1093 /* this is very similar to closefork */
1094 int flushfork( ofork )
1095 struct ofork *ofork;
1099 int err = 0, doflush = 0;
1101 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1102 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1103 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1104 ad_dfileno(ofork->of_ad), strerror(errno) );
1108 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1109 (ofork->of_flags & AFPFORK_RSRC)) {
1111 /* read in the rfork length */
1112 ad_refresh(ofork->of_ad);
1114 /* set the date if we're dirty */
1115 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1116 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1117 ofork->of_flags &= ~AFPFORK_DIRTY;
1121 /* flush the header */
1122 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1125 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1129 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1130 ad_hfileno(ofork->of_ad), strerror(errno) );
1136 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1139 int ibuflen, *rbuflen;
1141 struct ofork *ofork;
1143 int adflags, doflush = 0;
1148 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1150 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1151 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1152 return( AFPERR_PARAM );
1156 if ((ofork->of_flags & AFPFORK_OPEN)) {
1157 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1158 adflags |= ADFLAGS_DF;
1160 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1161 adflags |= ADFLAGS_HF;
1163 * Only set the rfork's length if we're closing the rfork.
1165 if ((ofork->of_flags & AFPFORK_RSRC)) {
1166 ad_refresh( ofork->of_ad );
1167 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1168 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1172 ad_flush( ofork->of_ad, adflags );
1177 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1178 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1179 return( AFPERR_PARAM );
1183 of_dealloc( ofork );
1188 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1189 off_t offset, char *rbuf,
1190 size_t rbuflen, const int xlate)
1196 * If this file is of type TEXT, swap \015 to \012.
1199 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1200 if ( *p == '\015' ) {
1202 } else if ( *p == '\012' ) {
1208 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1209 rbuf, rbuflen)) < 0 ) {
1214 return( AFPERR_DFULL );
1216 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1217 return( AFPERR_PARAM );
1225 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1226 * the client may have sent us a bunch of data that's not reflected
1227 * in reqcount et al. */
1228 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1231 int ibuflen, *rbuflen;
1234 struct ofork *ofork;
1235 off_t offset, saveoff, reqcount;
1236 int endflag, eid, xlate = 0, err = AFP_OK;
1240 /* figure out parameters */
1242 endflag = ENDBIT(*ibuf);
1244 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1245 ibuf += sizeof( ofrefnum );
1247 offset = get_off_t(&ibuf, is64);
1248 reqcount = get_off_t(&ibuf, is64);
1250 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1251 LOG(log_error, logtype_afpd, "afp_write: of_find");
1256 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1257 err = AFPERR_ACCESS;
1262 writtenfork = ofork;
1265 if ( ofork->of_flags & AFPFORK_DATA) {
1267 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1268 } else if (ofork->of_flags & AFPFORK_RSRC) {
1271 err = AFPERR_ACCESS; /* should never happen */
1276 offset += ad_size(ofork->of_ad, eid);
1278 /* handle bogus parameters */
1279 if (reqcount < 0 || offset < 0) {
1284 /* offset can overflow on 64-bit capable filesystems.
1285 * report disk full if that's going to happen. */
1286 if (sum_neg(is64, offset, reqcount)) {
1291 if (!reqcount) { /* handle request counts of 0 */
1293 *rbuflen = set_off_t (offset, rbuf, is64);
1298 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1299 reqcount, ofork->of_refnum) < 0) {
1304 /* this is yucky, but dsi can stream i/o and asp can't */
1305 switch (obj->proto) {
1308 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1310 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1311 return( AFPERR_PARAM );
1314 if (obj->options.flags & OPTION_DEBUG) {
1315 printf("(write) len: %d\n", *rbuflen);
1316 bprint(rbuf, *rbuflen);
1319 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1322 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1327 #endif /* no afp/asp */
1331 DSI *dsi = obj->handle;
1333 /* find out what we have already and write it out. */
1334 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1336 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1337 dsi_writeflush(dsi);
1339 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1344 #if 0 /*def HAVE_SENDFILE_WRITE*/
1345 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1346 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1347 offset, dsi->datasize)) < 0) {
1355 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1356 goto afp_write_loop;
1358 dsi_writeflush(dsi);
1360 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1361 reqcount, ofork->of_refnum);
1366 goto afp_write_done;
1368 #endif /* 0, was HAVE_SENDFILE_WRITE */
1370 /* loop until everything gets written. currently
1371 * dsi_write handles the end case by itself. */
1372 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1373 if ( obj->options.flags & OPTION_DEBUG ) {
1374 printf("(write) command cont'd: %d\n", cc);
1378 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1379 dsi_writeflush(dsi);
1381 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1382 reqcount, ofork->of_refnum);
1391 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1392 if ( ad_hfileno( ofork->of_ad ) != -1 )
1393 ofork->of_flags |= AFPFORK_DIRTY;
1395 *rbuflen = set_off_t (offset, rbuf, is64);
1399 if (obj->proto == AFPPROTO_DSI) {
1400 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1401 dsi_writeflush(obj->handle);
1404 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1408 /* ---------------------------- */
1409 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1412 int ibuflen, *rbuflen;
1414 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1417 /* ----------------------------
1418 * FIXME need to deal with SIGXFSZ signal
1420 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1423 int ibuflen, *rbuflen;
1425 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1428 /* ---------------------------- */
1429 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1432 int ibuflen, *rbuflen;
1434 struct ofork *ofork;
1436 u_int16_t ofrefnum, bitmap;
1437 u_int16_t attrbits = 0;
1440 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1441 ibuf += sizeof( ofrefnum );
1442 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1443 bitmap = ntohs( bitmap );
1444 ibuf += sizeof( bitmap );
1447 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1448 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1449 return( AFPERR_PARAM );
1451 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1452 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1454 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1455 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1456 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1457 return( AFPERR_PARAM );
1461 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1462 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1466 *rbuflen = buflen + sizeof( u_short );
1467 bitmap = htons( bitmap );
1468 memcpy(rbuf, &bitmap, sizeof( bitmap ));