2 * $Id: fork.c,v 1.6 2001-08-14 14:00:10 rufustfirefly 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: %m");
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);
180 /* find out if we have a fixed did already */
181 aint = cnid_lookup(ofork->of_vol->v_db, &st,
182 ofork->of_dir->d_did,
183 upath, strlen(upath));
186 /* look in AD v2 header */
189 #if AD_VERSION > AD_VERSION1
191 memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint));
192 #endif /* AD_VERSION > AD_VERSION1 */
195 aint = cnid_add(ofork->of_vol->v_db, &st,
196 ofork->of_dir->d_did,
197 upath, strlen(upath), aint);
205 aint = ( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff );
209 memcpy(data, &aint, sizeof( aint ));
210 data += sizeof( aint );
214 aint = htonl( st.st_size );
215 memcpy(data, &aint, sizeof( aint ));
216 data += sizeof( aint );
221 aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK ));
225 memcpy(data, &aint, sizeof( aint ));
226 data += sizeof( aint );
230 return( AFPERR_BITMAP );
237 ashort = htons( data - buf );
238 memcpy(nameoff, &ashort, sizeof( ashort ));
239 aint = strlen( ofork->of_name );
240 aint = ( aint > MACFILELEN ) ? MACFILELEN : aint;
242 memcpy(data, ofork->of_name, aint );
246 *buflen = data - buf;
250 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
253 int ibuflen, *rbuflen;
257 struct ofork *ofork, *opened;
258 struct adouble *adsame = NULL;
259 int buflen, ret, adflags, eid, lockop;
261 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
262 char fork, *path, *upath;
266 memcpy(&vid, ibuf, sizeof( vid ));
270 if (( vol = getvolbyvid( vid )) == NULL ) {
271 return( AFPERR_PARAM );
274 memcpy(&did, ibuf, sizeof( did ));
275 ibuf += sizeof( int );
277 if (( dir = dirsearch( vol, did )) == NULL ) {
278 return( AFPERR_NOOBJ );
281 memcpy(&bitmap, ibuf, sizeof( bitmap ));
282 bitmap = ntohs( bitmap );
283 ibuf += sizeof( bitmap );
284 memcpy(&access, ibuf, sizeof( access ));
285 access = ntohs( access );
286 ibuf += sizeof( access );
288 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
292 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
293 return( AFPERR_NOOBJ );
296 if ( fork == OPENFORK_DATA ) {
298 adflags = ADFLAGS_DF|ADFLAGS_HF;
301 adflags = ADFLAGS_HF;
304 /* XXX: this probably isn't the best way to do this. the already
305 open bits should really be set if the fork is opened by any
306 program, not just this one. however, that's problematic to do
307 if we can't write lock files somewhere. opened is also passed to
308 ad_open so that we can keep file locks together. */
309 if ((opened = of_findname(vol, curdir, path))) {
310 attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) |
311 ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
312 adsame = opened->of_ad;
315 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
317 return( AFPERR_NFILE );
320 /* try opening in read-write mode with a fallback to read-only
321 * if we don't need write access. */
322 upath = mtoupath(vol, path);
324 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
329 if (access & OPENACC_WR)
332 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
333 /* check for a read-only data fork */
334 if ((adflags != ADFLAGS_HF) &&
335 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
338 adflags = ADFLAGS_DF;
345 /* see if client asked for the data fork */
346 if (fork == OPENFORK_DATA) {
347 if (((access & OPENACC_WR) &&
348 (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0))
349 || (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0,
350 ofork->of_ad) < 0)) {
353 adflags = ADFLAGS_DF;
355 } else if (stat(upath, &st) == 0) {
356 /* here's the deal. we only try to create the resource
357 * fork if the user wants to open it for write access. */
358 if ((access & OPENACC_WR) &&
359 (ad_open(upath, adflags, O_RDWR | O_CREAT,
360 0666, ofork->of_ad) < 0))
372 ret = AFPERR_BADTYPE;
376 syslog( LOG_ERR, "afp_openfork: ad_open: %m" );
383 if ((adflags & ADFLAGS_HF) &&
384 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
385 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
386 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
387 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
388 ad_flush( ofork->of_ad, adflags );
391 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
392 &buflen, attrbits )) != AFP_OK ) {
393 ad_close( ofork->of_ad, adflags );
397 *rbuflen = buflen + 2 * sizeof( u_int16_t );
398 bitmap = htons( bitmap );
399 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
400 rbuf += sizeof( u_int16_t );
403 * synchronization locks:
406 * 1) attempt a read lock to see if we have read or write
408 * 2) if that succeeds, set a write lock to correspond to the
409 * deny mode requested.
410 * 3) whenever a file is read/written, locks get set which
414 /* don't try to lock non-existent rforks. */
415 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
417 /* try to see if we have access. */
419 if (access & OPENACC_WR) {
420 ofork->of_flags |= AFPFORK_ACCWR;
421 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
422 AD_FILELOCK_WR, 1, ofrefnum);
425 if (!ret && (access & OPENACC_RD)) {
426 ofork->of_flags |= AFPFORK_ACCRD;
427 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
428 AD_FILELOCK_RD, 1, ofrefnum);
431 /* can we access the fork? */
433 ad_close( ofork->of_ad, adflags );
436 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
437 return (AFPERR_DENYCONF);
440 /* now try to set the deny lock. if the fork is open for read or
441 * write, a read lock will already have been set. otherwise, we upgrade
442 * our lock to a write lock.
444 * NOTE: we can't write lock a read-only file. on those, we just
445 * make sure that we have a read lock set. that way, we at least prevent
446 * someone else from really setting a deny read/write on the file. */
447 lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
448 ADLOCK_WR : ADLOCK_RD;
449 ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid,
450 lockop | ADLOCK_FILELOCK |
451 ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
453 if (!ret && (access & OPENACC_DRD))
454 ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
455 ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
459 ad_close( ofork->of_ad, adflags );
462 case EAGAIN: /* return data anyway */
466 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
467 return( AFPERR_DENYCONF );
471 syslog( LOG_ERR, "afp_openfork: ad_lock: %m" );
472 return( AFPERR_PARAM );
477 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
483 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
487 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
490 int ibuflen, *rbuflen;
494 u_int16_t ofrefnum, bitmap;
498 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
499 ibuf += sizeof( ofrefnum );
500 memcpy(&bitmap, ibuf, sizeof(bitmap));
501 bitmap = ntohs(bitmap);
502 ibuf += sizeof( bitmap );
503 memcpy(&size, ibuf, sizeof( size ));
504 size = ntohl( size );
507 if (( ofork = of_find( ofrefnum )) == NULL ) {
508 syslog( LOG_ERR, "afp_setforkparams: of_find: %m" );
509 return( AFPERR_PARAM );
512 if (ofork->of_vol->v_flags & AFPVOL_RO)
515 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
516 return AFPERR_ACCESS;
521 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
522 err = ad_dtruncate( ofork->of_ad, size );
524 goto afp_setfork_err;
525 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
526 (ofork->of_flags & AFPFORK_RSRC)) {
527 ad_refresh( ofork->of_ad );
528 err = ad_rtruncate(ofork->of_ad, size);
530 goto afp_setfork_err;
532 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
533 syslog( LOG_ERR, "afp_setforkparams: ad_flush: %m" );
534 return( AFPERR_PARAM );
537 return AFPERR_BITMAP;
540 if ( flushfork( ofork ) < 0 ) {
541 syslog( LOG_ERR, "afp_setforkparams: flushfork: %m" );
556 return AFPERR_ACCESS;
567 /* for this to work correctly, we need to check for locks before each
568 * read and write. that's most easily handled by always doing an
569 * appropriate check before each ad_read/ad_write. other things
570 * that can change files like truncate are handled internally to those
573 #define ENDBIT(a) ((a) & 0x80)
574 #define UNLOCKBIT(a) ((a) & 0x01)
575 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
578 int ibuflen, *rbuflen;
581 int32_t offset, length;
588 /* figure out parameters */
590 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
592 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
593 ibuf += sizeof(ofrefnum);
595 if (( ofork = of_find( ofrefnum )) == NULL ) {
596 syslog( LOG_ERR, "afp_bytelock: of_find: %m" );
597 return( AFPERR_PARAM );
600 if ( ofork->of_flags & AFPFORK_DATA) {
602 } else if (ofork->of_flags & AFPFORK_RSRC) {
607 memcpy(&offset, ibuf, sizeof( offset ));
608 offset = ntohl(offset);
609 ibuf += sizeof(offset);
611 memcpy(&length, ibuf, sizeof( length ));
612 length = ntohl(length);
613 if (length == 0xFFFFFFFF)
614 length = BYTELOCK_MAX;
615 else if (length <= 0) {
617 } else if ((length >= AD_FILELOCK_BASE) &&
618 (ad_hfileno(ofork->of_ad) == -1))
622 offset += ad_size(ofork->of_ad, eid);
624 if (offset < 0) /* error if we have a negative offset */
627 /* if the file is a read-only file, we use read locks instead of
628 * write locks. that way, we can prevent anyone from initiating
630 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
631 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
632 ADLOCK_WR : ADLOCK_RD), offset, length,
633 ofork->of_refnum) < 0) {
637 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
643 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
652 offset = htonl(offset);
653 memcpy(rbuf, &offset, sizeof( offset ));
654 *rbuflen = sizeof( offset );
660 static __inline__ int crlf( of )
665 if ( ad_hfileno( of->of_ad ) == -1 ||
666 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
668 if (( em = getextmap( of->of_name )) == NULL ||
669 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
675 if ( memcmp( ufinderi,
676 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
685 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
686 int offset, u_char nlmask,
687 u_char nlchar, char *rbuf,
688 int *rbuflen, const int xlate)
694 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
696 syslog( LOG_ERR, "afp_read: ad_read: %m" );
698 return( AFPERR_PARAM );
700 if ( cc < *rbuflen ) {
708 for ( p = rbuf, q = p + cc; p < q; ) {
709 if (( *p++ & nlmask ) == nlchar ) {
720 * If this file is of type TEXT, then swap \012 to \015.
723 for ( p = rbuf, q = p + cc; p < q; p++ ) {
724 if ( *p == '\012' ) {
726 } else if ( *p == '\015' ) {
735 return( AFPERR_EOF );
740 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
743 int ibuflen, *rbuflen;
747 int32_t offset, saveoff, reqcount;
748 int cc, err, eid, xlate = 0;
750 u_char nlmask, nlchar;
753 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
754 ibuf += sizeof( u_short );
756 if (( ofork = of_find( ofrefnum )) == NULL ) {
757 syslog( LOG_ERR, "afp_read: of_find: %m" );
762 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
767 memcpy(&offset, ibuf, sizeof( offset ));
768 offset = ntohl( offset );
769 ibuf += sizeof( offset );
770 memcpy(&reqcount, ibuf, sizeof( reqcount ));
771 reqcount = ntohl( reqcount );
772 ibuf += sizeof( reqcount );
777 /* if we wanted to be picky, we could add in the following
778 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
780 if (reqcount < 0 || offset < 0) {
785 if ( ofork->of_flags & AFPFORK_DATA) {
787 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
788 } else if (ofork->of_flags & AFPFORK_RSRC) {
790 } else { /* fork wasn't opened. this should never really happen. */
795 /* zero request count */
801 /* reqcount isn't always truthful. we need to deal with that. */
802 if ((size = ad_size(ofork->of_ad, eid)) == 0) {
808 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
813 #define min(a,b) ((a)<(b)?(a):(b))
814 *rbuflen = min( reqcount, *rbuflen );
815 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
820 /* dsi can stream requests. we can only do this if we're not checking
821 * for an end-of-line character. oh well. */
822 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
823 DSI *dsi = obj->handle;
825 /* subtract off the offset */
827 if (reqcount > size) {
832 if (obj->options.flags & OPTION_DEBUG) {
833 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
834 reqcount, dsi->clientID);
835 bprint(rbuf, *rbuflen);
840 /* dsi_readinit() returns size of next read buffer. by this point,
841 * we know that we're sending some data. if we fail, something
842 * horrible happened. */
843 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
846 /* due to the nature of afp packets, we have to exit if we get
847 an error. we can't do this with translation on. */
848 #ifdef HAVE_SENDFILE_READ
849 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
850 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
851 dsi->datasize) < 0) {
855 syslog(LOG_ERR, "afp_read: ad_readfile: %m");
865 #endif /* HAVE_SENDFILE_READ */
867 /* fill up our buffer. */
868 while (*rbuflen > 0) {
869 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
875 if (obj->options.flags & OPTION_DEBUG) {
876 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
877 bprint(rbuf, *rbuflen);
880 /* dsi_read() also returns buffer size of next allocation */
881 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
890 syslog(LOG_ERR, "afp_read: %m");
892 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
897 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
905 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
908 int ibuflen, *rbuflen;
916 memcpy(&vid, ibuf, sizeof(vid));
917 if (( vol = getvolbyvid( vid )) == NULL ) {
918 return( AFPERR_PARAM );
925 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
928 int ibuflen, *rbuflen;
935 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
937 if (( ofork = of_find( ofrefnum )) == NULL ) {
938 syslog( LOG_ERR, "afp_flushfork: of_find: %m" );
939 return( AFPERR_PARAM );
942 if ( flushfork( ofork ) < 0 ) {
943 syslog( LOG_ERR, "afp_flushfork: %m" );
949 /* this is very similar to closefork */
950 int flushfork( ofork )
954 int len, err = 0, doflush = 0;
956 if ( ad_dfileno( ofork->of_ad ) != -1 &&
957 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
958 syslog( LOG_ERR, "flushfork: dfile(%d) %m",
959 ad_dfileno(ofork->of_ad) );
963 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
965 /* read in the rfork length */
966 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
967 ad_refresh(ofork->of_ad);
969 /* set the date if we're dirty */
970 if ((ofork->of_flags & AFPFORK_DIRTY) &&
971 (gettimeofday(&tv, NULL) == 0)) {
972 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
973 ofork->of_flags &= ~AFPFORK_DIRTY;
977 /* if we're actually flushing this fork, make sure to set the
978 * length. otherwise, just use the stored length */
979 if ((ofork->of_flags & AFPFORK_RSRC) &&
980 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
981 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
986 /* flush the header (if it is a resource fork) */
987 if (ofork->of_flags & AFPFORK_RSRC)
988 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
991 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
995 syslog( LOG_ERR, "flushfork: hfile(%d) %m",
996 ad_hfileno(ofork->of_ad) );
1002 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1005 int ibuflen, *rbuflen;
1007 struct ofork *ofork;
1009 int adflags, aint, doflush = 0;
1014 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1016 if (( ofork = of_find( ofrefnum )) == NULL ) {
1017 syslog( LOG_ERR, "afp_closefork: of_find: %m" );
1018 return( AFPERR_PARAM );
1022 if ((ofork->of_flags & AFPFORK_DATA) &&
1023 (ad_dfileno( ofork->of_ad ) != -1)) {
1024 adflags |= ADFLAGS_DF;
1027 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1028 adflags |= ADFLAGS_HF;
1030 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1031 ad_refresh( ofork->of_ad );
1032 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1033 (gettimeofday(&tv, NULL) == 0)) {
1034 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1040 * Only set the rfork's length if we're closing the rfork.
1042 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1043 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1044 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1048 ad_flush( ofork->of_ad, adflags );
1052 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1053 syslog( LOG_ERR, "afp_closefork: ad_close: %m" );
1054 return( AFPERR_PARAM );
1057 of_dealloc( ofork );
1062 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1063 off_t offset, char *rbuf,
1064 size_t rbuflen, const int xlate)
1070 * If this file is of type TEXT, swap \015 to \012.
1073 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1074 if ( *p == '\015' ) {
1076 } else if ( *p == '\012' ) {
1082 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1083 rbuf, rbuflen)) < 0 ) {
1088 return( AFPERR_DFULL );
1090 syslog( LOG_ERR, "afp_write: ad_write: %m" );
1091 return( AFPERR_PARAM );
1098 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1099 * the client may have sent us a bunch of data that's not reflected
1100 * in reqcount et al. */
1101 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1104 int ibuflen, *rbuflen;
1106 struct ofork *ofork;
1107 int32_t offset, saveoff, reqcount;
1108 int endflag, eid, xlate = 0, err = AFP_OK;
1112 /* figure out parameters */
1114 endflag = ENDBIT(*ibuf);
1116 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1117 ibuf += sizeof( ofrefnum );
1118 memcpy(&offset, ibuf, sizeof( offset ));
1119 offset = ntohl( offset );
1120 ibuf += sizeof( offset );
1121 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1122 reqcount = ntohl( reqcount );
1123 ibuf += sizeof( reqcount );
1125 if (( ofork = of_find( ofrefnum )) == NULL ) {
1126 syslog( LOG_ERR, "afp_write: of_find: %m" );
1131 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1132 err = AFPERR_ACCESS;
1137 writtenfork = ofork;
1140 if ( ofork->of_flags & AFPFORK_DATA) {
1142 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1143 } else if (ofork->of_flags & AFPFORK_RSRC) {
1146 err = AFPERR_ACCESS; /* should never happen */
1151 offset += ad_size(ofork->of_ad, eid);
1153 /* handle bogus parameters */
1154 if (reqcount < 0 || offset < 0) {
1159 /* offset can overflow on 64-bit capable filesystems.
1160 * report disk full if that's going to happen. */
1161 if (offset + reqcount < 0) {
1166 if (!reqcount) { /* handle request counts of 0 */
1168 offset = htonl(offset);
1169 memcpy(rbuf, &offset, sizeof(offset));
1174 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1180 /* this is yucky, but dsi can stream i/o and asp can't */
1181 switch (obj->proto) {
1184 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1186 syslog( LOG_ERR, "afp_write: asp_wrtcont: %m" );
1187 return( AFPERR_PARAM );
1190 if (obj->options.flags & OPTION_DEBUG) {
1191 printf("(write) len: %d\n", *rbuflen);
1192 bprint(rbuf, *rbuflen);
1195 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1198 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1203 #endif /* no afp/asp */
1207 DSI *dsi = obj->handle;
1209 /* find out what we have already and write it out. */
1210 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1212 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1213 dsi_writeflush(dsi);
1215 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1220 #if 0 /*def HAVE_SENDFILE_WRITE*/
1221 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1222 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1223 offset, dsi->datasize)) < 0) {
1231 syslog( LOG_ERR, "afp_write: ad_writefile: %m" );
1232 goto afp_write_loop;
1234 dsi_writeflush(dsi);
1236 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1242 goto afp_write_done;
1244 #endif /* 0, was HAVE_SENDFILE_WRITE */
1246 /* loop until everything gets written. currently
1247 * dsi_write handles the end case by itself. */
1249 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1250 if ( obj->options.flags & OPTION_DEBUG ) {
1251 printf("(write) command cont'd: %d\n", cc);
1255 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1256 dsi_writeflush(dsi);
1258 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1269 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1270 if ( ad_hfileno( ofork->of_ad ) != -1 )
1271 ofork->of_flags |= AFPFORK_DIRTY;
1273 offset = htonl( offset );
1274 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1275 bcopy(&offset, rbuf, sizeof(offset));
1276 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1277 memcpy(rbuf, &offset, sizeof(offset));
1278 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1279 *rbuflen = sizeof(offset);
1283 if (obj->proto == AFPPROTO_DSI) {
1284 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1285 dsi_writeflush(obj->handle);
1288 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1293 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1296 int ibuflen, *rbuflen;
1298 struct ofork *ofork;
1300 u_int16_t ofrefnum, bitmap;
1303 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1304 ibuf += sizeof( ofrefnum );
1305 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1306 bitmap = ntohs( bitmap );
1307 ibuf += sizeof( bitmap );
1310 if (( ofork = of_find( ofrefnum )) == NULL ) {
1311 syslog( LOG_ERR, "afp_getforkparams: of_find: %m" );
1312 return( AFPERR_PARAM );
1315 if (( ret = getforkparams( ofork, bitmap,
1316 rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1320 *rbuflen = buflen + sizeof( u_short );
1321 bitmap = htons( bitmap );
1322 memcpy(rbuf, &bitmap, sizeof( bitmap ));