2 * $Id: fork.c,v 1.43 2003-01-12 14:40: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 #define BYTELOCK_MAX 0x7FFFFFFFU
51 #define BYTELOCK_MAXL 0x7FFFFFFFFFFFFFFFULL
53 struct ofork *writtenfork;
54 extern int getmetadata(struct vol *vol,
56 char *path, struct dir *dir, struct stat *st,
57 char *buf, int *buflen, struct adouble *adp, int attrbits );
59 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
64 const u_int16_t attrbits;
74 /* can only get the length of the opened fork */
75 if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
76 && (ofork->of_flags & AFPFORK_RSRC))
78 ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
79 && (ofork->of_flags & AFPFORK_DATA))) {
80 return( AFPERR_BITMAP );
83 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
92 if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
93 (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
94 (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
95 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
96 upath = mtoupath(vol, ofork->of_name);
97 if (movecwd(vol, dir) < 0)
98 return( AFPERR_NOOBJ );
99 if ( stat( upath, &st ) < 0 )
100 return( AFPERR_NOOBJ );
102 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
103 return( AFPERR_BITMAP );
107 return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
110 /* -------------------------
114 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
119 /* NOTE: we can't write lock a read-only file. on those, we just
120 * make sure that we have a read lock set. that way, we at least prevent
121 * someone else from really setting a deny read/write on the file.
123 lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
124 lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
126 return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
130 /* -------------------------
132 extern int ad_testlock(struct adouble *adp, int eid, int off);
134 static int getforkmode(struct adouble *adp, int eid, int what)
136 return ad_testlock(adp, eid, what);
139 static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
148 if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
149 return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
152 if ((access & (OPENACC_RD | OPENACC_DRD))) {
153 if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
155 if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
158 if ((access & OPENACC_RD) && denyreadset) {
162 if ((access & OPENACC_DRD) && readset) {
166 /* boolean logic is not enough, because getforkmode is not always telling the
169 mode = ((access & OPENACC_DRD))?EXCL: SHARE;
170 if ((access & OPENACC_RD)) {
171 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
175 if ((access & OPENACC_DRD)) {
176 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
181 /* ------------same for writing -------------- */
182 if ((access & (OPENACC_WR | OPENACC_DWR))) {
183 if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
185 if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
188 if ((access & OPENACC_WR) && denywriteset) {
192 if ((access & OPENACC_DWR) && writeset) {
196 mode = ((access & OPENACC_DWR))?EXCL: SHARE;
197 if ((access & OPENACC_WR)) {
198 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
202 if ((access & OPENACC_DWR)) {
203 ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
211 /* ----------------------- */
212 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
215 int ibuflen, *rbuflen;
219 struct ofork *ofork, *opened;
220 struct adouble *adsame = NULL;
221 int buflen, ret, adflags, eid, lockop;
223 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
224 char fork, *path, *upath;
231 memcpy(&vid, ibuf, sizeof( vid ));
235 if (NULL == ( vol = getvolbyvid( vid ))) {
236 return( AFPERR_PARAM );
239 memcpy(&did, ibuf, sizeof( did ));
240 ibuf += sizeof( int );
242 if (NULL == ( dir = dirlookup( vol, did ))) {
246 memcpy(&bitmap, ibuf, sizeof( bitmap ));
247 bitmap = ntohs( bitmap );
248 ibuf += sizeof( bitmap );
249 memcpy(&access, ibuf, sizeof( access ));
250 access = ntohs( access );
251 ibuf += sizeof( access );
253 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
257 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
261 if (*s_path->m_name == '\0') {
263 return AFPERR_BADTYPE;
266 /* stat() data fork st is set because it's not a dir */
267 switch ( s_path->st_errno ) {
273 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
275 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
278 /* FIXME should we check it first ? */
279 upath = s_path->u_name;
280 if (check_access(upath, access ) < 0) {
281 return AFPERR_ACCESS;
285 /* XXX: this probably isn't the best way to do this. the already
286 open bits should really be set if the fork is opened by any
287 program, not just this one. however, that's problematic to do
288 if we can't write lock files somewhere. opened is also passed to
289 ad_open so that we can keep file locks together.
290 FIXME: add the fork we are opening?
292 if ((opened = of_findname(s_path))) {
293 attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
294 attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
296 adsame = opened->of_ad;
299 if ( fork == OPENFORK_DATA ) {
301 adflags = ADFLAGS_DF|ADFLAGS_HF;
304 adflags = ADFLAGS_HF;
307 path = s_path->m_name;
308 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
309 adsame, st)) == NULL ) {
310 return( AFPERR_NFILE );
314 if (access & OPENACC_WR) {
315 /* try opening in read-write mode */
316 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
324 if (fork == OPENFORK_DATA) {
325 /* try to open only the data fork */
326 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
329 adflags = ADFLAGS_DF;
332 /* here's the deal. we only try to create the resource
333 * fork if the user wants to open it for write acess. */
334 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
344 ret = AFPERR_BADTYPE;
348 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
354 /* the fork is open */
355 ofork->of_flags |= AFPFORK_OPEN;
357 /* try opening in read-only mode */
359 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
367 /* see if client asked for a read only data fork */
368 if (fork == OPENFORK_DATA) {
369 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
372 adflags = ADFLAGS_DF;
373 ofork->of_flags |= AFPFORK_OPEN;
375 /* else we don't set AFPFORK_OPEN because there's no ressource fork file
376 * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
377 * then create in open read-write.
386 ret = AFPERR_BADTYPE;
390 LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
396 /* the fork is open */
397 ofork->of_flags |= AFPFORK_OPEN;
401 if ((adflags & ADFLAGS_HF) &&
402 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
403 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
404 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
405 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
406 ad_flush( ofork->of_ad, adflags );
409 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
410 &buflen, attrbits )) != AFP_OK ) {
411 ad_close( ofork->of_ad, adflags );
415 *rbuflen = buflen + 2 * sizeof( u_int16_t );
416 bitmap = htons( bitmap );
417 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
418 rbuf += sizeof( u_int16_t );
420 /* check WriteInhibit bit if we have a ressource fork
421 * the test is done here, after some Mac trafic capture
423 if (ad_hfileno(ofork->of_ad) != -1) {
424 ad_getattr(ofork->of_ad, &bshort);
425 if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
426 ad_close( ofork->of_ad, adflags );
429 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
430 return(AFPERR_OLOCK);
435 * synchronization locks:
438 /* don't try to lock non-existent rforks. */
439 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
441 ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
442 /* can we access the fork? */
445 ad_close( ofork->of_ad, adflags );
448 case EAGAIN: /* return data anyway */
452 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
453 return( AFPERR_DENYCONF );
457 LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
458 return( AFPERR_PARAM );
461 if ((access & OPENACC_WR))
462 ofork->of_flags |= AFPFORK_ACCWR;
464 /* the file may be open read only without ressource fork */
465 if ((access & OPENACC_RD))
466 ofork->of_flags |= AFPFORK_ACCRD;
468 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
474 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
478 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
481 int ibuflen, *rbuflen;
485 u_int16_t ofrefnum, bitmap;
489 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
490 ibuf += sizeof( ofrefnum );
491 memcpy(&bitmap, ibuf, sizeof(bitmap));
492 bitmap = ntohs(bitmap);
493 ibuf += sizeof( bitmap );
494 memcpy(&size, ibuf, sizeof( size ));
495 size = ntohl( size );
498 if (( ofork = of_find( ofrefnum )) == NULL ) {
499 LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
500 return( AFPERR_PARAM );
503 if (ofork->of_vol->v_flags & AFPVOL_RO)
506 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
507 return AFPERR_ACCESS;
512 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
513 err = ad_dtruncate( ofork->of_ad, size );
515 goto afp_setfork_err;
516 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
517 (ofork->of_flags & AFPFORK_RSRC)) {
518 ad_refresh( ofork->of_ad );
519 err = ad_rtruncate(ofork->of_ad, size);
521 goto afp_setfork_err;
523 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
524 LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
526 return( AFPERR_PARAM );
529 return AFPERR_BITMAP;
532 if ( flushfork( ofork ) < 0 ) {
533 LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
548 return AFPERR_ACCESS;
559 /* for this to work correctly, we need to check for locks before each
560 * read and write. that's most easily handled by always doing an
561 * appropriate check before each ad_read/ad_write. other things
562 * that can change files like truncate are handled internally to those
565 #define ENDBIT(a) ((a) & 0x80)
566 #define UNLOCKBIT(a) ((a) & 0x01)
568 static off_t get_off_t(ibuf, is64)
575 memcpy(&temp, *ibuf, sizeof( temp ));
576 ret = ntohl(temp); /* ntohl is unsigned */
577 *ibuf += sizeof(temp);
580 memcpy(&temp, *ibuf, sizeof( temp ));
581 *ibuf += sizeof(temp);
582 ret = ntohl(temp)| (ret << 32);
587 /* ---------------------- */
588 static int set_off_t(offset, rbuf, is64)
598 temp = htonl(offset >> 32);
599 memcpy(rbuf, &temp, sizeof( temp ));
600 rbuf += sizeof(temp);
601 ret = sizeof( temp );
602 offset &= 0xffffffff;
604 temp = htonl(offset);
605 memcpy(rbuf, &temp, sizeof( temp ));
606 ret += sizeof( temp );
611 /* ---------------------- */
612 static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
615 int ibuflen, *rbuflen;
619 off_t offset, length;
626 /* figure out parameters */
628 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
630 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
631 ibuf += sizeof(ofrefnum);
633 if (( ofork = of_find( ofrefnum )) == NULL ) {
634 LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
635 return( AFPERR_PARAM );
638 if ( ofork->of_flags & AFPFORK_DATA) {
640 } else if (ofork->of_flags & AFPFORK_RSRC) {
645 offset = get_off_t(&ibuf, is64);
646 length = get_off_t(&ibuf, is64);
650 length = BYTELOCK_MAXL;
651 else if (length <= 0) {
653 } else if ((length >= AD_FILELOCK_BASE) &&
654 (ad_hfileno(ofork->of_ad) == -1)) {
659 if (length == 0xFFFFFFFF)
660 length = BYTELOCK_MAX;
661 else if (!length || (length & (1 << 31))) {
663 } else if ((length >= AD_FILELOCK_BASE) &&
664 (ad_hfileno(ofork->of_ad) == -1)) {
670 offset += ad_size(ofork->of_ad, eid);
672 if (offset < 0) /* error if we have a negative offset */
675 /* if the file is a read-only file, we use read locks instead of
676 * write locks. that way, we can prevent anyone from initiating
678 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
679 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
680 ADLOCK_WR : ADLOCK_RD), offset, length,
681 ofork->of_refnum) < 0) {
685 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
691 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
699 *rbuflen = set_off_t (offset, rbuf, is64);
703 /* --------------------------- */
704 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
707 int ibuflen, *rbuflen;
709 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
712 /* --------------------------- */
713 int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
716 int ibuflen, *rbuflen;
718 return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
723 /* --------------------------- */
724 static __inline__ int crlf( of )
729 if ( ad_hfileno( of->of_ad ) == -1 ||
730 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
732 if (( em = getextmap( of->of_name )) == NULL ||
733 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
739 if ( memcmp( ufinderi,
740 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
749 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
750 int offset, u_char nlmask,
751 u_char nlchar, char *rbuf,
752 int *rbuflen, const int xlate)
758 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
760 LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
762 return( AFPERR_PARAM );
764 if ( cc < *rbuflen ) {
772 for ( p = rbuf, q = p + cc; p < q; ) {
773 if (( *p++ & nlmask ) == nlchar ) {
784 * If this file is of type TEXT, then swap \012 to \015.
787 for ( p = rbuf, q = p + cc; p < q; p++ ) {
788 if ( *p == '\012' ) {
790 } else if ( *p == '\015' ) {
799 return( AFPERR_EOF );
804 /* -----------------------------
805 * with ddp, afp_read can return fewer bytes than in reqcount
806 * so return EOF only if read actually past end of file not
807 * if offset +reqcount > size of file
809 * getfork size ==> 10430
810 * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
811 * read fork offset 4264 size 6128 ==> 4264 (without EOF)
812 * read fork offset 9248 size 1508 ==> 1182 (EOF)
813 * 10752 is a bug in Mac 7.5.x finder
815 * with dsi, should we check that reqcount < server quantum?
817 static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
820 int ibuflen, *rbuflen;
825 off_t offset, saveoff, reqcount, savereqcount;
826 int cc, err, eid, xlate = 0;
828 u_char nlmask, nlchar;
831 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
832 ibuf += sizeof( u_short );
834 if (NULL == ( ofork = of_find( ofrefnum )) ) {
835 LOG(log_error, logtype_afpd, "afp_read: of_find");
840 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
844 offset = get_off_t(&ibuf, is64);
845 reqcount = get_off_t(&ibuf, is64);
854 /* if we wanted to be picky, we could add in the following
855 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
857 if (reqcount < 0 || offset < 0) {
862 if ( ofork->of_flags & AFPFORK_DATA) {
864 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
865 } else if (ofork->of_flags & AFPFORK_RSRC) {
867 } else { /* fork wasn't opened. this should never really happen. */
872 /* zero request count */
878 /* reqcount isn't always truthful. we need to deal with that. */
879 size = ad_size(ofork->of_ad, eid);
881 if (offset >= size) {
886 savereqcount = reqcount;
888 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
893 #define min(a,b) ((a)<(b)?(a):(b))
894 *rbuflen = min( reqcount, *rbuflen );
895 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
900 /* dsi can stream requests. we can only do this if we're not checking
901 * for an end-of-line character. oh well. */
902 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
903 DSI *dsi = obj->handle;
905 if (obj->options.flags & OPTION_DEBUG) {
906 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
907 (int) reqcount, dsi->clientID);
908 bprint(rbuf, *rbuflen);
910 /* subtract off the offset */
912 if (reqcount > size) {
919 /* dsi_readinit() returns size of next read buffer. by this point,
920 * we know that we're sending some data. if we fail, something
921 * horrible happened. */
922 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
925 /* due to the nature of afp packets, we have to exit if we get
926 an error. we can't do this with translation on. */
927 #ifdef HAVE_SENDFILE_READ
928 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
929 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
930 dsi->datasize) < 0) {
934 LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
944 #endif /* HAVE_SENDFILE_READ */
946 /* fill up our buffer. */
947 while (*rbuflen > 0) {
948 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
954 if (obj->options.flags & OPTION_DEBUG) {
955 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
956 bprint(rbuf, *rbuflen);
959 /* dsi_read() also returns buffer size of next allocation */
960 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
969 LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
971 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
976 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
984 /* ---------------------- */
985 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
988 int ibuflen, *rbuflen;
990 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
993 /* ---------------------- */
994 int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
997 int ibuflen, *rbuflen;
999 return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1002 /* ---------------------- */
1003 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
1006 int ibuflen, *rbuflen;
1014 memcpy(&vid, ibuf, sizeof(vid));
1015 if (NULL == ( vol = getvolbyvid( vid )) ) {
1016 return( AFPERR_PARAM );
1023 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
1026 int ibuflen, *rbuflen;
1028 struct ofork *ofork;
1033 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1035 if (( ofork = of_find( ofrefnum )) == NULL ) {
1036 LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
1037 return( AFPERR_PARAM );
1040 if ( flushfork( ofork ) < 0 ) {
1041 LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
1047 /* this is very similar to closefork */
1048 int flushfork( ofork )
1049 struct ofork *ofork;
1053 int err = 0, doflush = 0;
1055 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1056 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1057 LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
1058 ad_dfileno(ofork->of_ad), strerror(errno) );
1062 if ( ad_hfileno( ofork->of_ad ) != -1 &&
1063 (ofork->of_flags & AFPFORK_RSRC)) {
1065 /* read in the rfork length */
1066 ad_refresh(ofork->of_ad);
1068 /* set the date if we're dirty */
1069 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1070 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1071 ofork->of_flags &= ~AFPFORK_DIRTY;
1075 /* flush the header */
1076 if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
1079 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1083 LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
1084 ad_hfileno(ofork->of_ad), strerror(errno) );
1090 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1093 int ibuflen, *rbuflen;
1095 struct ofork *ofork;
1097 int adflags, doflush = 0;
1102 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1104 if (( ofork = of_find( ofrefnum )) == NULL ) {
1105 LOG(log_error, logtype_afpd, "afp_closefork: of_find");
1106 return( AFPERR_PARAM );
1110 if ((ofork->of_flags & AFPFORK_OPEN)) {
1111 if ((ofork->of_flags & AFPFORK_DATA) && (ad_dfileno( ofork->of_ad ) != -1)) {
1112 adflags |= ADFLAGS_DF;
1114 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1115 adflags |= ADFLAGS_HF;
1117 * Only set the rfork's length if we're closing the rfork.
1119 if ((ofork->of_flags & AFPFORK_RSRC)) {
1120 ad_refresh( ofork->of_ad );
1121 if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
1122 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
1126 ad_flush( ofork->of_ad, adflags );
1131 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1132 LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
1133 return( AFPERR_PARAM );
1137 of_dealloc( ofork );
1142 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1143 off_t offset, char *rbuf,
1144 size_t rbuflen, const int xlate)
1150 * If this file is of type TEXT, swap \015 to \012.
1153 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1154 if ( *p == '\015' ) {
1156 } else if ( *p == '\012' ) {
1162 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1163 rbuf, rbuflen)) < 0 ) {
1168 return( AFPERR_DFULL );
1170 LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
1171 return( AFPERR_PARAM );
1178 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1179 * the client may have sent us a bunch of data that's not reflected
1180 * in reqcount et al. */
1181 static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
1184 int ibuflen, *rbuflen;
1187 struct ofork *ofork;
1188 off_t offset, saveoff, reqcount;
1189 int endflag, eid, xlate = 0, err = AFP_OK;
1193 /* figure out parameters */
1195 endflag = ENDBIT(*ibuf);
1197 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1198 ibuf += sizeof( ofrefnum );
1200 offset = get_off_t(&ibuf, is64);
1201 reqcount = get_off_t(&ibuf, is64);
1203 if (( ofork = of_find( ofrefnum )) == NULL ) {
1204 LOG(log_error, logtype_afpd, "afp_write: of_find");
1209 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1210 err = AFPERR_ACCESS;
1215 writtenfork = ofork;
1218 if ( ofork->of_flags & AFPFORK_DATA) {
1220 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1221 } else if (ofork->of_flags & AFPFORK_RSRC) {
1224 err = AFPERR_ACCESS; /* should never happen */
1229 offset += ad_size(ofork->of_ad, eid);
1231 /* handle bogus parameters */
1232 if (reqcount < 0 || offset < 0) {
1237 /* offset can overflow on 64-bit capable filesystems.
1238 * report disk full if that's going to happen. */
1239 if (offset + reqcount < 0) {
1244 if (!reqcount) { /* handle request counts of 0 */
1246 *rbuflen = set_off_t (offset, rbuf, is64);
1251 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1257 /* this is yucky, but dsi can stream i/o and asp can't */
1258 switch (obj->proto) {
1261 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1263 LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
1264 return( AFPERR_PARAM );
1267 if (obj->options.flags & OPTION_DEBUG) {
1268 printf("(write) len: %d\n", *rbuflen);
1269 bprint(rbuf, *rbuflen);
1272 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1275 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1280 #endif /* no afp/asp */
1284 DSI *dsi = obj->handle;
1286 /* find out what we have already and write it out. */
1287 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1289 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1290 dsi_writeflush(dsi);
1292 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1297 #if 0 /*def HAVE_SENDFILE_WRITE*/
1298 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1299 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1300 offset, dsi->datasize)) < 0) {
1308 LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
1309 goto afp_write_loop;
1311 dsi_writeflush(dsi);
1313 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1319 goto afp_write_done;
1321 #endif /* 0, was HAVE_SENDFILE_WRITE */
1323 /* loop until everything gets written. currently
1324 * dsi_write handles the end case by itself. */
1325 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1326 if ( obj->options.flags & OPTION_DEBUG ) {
1327 printf("(write) command cont'd: %d\n", cc);
1331 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1332 dsi_writeflush(dsi);
1334 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1344 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1345 if ( ad_hfileno( ofork->of_ad ) != -1 )
1346 ofork->of_flags |= AFPFORK_DIRTY;
1348 *rbuflen = set_off_t (offset, rbuf, is64);
1352 if (obj->proto == AFPPROTO_DSI) {
1353 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1354 dsi_writeflush(obj->handle);
1357 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1361 /* ---------------------------- */
1362 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1365 int ibuflen, *rbuflen;
1367 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
1370 /* ----------------------------
1371 * FIXME need to deal with SIGXFSZ signal
1373 int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
1376 int ibuflen, *rbuflen;
1378 return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
1381 /* ---------------------------- */
1382 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1385 int ibuflen, *rbuflen;
1387 struct ofork *ofork;
1389 u_int16_t ofrefnum, bitmap;
1390 u_int16_t attrbits = 0;
1393 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1394 ibuf += sizeof( ofrefnum );
1395 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1396 bitmap = ntohs( bitmap );
1397 ibuf += sizeof( bitmap );
1400 if (( ofork = of_find( ofrefnum )) == NULL ) {
1401 LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
1402 return( AFPERR_PARAM );
1404 attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
1405 attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
1407 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1408 if ( ad_refresh( ofork->of_ad ) < 0 ) {
1409 LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
1410 return( AFPERR_PARAM );
1414 if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
1415 rbuf + sizeof( u_short ), &buflen, attrbits ))) {
1419 *rbuflen = buflen + sizeof( u_short );
1420 bitmap = htons( bitmap );
1421 memcpy(rbuf, &bitmap, sizeof( bitmap ));