2 * $Id: fork.c,v 1.47 2003-01-31 11:26:35 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)
196 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
197 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE);
200 if ((access & (OPENACC_RD | OPENACC_DRD))) {
201 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
203 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
206 if ((access & OPENACC_RD) && denyreadset) {
210 if ((access & OPENACC_DRD) && readset) {
214 /* boolean logic is not enough, because getforkmode is not always telling the
217 if ((access & OPENACC_RD)) {
218 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
222 if ((access & OPENACC_DRD)) {
223 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD);
228 /* ------------same for writing -------------- */
229 if ((access & (OPENACC_WR | OPENACC_DWR))) {
230 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
232 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
235 if ((access & OPENACC_WR) && denywriteset) {
239 if ((access & OPENACC_DWR) && writeset) {
243 if ((access & OPENACC_WR)) {
244 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
248 if ((access & OPENACC_DWR)) {
249 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR);
255 if ( access == (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD)) {
256 return ad_excl_lock(adp, eid);
262 /* ----------------------- */
263 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
266 int ibuflen, *rbuflen;
270 struct ofork *ofork, *opened;
271 struct adouble *adsame = NULL;
272 int buflen, ret, adflags, eid, lockop;
274 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
275 char fork, *path, *upath;
282 memcpy(&vid, ibuf, sizeof( vid ));
286 if (NULL == ( vol = getvolbyvid( vid ))) {
287 return( AFPERR_PARAM );
290 memcpy(&did, ibuf, sizeof( did ));
291 ibuf += sizeof( int );
293 if (NULL == ( dir = dirlookup( vol, did ))) {
297 memcpy(&bitmap, ibuf, sizeof( bitmap ));
298 bitmap = ntohs( bitmap );
299 ibuf += sizeof( bitmap );
300 memcpy(&access, ibuf, sizeof( access ));
301 access = ntohs( access );
302 ibuf += sizeof( access );
304 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
308 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
312 if (*s_path->m_name == '\0') {
314 return AFPERR_BADTYPE;
317 /* stat() data fork st is set because it's not a dir */
318 switch ( s_path->st_errno ) {
324 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
326 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
329 /* FIXME should we check it first ? */
330 upath = s_path->u_name;
331 if (check_access(upath, access ) < 0) {
332 return AFPERR_ACCESS;
336 /* XXX: this probably isn't the best way to do this. the already
337 open bits should really be set if the fork is opened by any
338 program, not just this one. however, that's problematic to do
339 if we can't write lock files somewhere. opened is also passed to
340 ad_open so that we can keep file locks together.
341 FIXME: add the fork we are opening?
343 if ((opened = of_findname(s_path))) {
344 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
345 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
347 adsame = opened->of_ad;
350 if ( fork == OPENFORK_DATA ) {
352 adflags = ADFLAGS_DF|ADFLAGS_HF;
355 adflags = ADFLAGS_HF;
358 path = s_path->m_name;
359 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
360 adsame, st)) == NULL ) {
361 return( AFPERR_NFILE );
365 if (access & OPENACC_WR) {
366 /* try opening in read-write mode */
367 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
375 if (fork == OPENFORK_DATA) {
376 /* try to open only the data fork */
377 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
380 adflags = ADFLAGS_DF;
383 /* here's the deal. we only try to create the resource
384 * fork if the user wants to open it for write acess. */
385 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
395 ret = AFPERR_BADTYPE;
399 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
405 /* the fork is open */
406 ofork->of_flags |= AFPFORK_OPEN;
408 /* try opening in read-only mode */
410 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
418 /* see if client asked for a read only data fork */
419 if (fork == OPENFORK_DATA) {
420 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
423 adflags = ADFLAGS_DF;
424 ofork->of_flags |= AFPFORK_OPEN;
426 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
427 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
428 * then create in open read-write.
437 ret = AFPERR_BADTYPE;
441 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
447 /* the fork is open */
448 ofork->of_flags |= AFPFORK_OPEN;
452 if ((adflags & ADFLAGS_HF) &&
453 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
454 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
455 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
456 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
457 ad_flush( ofork->of_ad, adflags );
460 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
461 &buflen, attrbits )) != AFP_OK ) {
462 ad_close( ofork->of_ad, adflags );
466 *rbuflen = buflen + 2 * sizeof( u_int16_t );
467 bitmap = htons( bitmap );
468 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
469 rbuf += sizeof( u_int16_t );
471 /* check WriteInhibit bit if we have a ressource fork
472 * the test is done here, after some Mac trafic capture
474 if (ad_hfileno(ofork->of_ad) != -1) {
475 ad_getattr(ofork->of_ad, &bshort);
476 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
477 ad_close( ofork->of_ad, adflags );
480 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
481 return(AFPERR_OLOCK);
486 * synchronization locks:
489 /* don't try to lock non-existent rforks. */
490 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
492 ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
493 /* can we access the fork? */
496 ad_close( ofork->of_ad, adflags );
499 case EAGAIN: /* return data anyway */
503 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
504 return( AFPERR_DENYCONF );
508 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
509 return( AFPERR_PARAM );
512 if ((access & OPENACC_WR))
513 ofork->of_flags |= AFPFORK_ACCWR;
515 /* the file may be open read only without ressource fork */
516 if ((access & OPENACC_RD))
517 ofork->of_flags |= AFPFORK_ACCRD;
519 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
525 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
529 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
532 int ibuflen, *rbuflen;
536 u_int16_t ofrefnum, bitmap;
544 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
545 ibuf += sizeof( ofrefnum );
547 memcpy(&bitmap, ibuf, sizeof(bitmap));
548 bitmap = ntohs(bitmap);
549 ibuf += sizeof( bitmap );
552 if (NULL == ( ofork = of_find( ofrefnum )) ) {
553 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
554 return( AFPERR_PARAM );
557 if (ofork->of_vol->v_flags & AFPVOL_RO)
560 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
561 return AFPERR_ACCESS;
563 if ( ofork->of_flags & AFPFORK_DATA) {
565 } else if (ofork->of_flags & AFPFORK_RSRC) {
570 if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
571 && eid == ADEID_RFORK
573 ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
574 && eid == ADEID_DFORK)) {
575 return AFPERR_BITMAP;
579 if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
580 if (afp_version >= 30) {
584 return AFPERR_BITMAP;
587 if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
588 return AFPERR_PARAM ;
590 size = get_off_t(&ibuf, is64);
593 return AFPERR_PARAM; /* Some MacOS don't return an error they just don't change the size! */
596 if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
597 st_size = ad_size(ofork->of_ad, eid);
599 if (st_size > size &&
600 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
601 goto afp_setfork_err;
603 err = ad_dtruncate( ofork->of_ad, size );
605 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
607 goto afp_setfork_err;
608 } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
609 ad_refresh( ofork->of_ad );
611 st_size = ad_size(ofork->of_ad, eid);
613 if (st_size > size &&
614 ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
615 goto afp_setfork_err;
617 err = ad_rtruncate(ofork->of_ad, size);
619 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
621 goto afp_setfork_err;
623 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
624 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",strerror(errno) );
628 return AFPERR_BITMAP;
631 if ( flushfork( ofork ) < 0 ) {
632 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
647 return AFPERR_ACCESS;
658 /* for this to work correctly, we need to check for locks before each
659 * read and write. that's most easily handled by always doing an
660 * appropriate check before each ad_read/ad_write. other things
661 * that can change files like truncate are handled internally to those
664 #define ENDBIT(a) ((a) & 0x80)
665 #define UNLOCKBIT(a) ((a) & 0x01)
668 /* ---------------------- */
669 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
672 int ibuflen, *rbuflen;
676 off_t offset, length;
684 /* figure out parameters */
686 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
688 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
689 ibuf += sizeof(ofrefnum);
691 if (NULL == ( ofork = of_find( ofrefnum )) ) {
692 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
693 return( AFPERR_PARAM );
696 if ( ofork->of_flags & AFPFORK_DATA) {
698 } else if (ofork->of_flags & AFPFORK_RSRC) {
703 offset = get_off_t(&ibuf, is64);
704 length = get_off_t(&ibuf, is64);
706 /* FIXME AD_FILELOCK test is surely wrong */
708 length = BYTELOCK_MAX;
709 else if (!length || is_neg(is64, length)) {
711 } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_hfileno(ofork->of_ad))) {
716 offset += ad_size(ofork->of_ad, eid);
717 /* FIXME what do we do if file size > 2 GB and
718 it's not byte_lock_ext?
721 if (offset < 0) /* error if we have a negative offset */
724 /* if the file is a read-only file, we use read locks instead of
725 * write locks. that way, we can prevent anyone from initiating
727 lockop = UNLOCKBIT(flags) ? ADLOCK_CLR : ADLOCK_WR;
728 if (ad_lock(ofork->of_ad, eid, lockop, offset, length,
729 ofork->of_refnum) < 0) {
733 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
739 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
747 *rbuflen = set_off_t (offset, rbuf, is64);
751 /* --------------------------- */
752 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
755 int ibuflen, *rbuflen;
757 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
760 /* --------------------------- */
761 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
764 int ibuflen, *rbuflen;
766 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
771 /* --------------------------- */
772 static __inline__ int crlf( of )
777 if ( ad_hfileno( of->of_ad ) == -1 ||
778 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
780 if (( em = getextmap( of->of_name )) == NULL ||
781 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
787 if ( memcmp( ufinderi,
788 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
797 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
798 off_t offset, u_char nlmask,
799 u_char nlchar, char *rbuf,
800 int *rbuflen, const int xlate)
806 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
808 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
810 return( AFPERR_PARAM );
812 if ( cc < *rbuflen ) {
820 for ( p = rbuf, q = p + cc; p < q; ) {
821 if (( *p++ & nlmask ) == nlchar ) {
832 * If this file is of type TEXT, then swap \012 to \015.
835 for ( p = rbuf, q = p + cc; p < q; p++ ) {
836 if ( *p == '\012' ) {
838 } else if ( *p == '\015' ) {
847 return( AFPERR_EOF );
852 /* -----------------------------
853 * with ddp, afp_read can return fewer bytes than in reqcount
854 * so return EOF only if read actually past end of file not
855 * if offset +reqcount > size of file
857 * getfork size ==> 10430
858 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
859 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
860 * read fork offset 9248 size 1508 ==> 1182 (EOF)
861 * 10752 is a bug in Mac 7.5.x finder
863 * with dsi, should we check that reqcount < server quantum?
865 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
868 int ibuflen, *rbuflen;
873 off_t offset, saveoff, reqcount, savereqcount;
874 int cc, err, eid, xlate = 0;
876 u_char nlmask, nlchar;
879 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
880 ibuf += sizeof( u_short );
882 if (NULL == ( ofork = of_find( ofrefnum )) ) {
883 LOG(log_error, logtype_afpd, "afp_read: of_find");
888 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
892 offset = get_off_t(&ibuf, is64);
893 reqcount = get_off_t(&ibuf, is64);
902 /* if we wanted to be picky, we could add in the following
903 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
905 if (reqcount < 0 || offset < 0) {
910 if ( ofork->of_flags & AFPFORK_DATA) {
912 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
913 } else if (ofork->of_flags & AFPFORK_RSRC) {
915 } else { /* fork wasn't opened. this should never really happen. */
920 /* zero request count */
926 /* reqcount isn't always truthful. we need to deal with that. */
927 size = ad_size(ofork->of_ad, eid);
929 if (offset >= size) {
934 savereqcount = reqcount;
936 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount,ofork->of_refnum) < 0) {
941 #define min(a,b) ((a)<(b)?(a):(b))
942 *rbuflen = min( reqcount, *rbuflen );
943 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
948 /* dsi can stream requests. we can only do this if we're not checking
949 * for an end-of-line character. oh well. */
950 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
951 DSI *dsi = obj->handle;
953 if (obj->options.flags & OPTION_DEBUG) {
954 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
955 (int) reqcount, dsi->clientID);
956 bprint(rbuf, *rbuflen);
958 /* subtract off the offset */
960 if (reqcount > size) {
967 /* dsi_readinit() returns size of next read buffer. by this point,
968 * we know that we're sending some data. if we fail, something
969 * horrible happened. */
970 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
973 /* due to the nature of afp packets, we have to exit if we get
974 an error. we can't do this with translation on. */
975 #ifdef HAVE_SENDFILE_READ
976 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
977 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
978 dsi->datasize) < 0) {
982 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
992 #endif /* HAVE_SENDFILE_READ */
994 /* fill up our buffer. */
995 while (*rbuflen > 0) {
996 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
1002 if (obj->options.flags & OPTION_DEBUG) {
1003 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
1004 bprint(rbuf, *rbuflen);
1007 /* dsi_read() also returns buffer size of next allocation */
1008 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
1017 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
1019 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1024 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
1032 /* ---------------------- */
1033 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
1036 int ibuflen, *rbuflen;
1038 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1041 /* ---------------------- */
1042 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1045 int ibuflen, *rbuflen;
1047 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1050 /* ---------------------- */
1051 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1054 int ibuflen, *rbuflen;
1062 memcpy(&vid, ibuf, sizeof(vid));
1063 if (NULL == ( vol = getvolbyvid( vid )) ) {
1064 return( AFPERR_PARAM );
1071 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1074 int ibuflen, *rbuflen;
1076 struct ofork *ofork;
1081 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1083 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1084 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1085 return( AFPERR_PARAM );
1088 if ( flushfork( ofork ) < 0 ) {
1089 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1095 /* this is very similar to closefork */
1096 int flushfork( ofork )
1097 struct ofork *ofork;
1101 int err = 0, doflush = 0;
1103 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1104 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1105 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1106 ad_dfileno(ofork->of_ad), strerror(errno) );
1110 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1111 (ofork->of_flags & AFPFORK_RSRC)) {
1113 /* read in the rfork length */
1114 ad_refresh(ofork->of_ad);
1116 /* set the date if we're dirty */
1117 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1118 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1119 ofork->of_flags &= ~AFPFORK_DIRTY;
1123 /* flush the header */
1124 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1127 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1131 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1132 ad_hfileno(ofork->of_ad), strerror(errno) );
1138 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1141 int ibuflen, *rbuflen;
1143 struct ofork *ofork;
1145 int adflags, doflush = 0;
1150 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1152 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1153 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1154 return( AFPERR_PARAM );
1158 if ((ofork->of_flags & AFPFORK_OPEN)) {
1159 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1160 adflags |= ADFLAGS_DF;
1162 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1163 adflags |= ADFLAGS_HF;
1165 * Only set the rfork's length if we're closing the rfork.
1167 if ((ofork->of_flags & AFPFORK_RSRC)) {
1168 ad_refresh( ofork->of_ad );
1169 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1170 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1174 ad_flush( ofork->of_ad, adflags );
1179 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1180 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1181 return( AFPERR_PARAM );
1185 of_dealloc( ofork );
1190 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1191 off_t offset, char *rbuf,
1192 size_t rbuflen, const int xlate)
1198 * If this file is of type TEXT, swap \015 to \012.
1201 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1202 if ( *p == '\015' ) {
1204 } else if ( *p == '\012' ) {
1210 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1211 rbuf, rbuflen)) < 0 ) {
1216 return( AFPERR_DFULL );
1218 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1219 return( AFPERR_PARAM );
1227 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1228 * the client may have sent us a bunch of data that's not reflected
1229 * in reqcount et al. */
1230 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1233 int ibuflen, *rbuflen;
1236 struct ofork *ofork;
1237 off_t offset, saveoff, reqcount;
1238 int endflag, eid, xlate = 0, err = AFP_OK;
1242 /* figure out parameters */
1244 endflag = ENDBIT(*ibuf);
1246 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1247 ibuf += sizeof( ofrefnum );
1249 offset = get_off_t(&ibuf, is64);
1250 reqcount = get_off_t(&ibuf, is64);
1252 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1253 LOG(log_error, logtype_afpd, "afp_write: of_find");
1258 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1259 err = AFPERR_ACCESS;
1264 writtenfork = ofork;
1267 if ( ofork->of_flags & AFPFORK_DATA) {
1269 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1270 } else if (ofork->of_flags & AFPFORK_RSRC) {
1273 err = AFPERR_ACCESS; /* should never happen */
1278 offset += ad_size(ofork->of_ad, eid);
1280 /* handle bogus parameters */
1281 if (reqcount < 0 || offset < 0) {
1286 /* offset can overflow on 64-bit capable filesystems.
1287 * report disk full if that's going to happen. */
1288 if (sum_neg(is64, offset, reqcount)) {
1293 if (!reqcount) { /* handle request counts of 0 */
1295 *rbuflen = set_off_t (offset, rbuf, is64);
1300 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1301 reqcount, ofork->of_refnum) < 0) {
1306 /* this is yucky, but dsi can stream i/o and asp can't */
1307 switch (obj->proto) {
1310 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1312 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1313 return( AFPERR_PARAM );
1316 if (obj->options.flags & OPTION_DEBUG) {
1317 printf("(write) len: %d\n", *rbuflen);
1318 bprint(rbuf, *rbuflen);
1321 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1324 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1329 #endif /* no afp/asp */
1333 DSI *dsi = obj->handle;
1335 /* find out what we have already and write it out. */
1336 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1338 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1339 dsi_writeflush(dsi);
1341 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1346 #if 0 /*def HAVE_SENDFILE_WRITE*/
1347 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1348 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1349 offset, dsi->datasize)) < 0) {
1357 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1358 goto afp_write_loop;
1360 dsi_writeflush(dsi);
1362 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1363 reqcount, ofork->of_refnum);
1368 goto afp_write_done;
1370 #endif /* 0, was HAVE_SENDFILE_WRITE */
1372 /* loop until everything gets written. currently
1373 * dsi_write handles the end case by itself. */
1374 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1375 if ( obj->options.flags & OPTION_DEBUG ) {
1376 printf("(write) command cont'd: %d\n", cc);
1380 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1381 dsi_writeflush(dsi);
1383 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1384 reqcount, ofork->of_refnum);
1393 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
1394 if ( ad_hfileno( ofork->of_ad ) != -1 )
1395 ofork->of_flags |= AFPFORK_DIRTY;
1397 *rbuflen = set_off_t (offset, rbuf, is64);
1401 if (obj->proto == AFPPROTO_DSI) {
1402 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1403 dsi_writeflush(obj->handle);
1406 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1410 /* ---------------------------- */
1411 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1414 int ibuflen, *rbuflen;
1416 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1419 /* ----------------------------
1420 * FIXME need to deal with SIGXFSZ signal
1422 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1425 int ibuflen, *rbuflen;
1427 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1430 /* ---------------------------- */
1431 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1434 int ibuflen, *rbuflen;
1436 struct ofork *ofork;
1438 u_int16_t ofrefnum, bitmap;
1439 u_int16_t attrbits = 0;
1442 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1443 ibuf += sizeof( ofrefnum );
1444 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1445 bitmap = ntohs( bitmap );
1446 ibuf += sizeof( bitmap );
1449 if (NULL == ( ofork = of_find( ofrefnum )) ) {
1450 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1451 return( AFPERR_PARAM );
1453 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1454 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1456 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1457 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1458 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1459 return( AFPERR_PARAM );
1463 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1464 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1468 *rbuflen = buflen + sizeof( u_short );
1469 bitmap = htons( bitmap );
1470 memcpy(rbuf, &bitmap, sizeof( bitmap ));