2 * $Id: fork.c,v 1.9 2001-10-24 04:13:22 jmarcus 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 */
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
52 struct ofork *writtenfork;
54 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
59 const u_int16_t attrbits;
63 char *data, *nameoff = NULL, *upath;
64 int bit = 0, isad = 1;
68 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
71 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
72 if ( ad_refresh( ofork->of_ad ) < 0 ) {
73 syslog( LOG_ERR, "getforkparams: ad_refresh: %s", strerror(errno) );
74 return( AFPERR_PARAM );
76 /* See afp_closefork() for why this is bad */
77 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
80 /* can only get the length of the opened fork */
81 if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
82 ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
83 return( AFPERR_BITMAP );
86 if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
87 (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
88 (1 << FILPBIT_BDATE))) {
89 upath = mtoupath(ofork->of_vol, ofork->of_name);
90 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
91 if ( stat( upath, &st ) < 0 )
92 return( AFPERR_NOOBJ );
94 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
95 return( AFPERR_BITMAP );
101 while ( bitmap != 0 ) {
102 while (( bitmap & 1 ) == 0 ) {
110 ad_getattr(ofork->of_ad, &ashort);
115 ashort = htons(ntohs(ashort) | attrbits);
116 memcpy(data, &ashort, sizeof( ashort ));
117 data += sizeof( ashort );
121 memcpy(data, &ofork->of_dir->d_did, sizeof( aint ));
122 data += sizeof( aint );
127 (ad_getdate(ofork->of_ad, AD_DATE_CREATE, &aint) < 0))
128 aint = AD_DATE_FROM_UNIX(st.st_mtime);
129 memcpy(data, &aint, sizeof( aint ));
130 data += sizeof( aint );
135 (ad_getdate(ofork->of_ad, AD_DATE_MODIFY, &aint) < 0) ||
136 (AD_DATE_TO_UNIX(aint) < st.st_mtime))
137 aint = AD_DATE_FROM_UNIX(st.st_mtime);
138 memcpy(data, &aint, sizeof( aint ));
139 data += sizeof( aint );
144 (ad_getdate(ofork->of_ad, AD_DATE_BACKUP, &aint) < 0))
145 aint = AD_DATE_START;
146 memcpy(data, &aint, sizeof( aint ));
147 data += sizeof( aint );
152 (void *) ad_entry(ofork->of_ad, ADEID_FINDERI) :
153 (void *) ufinderi, 32);
155 memcmp( ad_entry( ofork->of_ad, ADEID_FINDERI ),
156 ufinderi, 8 ) == 0 ) {
157 memcpy(data, ufinderi, 8 );
158 if (( em = getextmap( ofork->of_name )) != NULL ) {
159 memcpy(data, em->em_type, sizeof( em->em_type ));
160 memcpy(data + 4, em->em_creator,
161 sizeof( em->em_creator ));
169 data += sizeof(u_int16_t);
173 memset(data, 0, sizeof(u_int16_t));
174 data += sizeof(u_int16_t);
179 #if AD_VERSION > AD_VERSION1
180 /* look in AD v2 header */
182 memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint));
183 #endif /* AD_VERSION > AD_VERSION1 */
186 aint = cnid_add(ofork->of_vol->v_db, &st,
187 ofork->of_dir->d_did,
188 upath, strlen(upath), aint);
195 aint = ( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff );
199 memcpy(data, &aint, sizeof( aint ));
200 data += sizeof( aint );
204 aint = htonl( st.st_size );
205 memcpy(data, &aint, sizeof( aint ));
206 data += sizeof( aint );
211 aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK ));
215 memcpy(data, &aint, sizeof( aint ));
216 data += sizeof( aint );
220 return( AFPERR_BITMAP );
227 ashort = htons( data - buf );
228 memcpy(nameoff, &ashort, sizeof( ashort ));
229 aint = strlen( ofork->of_name );
230 aint = ( aint > MACFILELEN ) ? MACFILELEN : aint;
232 memcpy(data, ofork->of_name, aint );
236 *buflen = data - buf;
240 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
243 int ibuflen, *rbuflen;
247 struct ofork *ofork, *opened;
248 struct adouble *adsame = NULL;
249 int buflen, ret, adflags, eid, lockop;
251 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
252 char fork, *path, *upath;
256 memcpy(&vid, ibuf, sizeof( vid ));
260 if (( vol = getvolbyvid( vid )) == NULL ) {
261 return( AFPERR_PARAM );
264 memcpy(&did, ibuf, sizeof( did ));
265 ibuf += sizeof( int );
267 if (( dir = dirsearch( vol, did )) == NULL ) {
268 return( AFPERR_NOOBJ );
271 memcpy(&bitmap, ibuf, sizeof( bitmap ));
272 bitmap = ntohs( bitmap );
273 ibuf += sizeof( bitmap );
274 memcpy(&access, ibuf, sizeof( access ));
275 access = ntohs( access );
276 ibuf += sizeof( access );
278 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
282 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
283 return( AFPERR_NOOBJ );
286 if ( fork == OPENFORK_DATA ) {
288 adflags = ADFLAGS_DF|ADFLAGS_HF;
291 adflags = ADFLAGS_HF;
294 /* XXX: this probably isn't the best way to do this. the already
295 open bits should really be set if the fork is opened by any
296 program, not just this one. however, that's problematic to do
297 if we can't write lock files somewhere. opened is also passed to
298 ad_open so that we can keep file locks together. */
299 if ((opened = of_findname(vol, curdir, path))) {
300 attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) |
301 ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
302 adsame = opened->of_ad;
305 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
307 return( AFPERR_NFILE );
309 if (access & OPENACC_WR) {
310 /* try opening in read-write mode */
311 upath = mtoupath(vol, path);
313 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
325 /* see if client asked for the data fork */
326 if (fork == OPENFORK_DATA) {
327 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
330 adflags = ADFLAGS_DF;
332 } else if (stat(upath, &st) == 0) {
333 /* here's the deal. we only try to create the resource
334 * fork if the user wants to open it for write acess. */
335 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
347 ret = AFPERR_BADTYPE;
351 syslog( LOG_ERR, "afp_openfork: ad_open: %s", strerror(errno) );
358 /* try opening in read-only mode */
359 upath = mtoupath(vol, path);
361 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
366 /* check for a read-only data fork */
367 if ((adflags != ADFLAGS_HF) &&
368 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
371 adflags = ADFLAGS_DF;
377 /* see if client asked for the data fork */
378 if (fork == OPENFORK_DATA) {
379 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
382 adflags = ADFLAGS_DF;
384 } else if (stat(upath, &st) != 0) {
395 ret = AFPERR_BADTYPE;
399 syslog( LOG_ERR, "afp_openfork: ad_open: %s", strerror(errno) );
406 if ((adflags & ADFLAGS_HF) &&
407 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
408 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
409 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
410 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
411 ad_flush( ofork->of_ad, adflags );
414 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
415 &buflen, attrbits )) != AFP_OK ) {
416 ad_close( ofork->of_ad, adflags );
420 *rbuflen = buflen + 2 * sizeof( u_int16_t );
421 bitmap = htons( bitmap );
422 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
423 rbuf += sizeof( u_int16_t );
426 * synchronization locks:
429 * 1) attempt a read lock to see if we have read or write
431 * 2) if that succeeds, set a write lock to correspond to the
432 * deny mode requested.
433 * 3) whenever a file is read/written, locks get set which
437 /* don't try to lock non-existent rforks. */
438 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
440 /* try to see if we have access. */
442 if (access & OPENACC_WR) {
443 ofork->of_flags |= AFPFORK_ACCWR;
444 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
445 AD_FILELOCK_WR, 1, ofrefnum);
448 if (!ret && (access & OPENACC_RD)) {
449 ofork->of_flags |= AFPFORK_ACCRD;
450 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
451 AD_FILELOCK_RD, 1, ofrefnum);
454 /* can we access the fork? */
456 ad_close( ofork->of_ad, adflags );
459 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
460 return (AFPERR_DENYCONF);
463 /* now try to set the deny lock. if the fork is open for read or
464 * write, a read lock will already have been set. otherwise, we upgrade
465 * our lock to a write lock.
467 * NOTE: we can't write lock a read-only file. on those, we just
468 * make sure that we have a read lock set. that way, we at least prevent
469 * someone else from really setting a deny read/write on the file. */
470 lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
471 ADLOCK_WR : ADLOCK_RD;
472 ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid,
473 lockop | ADLOCK_FILELOCK |
474 ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
476 if (!ret && (access & OPENACC_DRD))
477 ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
478 ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
482 ad_close( ofork->of_ad, adflags );
485 case EAGAIN: /* return data anyway */
489 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
490 return( AFPERR_DENYCONF );
494 syslog( LOG_ERR, "afp_openfork: ad_lock: %s", strerror(errno) );
495 return( AFPERR_PARAM );
500 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
506 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
510 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
513 int ibuflen, *rbuflen;
517 u_int16_t ofrefnum, bitmap;
521 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
522 ibuf += sizeof( ofrefnum );
523 memcpy(&bitmap, ibuf, sizeof(bitmap));
524 bitmap = ntohs(bitmap);
525 ibuf += sizeof( bitmap );
526 memcpy(&size, ibuf, sizeof( size ));
527 size = ntohl( size );
530 if (( ofork = of_find( ofrefnum )) == NULL ) {
531 syslog( LOG_ERR, "afp_setforkparams: of_find: %s", strerror(errno) );
532 return( AFPERR_PARAM );
535 if (ofork->of_vol->v_flags & AFPVOL_RO)
538 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
539 return AFPERR_ACCESS;
544 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
545 err = ad_dtruncate( ofork->of_ad, size );
547 goto afp_setfork_err;
548 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
549 (ofork->of_flags & AFPFORK_RSRC)) {
550 ad_refresh( ofork->of_ad );
551 err = ad_rtruncate(ofork->of_ad, size);
553 goto afp_setfork_err;
555 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
556 syslog( LOG_ERR, "afp_setforkparams: ad_flush: %s",
558 return( AFPERR_PARAM );
561 return AFPERR_BITMAP;
564 if ( flushfork( ofork ) < 0 ) {
565 syslog( LOG_ERR, "afp_setforkparams: flushfork: %m" );
580 return AFPERR_ACCESS;
591 /* for this to work correctly, we need to check for locks before each
592 * read and write. that's most easily handled by always doing an
593 * appropriate check before each ad_read/ad_write. other things
594 * that can change files like truncate are handled internally to those
597 #define ENDBIT(a) ((a) & 0x80)
598 #define UNLOCKBIT(a) ((a) & 0x01)
599 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
602 int ibuflen, *rbuflen;
605 int32_t offset, length;
612 /* figure out parameters */
614 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
616 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
617 ibuf += sizeof(ofrefnum);
619 if (( ofork = of_find( ofrefnum )) == NULL ) {
620 syslog( LOG_ERR, "afp_bytelock: of_find: %s", strerror(errno) );
621 return( AFPERR_PARAM );
624 if ( ofork->of_flags & AFPFORK_DATA) {
626 } else if (ofork->of_flags & AFPFORK_RSRC) {
631 memcpy(&offset, ibuf, sizeof( offset ));
632 offset = ntohl(offset);
633 ibuf += sizeof(offset);
635 memcpy(&length, ibuf, sizeof( length ));
636 length = ntohl(length);
637 if (length == 0xFFFFFFFF)
638 length = BYTELOCK_MAX;
639 else if (length <= 0) {
641 } else if ((length >= AD_FILELOCK_BASE) &&
642 (ad_hfileno(ofork->of_ad) == -1))
646 offset += ad_size(ofork->of_ad, eid);
648 if (offset < 0) /* error if we have a negative offset */
651 /* if the file is a read-only file, we use read locks instead of
652 * write locks. that way, we can prevent anyone from initiating
654 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
655 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
656 ADLOCK_WR : ADLOCK_RD), offset, length,
657 ofork->of_refnum) < 0) {
661 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
667 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
676 offset = htonl(offset);
677 memcpy(rbuf, &offset, sizeof( offset ));
678 *rbuflen = sizeof( offset );
684 static __inline__ int crlf( of )
689 if ( ad_hfileno( of->of_ad ) == -1 ||
690 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
692 if (( em = getextmap( of->of_name )) == NULL ||
693 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
699 if ( memcmp( ufinderi,
700 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
709 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
710 int offset, u_char nlmask,
711 u_char nlchar, char *rbuf,
712 int *rbuflen, const int xlate)
718 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
720 syslog( LOG_ERR, "afp_read: ad_read: %s", strerror(errno) );
722 return( AFPERR_PARAM );
724 if ( cc < *rbuflen ) {
732 for ( p = rbuf, q = p + cc; p < q; ) {
733 if (( *p++ & nlmask ) == nlchar ) {
744 * If this file is of type TEXT, then swap \012 to \015.
747 for ( p = rbuf, q = p + cc; p < q; p++ ) {
748 if ( *p == '\012' ) {
750 } else if ( *p == '\015' ) {
759 return( AFPERR_EOF );
764 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
767 int ibuflen, *rbuflen;
771 int32_t offset, saveoff, reqcount;
772 int cc, err, eid, xlate = 0;
774 u_char nlmask, nlchar;
777 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
778 ibuf += sizeof( u_short );
780 if (( ofork = of_find( ofrefnum )) == NULL ) {
781 syslog( LOG_ERR, "afp_read: of_find: %s", strerror(errno) );
786 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
791 memcpy(&offset, ibuf, sizeof( offset ));
792 offset = ntohl( offset );
793 ibuf += sizeof( offset );
794 memcpy(&reqcount, ibuf, sizeof( reqcount ));
795 reqcount = ntohl( reqcount );
796 ibuf += sizeof( reqcount );
801 /* if we wanted to be picky, we could add in the following
802 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
804 if (reqcount < 0 || offset < 0) {
809 if ( ofork->of_flags & AFPFORK_DATA) {
811 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
812 } else if (ofork->of_flags & AFPFORK_RSRC) {
814 } else { /* fork wasn't opened. this should never really happen. */
819 /* zero request count */
825 /* reqcount isn't always truthful. we need to deal with that. */
826 if ((size = ad_size(ofork->of_ad, eid)) == 0) {
832 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
837 #define min(a,b) ((a)<(b)?(a):(b))
838 *rbuflen = min( reqcount, *rbuflen );
839 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
844 /* dsi can stream requests. we can only do this if we're not checking
845 * for an end-of-line character. oh well. */
846 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
847 DSI *dsi = obj->handle;
849 /* subtract off the offset */
851 if (reqcount > size) {
856 if (obj->options.flags & OPTION_DEBUG) {
857 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
858 reqcount, dsi->clientID);
859 bprint(rbuf, *rbuflen);
864 /* dsi_readinit() returns size of next read buffer. by this point,
865 * we know that we're sending some data. if we fail, something
866 * horrible happened. */
867 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
870 /* due to the nature of afp packets, we have to exit if we get
871 an error. we can't do this with translation on. */
872 #ifdef HAVE_SENDFILE_READ
873 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
874 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
875 dsi->datasize) < 0) {
879 syslog(LOG_ERR, "afp_read: ad_readfile: %s", strerror(errno));
889 #endif /* HAVE_SENDFILE_READ */
891 /* fill up our buffer. */
892 while (*rbuflen > 0) {
893 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
899 if (obj->options.flags & OPTION_DEBUG) {
900 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
901 bprint(rbuf, *rbuflen);
904 /* dsi_read() also returns buffer size of next allocation */
905 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
914 syslog(LOG_ERR, "afp_read: %s", strerror(errno));
916 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
921 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
929 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
932 int ibuflen, *rbuflen;
940 memcpy(&vid, ibuf, sizeof(vid));
941 if (( vol = getvolbyvid( vid )) == NULL ) {
942 return( AFPERR_PARAM );
949 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
952 int ibuflen, *rbuflen;
959 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
961 if (( ofork = of_find( ofrefnum )) == NULL ) {
962 syslog( LOG_ERR, "afp_flushfork: of_find: %s", strerror(errno) );
963 return( AFPERR_PARAM );
966 if ( flushfork( ofork ) < 0 ) {
967 syslog( LOG_ERR, "afp_flushfork: %s", strerror(errno) );
973 /* this is very similar to closefork */
974 int flushfork( ofork )
978 int len, err = 0, doflush = 0;
980 if ( ad_dfileno( ofork->of_ad ) != -1 &&
981 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
982 syslog( LOG_ERR, "flushfork: dfile(%d) %s",
983 ad_dfileno(ofork->of_ad), strerror(errno) );
987 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
989 /* read in the rfork length */
990 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
991 ad_refresh(ofork->of_ad);
993 /* set the date if we're dirty */
994 if ((ofork->of_flags & AFPFORK_DIRTY) &&
995 (gettimeofday(&tv, NULL) == 0)) {
996 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
997 ofork->of_flags &= ~AFPFORK_DIRTY;
1001 /* if we're actually flushing this fork, make sure to set the
1002 * length. otherwise, just use the stored length */
1003 if ((ofork->of_flags & AFPFORK_RSRC) &&
1004 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
1005 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
1010 /* flush the header (if it is a resource fork) */
1011 if (ofork->of_flags & AFPFORK_RSRC)
1012 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
1015 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1019 syslog( LOG_ERR, "flushfork: hfile(%d) %m",
1020 ad_hfileno(ofork->of_ad) );
1026 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1029 int ibuflen, *rbuflen;
1031 struct ofork *ofork;
1033 int adflags, aint, doflush = 0;
1038 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1040 if (( ofork = of_find( ofrefnum )) == NULL ) {
1041 syslog( LOG_ERR, "afp_closefork: of_find: %m" );
1042 return( AFPERR_PARAM );
1046 if ((ofork->of_flags & AFPFORK_DATA) &&
1047 (ad_dfileno( ofork->of_ad ) != -1)) {
1048 adflags |= ADFLAGS_DF;
1051 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1052 adflags |= ADFLAGS_HF;
1054 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1055 ad_refresh( ofork->of_ad );
1056 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1057 (gettimeofday(&tv, NULL) == 0)) {
1058 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1064 * Only set the rfork's length if we're closing the rfork.
1066 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1067 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1068 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1072 ad_flush( ofork->of_ad, adflags );
1076 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1077 syslog( LOG_ERR, "afp_closefork: ad_close: %m" );
1078 return( AFPERR_PARAM );
1081 of_dealloc( ofork );
1086 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1087 off_t offset, char *rbuf,
1088 size_t rbuflen, const int xlate)
1094 * If this file is of type TEXT, swap \015 to \012.
1097 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1098 if ( *p == '\015' ) {
1100 } else if ( *p == '\012' ) {
1106 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1107 rbuf, rbuflen)) < 0 ) {
1112 return( AFPERR_DFULL );
1114 syslog( LOG_ERR, "afp_write: ad_write: %m" );
1115 return( AFPERR_PARAM );
1122 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1123 * the client may have sent us a bunch of data that's not reflected
1124 * in reqcount et al. */
1125 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1128 int ibuflen, *rbuflen;
1130 struct ofork *ofork;
1131 int32_t offset, saveoff, reqcount;
1132 int endflag, eid, xlate = 0, err = AFP_OK;
1136 /* figure out parameters */
1138 endflag = ENDBIT(*ibuf);
1140 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1141 ibuf += sizeof( ofrefnum );
1142 memcpy(&offset, ibuf, sizeof( offset ));
1143 offset = ntohl( offset );
1144 ibuf += sizeof( offset );
1145 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1146 reqcount = ntohl( reqcount );
1147 ibuf += sizeof( reqcount );
1149 if (( ofork = of_find( ofrefnum )) == NULL ) {
1150 syslog( LOG_ERR, "afp_write: of_find: %m" );
1155 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1156 err = AFPERR_ACCESS;
1161 writtenfork = ofork;
1164 if ( ofork->of_flags & AFPFORK_DATA) {
1166 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1167 } else if (ofork->of_flags & AFPFORK_RSRC) {
1170 err = AFPERR_ACCESS; /* should never happen */
1175 offset += ad_size(ofork->of_ad, eid);
1177 /* handle bogus parameters */
1178 if (reqcount < 0 || offset < 0) {
1183 /* offset can overflow on 64-bit capable filesystems.
1184 * report disk full if that's going to happen. */
1185 if (offset + reqcount < 0) {
1190 if (!reqcount) { /* handle request counts of 0 */
1192 offset = htonl(offset);
1193 memcpy(rbuf, &offset, sizeof(offset));
1198 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1204 /* this is yucky, but dsi can stream i/o and asp can't */
1205 switch (obj->proto) {
1208 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1210 syslog( LOG_ERR, "afp_write: asp_wrtcont: %m" );
1211 return( AFPERR_PARAM );
1214 if (obj->options.flags & OPTION_DEBUG) {
1215 printf("(write) len: %d\n", *rbuflen);
1216 bprint(rbuf, *rbuflen);
1219 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1222 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1227 #endif /* no afp/asp */
1231 DSI *dsi = obj->handle;
1233 /* find out what we have already and write it out. */
1234 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1236 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1237 dsi_writeflush(dsi);
1239 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1244 #if 0 /*def HAVE_SENDFILE_WRITE*/
1245 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1246 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1247 offset, dsi->datasize)) < 0) {
1255 syslog( LOG_ERR, "afp_write: ad_writefile: %m" );
1256 goto afp_write_loop;
1258 dsi_writeflush(dsi);
1260 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1266 goto afp_write_done;
1268 #endif /* 0, was HAVE_SENDFILE_WRITE */
1270 /* loop until everything gets written. currently
1271 * dsi_write handles the end case by itself. */
1273 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1274 if ( obj->options.flags & OPTION_DEBUG ) {
1275 printf("(write) command cont'd: %d\n", cc);
1279 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1280 dsi_writeflush(dsi);
1282 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1293 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1294 if ( ad_hfileno( ofork->of_ad ) != -1 )
1295 ofork->of_flags |= AFPFORK_DIRTY;
1297 offset = htonl( offset );
1298 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1299 bcopy(&offset, rbuf, sizeof(offset));
1300 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1301 memcpy(rbuf, &offset, sizeof(offset));
1302 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1303 *rbuflen = sizeof(offset);
1307 if (obj->proto == AFPPROTO_DSI) {
1308 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1309 dsi_writeflush(obj->handle);
1312 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1317 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1320 int ibuflen, *rbuflen;
1322 struct ofork *ofork;
1324 u_int16_t ofrefnum, bitmap;
1327 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1328 ibuf += sizeof( ofrefnum );
1329 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1330 bitmap = ntohs( bitmap );
1331 ibuf += sizeof( bitmap );
1334 if (( ofork = of_find( ofrefnum )) == NULL ) {
1335 syslog( LOG_ERR, "afp_getforkparams: of_find: %m" );
1336 return( AFPERR_PARAM );
1339 if (( ret = getforkparams( ofork, bitmap,
1340 rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1344 *rbuflen = buflen + sizeof( u_short );
1345 bitmap = htons( bitmap );
1346 memcpy(rbuf, &bitmap, sizeof( bitmap ));