2 * $Id: fork.c,v 1.8 2001-08-27 15:26:16 uhees 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 );
310 /* try opening in read-write mode with a fallback to read-only
311 * if we don't need write access. */
312 upath = mtoupath(vol, path);
314 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
319 if (access & OPENACC_WR)
322 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
323 /* check for a read-only data fork */
324 if ((adflags != ADFLAGS_HF) &&
325 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
328 adflags = ADFLAGS_DF;
335 /* see if client asked for the data fork */
336 if (fork == OPENFORK_DATA) {
337 if (((access & OPENACC_WR) &&
338 (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0))
339 || (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0,
340 ofork->of_ad) < 0)) {
343 adflags = ADFLAGS_DF;
345 } else if (stat(upath, &st) == 0) {
346 /* here's the deal. we only try to create the resource
347 * fork if the user wants to open it for write access. */
348 if ((access & OPENACC_WR) &&
349 (ad_open(upath, adflags, O_RDWR | O_CREAT,
350 0666, ofork->of_ad) < 0))
362 ret = AFPERR_BADTYPE;
366 syslog( LOG_ERR, "afp_openfork: ad_open: %s", strerror(errno) );
373 if ((adflags & ADFLAGS_HF) &&
374 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
375 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
376 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
377 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
378 ad_flush( ofork->of_ad, adflags );
381 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
382 &buflen, attrbits )) != AFP_OK ) {
383 ad_close( ofork->of_ad, adflags );
387 *rbuflen = buflen + 2 * sizeof( u_int16_t );
388 bitmap = htons( bitmap );
389 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
390 rbuf += sizeof( u_int16_t );
393 * synchronization locks:
396 * 1) attempt a read lock to see if we have read or write
398 * 2) if that succeeds, set a write lock to correspond to the
399 * deny mode requested.
400 * 3) whenever a file is read/written, locks get set which
404 /* don't try to lock non-existent rforks. */
405 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
407 /* try to see if we have access. */
409 if (access & OPENACC_WR) {
410 ofork->of_flags |= AFPFORK_ACCWR;
411 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
412 AD_FILELOCK_WR, 1, ofrefnum);
415 if (!ret && (access & OPENACC_RD)) {
416 ofork->of_flags |= AFPFORK_ACCRD;
417 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
418 AD_FILELOCK_RD, 1, ofrefnum);
421 /* can we access the fork? */
423 ad_close( ofork->of_ad, adflags );
426 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
427 return (AFPERR_DENYCONF);
430 /* now try to set the deny lock. if the fork is open for read or
431 * write, a read lock will already have been set. otherwise, we upgrade
432 * our lock to a write lock.
434 * NOTE: we can't write lock a read-only file. on those, we just
435 * make sure that we have a read lock set. that way, we at least prevent
436 * someone else from really setting a deny read/write on the file. */
437 lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
438 ADLOCK_WR : ADLOCK_RD;
439 ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid,
440 lockop | ADLOCK_FILELOCK |
441 ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
443 if (!ret && (access & OPENACC_DRD))
444 ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
445 ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
449 ad_close( ofork->of_ad, adflags );
452 case EAGAIN: /* return data anyway */
456 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
457 return( AFPERR_DENYCONF );
461 syslog( LOG_ERR, "afp_openfork: ad_lock: %s", strerror(errno) );
462 return( AFPERR_PARAM );
467 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
473 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
477 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
480 int ibuflen, *rbuflen;
484 u_int16_t ofrefnum, bitmap;
488 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
489 ibuf += sizeof( ofrefnum );
490 memcpy(&bitmap, ibuf, sizeof(bitmap));
491 bitmap = ntohs(bitmap);
492 ibuf += sizeof( bitmap );
493 memcpy(&size, ibuf, sizeof( size ));
494 size = ntohl( size );
497 if (( ofork = of_find( ofrefnum )) == NULL ) {
498 syslog( LOG_ERR, "afp_setforkparams: of_find: %s", strerror(errno) );
499 return( AFPERR_PARAM );
502 if (ofork->of_vol->v_flags & AFPVOL_RO)
505 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
506 return AFPERR_ACCESS;
511 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
512 err = ad_dtruncate( ofork->of_ad, size );
514 goto afp_setfork_err;
515 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
516 (ofork->of_flags & AFPFORK_RSRC)) {
517 ad_refresh( ofork->of_ad );
518 err = ad_rtruncate(ofork->of_ad, size);
520 goto afp_setfork_err;
522 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
523 syslog( LOG_ERR, "afp_setforkparams: ad_flush: %s",
525 return( AFPERR_PARAM );
528 return AFPERR_BITMAP;
531 if ( flushfork( ofork ) < 0 ) {
532 syslog( LOG_ERR, "afp_setforkparams: flushfork: %m" );
547 return AFPERR_ACCESS;
558 /* for this to work correctly, we need to check for locks before each
559 * read and write. that's most easily handled by always doing an
560 * appropriate check before each ad_read/ad_write. other things
561 * that can change files like truncate are handled internally to those
564 #define ENDBIT(a) ((a) & 0x80)
565 #define UNLOCKBIT(a) ((a) & 0x01)
566 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
569 int ibuflen, *rbuflen;
572 int32_t offset, length;
579 /* figure out parameters */
581 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
583 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
584 ibuf += sizeof(ofrefnum);
586 if (( ofork = of_find( ofrefnum )) == NULL ) {
587 syslog( LOG_ERR, "afp_bytelock: of_find: %s", strerror(errno) );
588 return( AFPERR_PARAM );
591 if ( ofork->of_flags & AFPFORK_DATA) {
593 } else if (ofork->of_flags & AFPFORK_RSRC) {
598 memcpy(&offset, ibuf, sizeof( offset ));
599 offset = ntohl(offset);
600 ibuf += sizeof(offset);
602 memcpy(&length, ibuf, sizeof( length ));
603 length = ntohl(length);
604 if (length == 0xFFFFFFFF)
605 length = BYTELOCK_MAX;
606 else if (length <= 0) {
608 } else if ((length >= AD_FILELOCK_BASE) &&
609 (ad_hfileno(ofork->of_ad) == -1))
613 offset += ad_size(ofork->of_ad, eid);
615 if (offset < 0) /* error if we have a negative offset */
618 /* if the file is a read-only file, we use read locks instead of
619 * write locks. that way, we can prevent anyone from initiating
621 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
622 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
623 ADLOCK_WR : ADLOCK_RD), offset, length,
624 ofork->of_refnum) < 0) {
628 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
634 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
643 offset = htonl(offset);
644 memcpy(rbuf, &offset, sizeof( offset ));
645 *rbuflen = sizeof( offset );
651 static __inline__ int crlf( of )
656 if ( ad_hfileno( of->of_ad ) == -1 ||
657 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
659 if (( em = getextmap( of->of_name )) == NULL ||
660 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
666 if ( memcmp( ufinderi,
667 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
676 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
677 int offset, u_char nlmask,
678 u_char nlchar, char *rbuf,
679 int *rbuflen, const int xlate)
685 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
687 syslog( LOG_ERR, "afp_read: ad_read: %s", strerror(errno) );
689 return( AFPERR_PARAM );
691 if ( cc < *rbuflen ) {
699 for ( p = rbuf, q = p + cc; p < q; ) {
700 if (( *p++ & nlmask ) == nlchar ) {
711 * If this file is of type TEXT, then swap \012 to \015.
714 for ( p = rbuf, q = p + cc; p < q; p++ ) {
715 if ( *p == '\012' ) {
717 } else if ( *p == '\015' ) {
726 return( AFPERR_EOF );
731 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
734 int ibuflen, *rbuflen;
738 int32_t offset, saveoff, reqcount;
739 int cc, err, eid, xlate = 0;
741 u_char nlmask, nlchar;
744 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
745 ibuf += sizeof( u_short );
747 if (( ofork = of_find( ofrefnum )) == NULL ) {
748 syslog( LOG_ERR, "afp_read: of_find: %s", strerror(errno) );
753 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
758 memcpy(&offset, ibuf, sizeof( offset ));
759 offset = ntohl( offset );
760 ibuf += sizeof( offset );
761 memcpy(&reqcount, ibuf, sizeof( reqcount ));
762 reqcount = ntohl( reqcount );
763 ibuf += sizeof( reqcount );
768 /* if we wanted to be picky, we could add in the following
769 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
771 if (reqcount < 0 || offset < 0) {
776 if ( ofork->of_flags & AFPFORK_DATA) {
778 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
779 } else if (ofork->of_flags & AFPFORK_RSRC) {
781 } else { /* fork wasn't opened. this should never really happen. */
786 /* zero request count */
792 /* reqcount isn't always truthful. we need to deal with that. */
793 if ((size = ad_size(ofork->of_ad, eid)) == 0) {
799 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
804 #define min(a,b) ((a)<(b)?(a):(b))
805 *rbuflen = min( reqcount, *rbuflen );
806 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
811 /* dsi can stream requests. we can only do this if we're not checking
812 * for an end-of-line character. oh well. */
813 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
814 DSI *dsi = obj->handle;
816 /* subtract off the offset */
818 if (reqcount > size) {
823 if (obj->options.flags & OPTION_DEBUG) {
824 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
825 reqcount, dsi->clientID);
826 bprint(rbuf, *rbuflen);
831 /* dsi_readinit() returns size of next read buffer. by this point,
832 * we know that we're sending some data. if we fail, something
833 * horrible happened. */
834 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
837 /* due to the nature of afp packets, we have to exit if we get
838 an error. we can't do this with translation on. */
839 #ifdef HAVE_SENDFILE_READ
840 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
841 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
842 dsi->datasize) < 0) {
846 syslog(LOG_ERR, "afp_read: ad_readfile: %s", strerror(errno));
856 #endif /* HAVE_SENDFILE_READ */
858 /* fill up our buffer. */
859 while (*rbuflen > 0) {
860 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
866 if (obj->options.flags & OPTION_DEBUG) {
867 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
868 bprint(rbuf, *rbuflen);
871 /* dsi_read() also returns buffer size of next allocation */
872 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
881 syslog(LOG_ERR, "afp_read: %s", strerror(errno));
883 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
888 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
896 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
899 int ibuflen, *rbuflen;
907 memcpy(&vid, ibuf, sizeof(vid));
908 if (( vol = getvolbyvid( vid )) == NULL ) {
909 return( AFPERR_PARAM );
916 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
919 int ibuflen, *rbuflen;
926 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
928 if (( ofork = of_find( ofrefnum )) == NULL ) {
929 syslog( LOG_ERR, "afp_flushfork: of_find: %s", strerror(errno) );
930 return( AFPERR_PARAM );
933 if ( flushfork( ofork ) < 0 ) {
934 syslog( LOG_ERR, "afp_flushfork: %s", strerror(errno) );
940 /* this is very similar to closefork */
941 int flushfork( ofork )
945 int len, err = 0, doflush = 0;
947 if ( ad_dfileno( ofork->of_ad ) != -1 &&
948 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
949 syslog( LOG_ERR, "flushfork: dfile(%d) %s",
950 ad_dfileno(ofork->of_ad), strerror(errno) );
954 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
956 /* read in the rfork length */
957 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
958 ad_refresh(ofork->of_ad);
960 /* set the date if we're dirty */
961 if ((ofork->of_flags & AFPFORK_DIRTY) &&
962 (gettimeofday(&tv, NULL) == 0)) {
963 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
964 ofork->of_flags &= ~AFPFORK_DIRTY;
968 /* if we're actually flushing this fork, make sure to set the
969 * length. otherwise, just use the stored length */
970 if ((ofork->of_flags & AFPFORK_RSRC) &&
971 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
972 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
977 /* flush the header (if it is a resource fork) */
978 if (ofork->of_flags & AFPFORK_RSRC)
979 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
982 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
986 syslog( LOG_ERR, "flushfork: hfile(%d) %m",
987 ad_hfileno(ofork->of_ad) );
993 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
996 int ibuflen, *rbuflen;
1000 int adflags, aint, doflush = 0;
1005 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1007 if (( ofork = of_find( ofrefnum )) == NULL ) {
1008 syslog( LOG_ERR, "afp_closefork: of_find: %m" );
1009 return( AFPERR_PARAM );
1013 if ((ofork->of_flags & AFPFORK_DATA) &&
1014 (ad_dfileno( ofork->of_ad ) != -1)) {
1015 adflags |= ADFLAGS_DF;
1018 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1019 adflags |= ADFLAGS_HF;
1021 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1022 ad_refresh( ofork->of_ad );
1023 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1024 (gettimeofday(&tv, NULL) == 0)) {
1025 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1031 * Only set the rfork's length if we're closing the rfork.
1033 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1034 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1035 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1039 ad_flush( ofork->of_ad, adflags );
1043 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1044 syslog( LOG_ERR, "afp_closefork: ad_close: %m" );
1045 return( AFPERR_PARAM );
1048 of_dealloc( ofork );
1053 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1054 off_t offset, char *rbuf,
1055 size_t rbuflen, const int xlate)
1061 * If this file is of type TEXT, swap \015 to \012.
1064 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1065 if ( *p == '\015' ) {
1067 } else if ( *p == '\012' ) {
1073 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1074 rbuf, rbuflen)) < 0 ) {
1079 return( AFPERR_DFULL );
1081 syslog( LOG_ERR, "afp_write: ad_write: %m" );
1082 return( AFPERR_PARAM );
1089 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1090 * the client may have sent us a bunch of data that's not reflected
1091 * in reqcount et al. */
1092 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1095 int ibuflen, *rbuflen;
1097 struct ofork *ofork;
1098 int32_t offset, saveoff, reqcount;
1099 int endflag, eid, xlate = 0, err = AFP_OK;
1103 /* figure out parameters */
1105 endflag = ENDBIT(*ibuf);
1107 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1108 ibuf += sizeof( ofrefnum );
1109 memcpy(&offset, ibuf, sizeof( offset ));
1110 offset = ntohl( offset );
1111 ibuf += sizeof( offset );
1112 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1113 reqcount = ntohl( reqcount );
1114 ibuf += sizeof( reqcount );
1116 if (( ofork = of_find( ofrefnum )) == NULL ) {
1117 syslog( LOG_ERR, "afp_write: of_find: %m" );
1122 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1123 err = AFPERR_ACCESS;
1128 writtenfork = ofork;
1131 if ( ofork->of_flags & AFPFORK_DATA) {
1133 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1134 } else if (ofork->of_flags & AFPFORK_RSRC) {
1137 err = AFPERR_ACCESS; /* should never happen */
1142 offset += ad_size(ofork->of_ad, eid);
1144 /* handle bogus parameters */
1145 if (reqcount < 0 || offset < 0) {
1150 /* offset can overflow on 64-bit capable filesystems.
1151 * report disk full if that's going to happen. */
1152 if (offset + reqcount < 0) {
1157 if (!reqcount) { /* handle request counts of 0 */
1159 offset = htonl(offset);
1160 memcpy(rbuf, &offset, sizeof(offset));
1165 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1171 /* this is yucky, but dsi can stream i/o and asp can't */
1172 switch (obj->proto) {
1175 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1177 syslog( LOG_ERR, "afp_write: asp_wrtcont: %m" );
1178 return( AFPERR_PARAM );
1181 if (obj->options.flags & OPTION_DEBUG) {
1182 printf("(write) len: %d\n", *rbuflen);
1183 bprint(rbuf, *rbuflen);
1186 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1189 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1194 #endif /* no afp/asp */
1198 DSI *dsi = obj->handle;
1200 /* find out what we have already and write it out. */
1201 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1203 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1204 dsi_writeflush(dsi);
1206 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1211 #if 0 /*def HAVE_SENDFILE_WRITE*/
1212 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1213 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1214 offset, dsi->datasize)) < 0) {
1222 syslog( LOG_ERR, "afp_write: ad_writefile: %m" );
1223 goto afp_write_loop;
1225 dsi_writeflush(dsi);
1227 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1233 goto afp_write_done;
1235 #endif /* 0, was HAVE_SENDFILE_WRITE */
1237 /* loop until everything gets written. currently
1238 * dsi_write handles the end case by itself. */
1240 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1241 if ( obj->options.flags & OPTION_DEBUG ) {
1242 printf("(write) command cont'd: %d\n", cc);
1246 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1247 dsi_writeflush(dsi);
1249 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1260 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1261 if ( ad_hfileno( ofork->of_ad ) != -1 )
1262 ofork->of_flags |= AFPFORK_DIRTY;
1264 offset = htonl( offset );
1265 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1266 bcopy(&offset, rbuf, sizeof(offset));
1267 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1268 memcpy(rbuf, &offset, sizeof(offset));
1269 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1270 *rbuflen = sizeof(offset);
1274 if (obj->proto == AFPPROTO_DSI) {
1275 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1276 dsi_writeflush(obj->handle);
1279 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1284 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1287 int ibuflen, *rbuflen;
1289 struct ofork *ofork;
1291 u_int16_t ofrefnum, bitmap;
1294 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1295 ibuf += sizeof( ofrefnum );
1296 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1297 bitmap = ntohs( bitmap );
1298 ibuf += sizeof( bitmap );
1301 if (( ofork = of_find( ofrefnum )) == NULL ) {
1302 syslog( LOG_ERR, "afp_getforkparams: of_find: %m" );
1303 return( AFPERR_PARAM );
1306 if (( ret = getforkparams( ofork, bitmap,
1307 rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1311 *rbuflen = buflen + sizeof( u_short );
1312 bitmap = htons( bitmap );
1313 memcpy(rbuf, &bitmap, sizeof( bitmap ));