2 * $Id: fork.c,v 1.18 2002-01-20 01:34:40 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 */
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
52 struct ofork *writtenfork;
54 static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
59 const u_int16_t attrbits;
62 struct stat hst, lst, *lstp;
63 #else /* USE_LASTDID */
68 char *data, *nameoff = NULL, *upath;
69 int bit = 0, isad = 1;
73 if ( ad_hfileno( ofork->of_ad ) == -1 ) {
76 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
77 if ( ad_refresh( ofork->of_ad ) < 0 ) {
78 LOG(log_error, logtype_default, "getforkparams: ad_refresh: %s", strerror(errno) );
79 return( AFPERR_PARAM );
81 /* See afp_closefork() for why this is bad */
82 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
85 /* can only get the length of the opened fork */
86 if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
87 ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
88 return( AFPERR_BITMAP );
91 if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
92 (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
93 (1 << FILPBIT_BDATE))) {
94 upath = mtoupath(ofork->of_vol, ofork->of_name);
95 if ( ad_dfileno( ofork->of_ad ) == -1 ) {
96 if ( stat( upath, &st ) < 0 )
97 return( AFPERR_NOOBJ );
99 if ( fstat( ad_dfileno( ofork->of_ad ), &st ) < 0 ) {
100 return( AFPERR_BITMAP );
106 while ( bitmap != 0 ) {
107 while (( bitmap & 1 ) == 0 ) {
115 ad_getattr(ofork->of_ad, &ashort);
120 ashort = htons(ntohs(ashort) | attrbits);
121 memcpy(data, &ashort, sizeof( ashort ));
122 data += sizeof( ashort );
126 memcpy(data, &ofork->of_dir->d_did, sizeof( aint ));
127 data += sizeof( aint );
132 (ad_getdate(ofork->of_ad, AD_DATE_CREATE, &aint) < 0))
133 aint = AD_DATE_FROM_UNIX(st.st_mtime);
134 memcpy(data, &aint, sizeof( aint ));
135 data += sizeof( aint );
140 (ad_getdate(ofork->of_ad, AD_DATE_MODIFY, &aint) < 0) ||
141 (AD_DATE_TO_UNIX(aint) < st.st_mtime))
142 aint = AD_DATE_FROM_UNIX(st.st_mtime);
143 memcpy(data, &aint, sizeof( aint ));
144 data += sizeof( aint );
149 (ad_getdate(ofork->of_ad, AD_DATE_BACKUP, &aint) < 0))
150 aint = AD_DATE_START;
151 memcpy(data, &aint, sizeof( aint ));
152 data += sizeof( aint );
157 (void *) ad_entry(ofork->of_ad, ADEID_FINDERI) :
158 (void *) ufinderi, 32);
160 memcmp( ad_entry( ofork->of_ad, ADEID_FINDERI ),
161 ufinderi, 8 ) == 0 ) {
162 memcpy(data, ufinderi, 8 );
163 if (( em = getextmap( ofork->of_name )) != NULL ) {
164 memcpy(data, em->em_type, sizeof( em->em_type ));
165 memcpy(data + 4, em->em_creator,
166 sizeof( em->em_creator ));
174 data += sizeof(u_int16_t);
178 memset(data, 0, sizeof(u_int16_t));
179 data += sizeof(u_int16_t);
184 #if AD_VERSION > AD_VERSION1
185 /* look in AD v2 header */
187 memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint));
188 #endif /* AD_VERSION > AD_VERSION1 */
191 aint = cnid_add(ofork->of_vol->v_db, &st,
192 ofork->of_dir->d_did,
193 upath, strlen(upath), aint);
194 if (aint > CNID_MAX) {
197 LOG(log_error, logtype_default, "getforkparams: Incorrect parameters passed to cnid_add");
198 return(AFPERR_PARAM);
200 return(AFPERR_PARAM);
210 aint = htonl(( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff ));
211 #else /* USE_LASTDID */
212 lstp = lstat(upath, &lst) < 0 ? &st : &lst;
214 aint = htonl( afpd_st_cnid ( lstp ) );
216 aint = htonl(CNID(lstp, 1));
217 #endif /* DID_MTAB */
218 #endif /* USE_LASTDID */
221 memcpy(data, &aint, sizeof( aint ));
222 data += sizeof( aint );
226 aint = htonl( st.st_size );
227 memcpy(data, &aint, sizeof( aint ));
228 data += sizeof( aint );
233 aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK ));
237 memcpy(data, &aint, sizeof( aint ));
238 data += sizeof( aint );
242 return( AFPERR_BITMAP );
249 ashort = htons( data - buf );
250 memcpy(nameoff, &ashort, sizeof( ashort ));
251 aint = strlen( ofork->of_name );
252 aint = ( aint > MACFILELEN ) ? MACFILELEN : aint;
254 memcpy(data, ofork->of_name, aint );
258 *buflen = data - buf;
262 int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
265 int ibuflen, *rbuflen;
269 struct ofork *ofork, *opened;
270 struct adouble *adsame = NULL;
271 int buflen, ret, adflags, eid, lockop;
273 u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
274 char fork, *path, *upath;
278 memcpy(&vid, ibuf, sizeof( vid ));
282 if (( vol = getvolbyvid( vid )) == NULL ) {
283 return( AFPERR_PARAM );
286 memcpy(&did, ibuf, sizeof( did ));
287 ibuf += sizeof( int );
289 if (( dir = dirsearch( vol, did )) == NULL ) {
290 return( AFPERR_NOOBJ );
293 memcpy(&bitmap, ibuf, sizeof( bitmap ));
294 bitmap = ntohs( bitmap );
295 ibuf += sizeof( bitmap );
296 memcpy(&access, ibuf, sizeof( access ));
297 access = ntohs( access );
298 ibuf += sizeof( access );
300 if ((vol->v_flags & AFPVOL_RO) && (access & OPENACC_WR)) {
304 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
305 return( AFPERR_NOOBJ );
308 if ( fork == OPENFORK_DATA ) {
310 adflags = ADFLAGS_DF|ADFLAGS_HF;
313 adflags = ADFLAGS_HF;
316 /* XXX: this probably isn't the best way to do this. the already
317 open bits should really be set if the fork is opened by any
318 program, not just this one. however, that's problematic to do
319 if we can't write lock files somewhere. opened is also passed to
320 ad_open so that we can keep file locks together. */
321 if ((opened = of_findname(vol, curdir, path))) {
322 attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) |
323 ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
324 adsame = opened->of_ad;
327 if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
329 return( AFPERR_NFILE );
331 if (access & OPENACC_WR) {
332 /* try opening in read-write mode */
333 upath = mtoupath(vol, path);
335 if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
347 /* see if client asked for the data fork */
348 if (fork == OPENFORK_DATA) {
349 if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
352 adflags = ADFLAGS_DF;
354 } else if (stat(upath, &st) == 0) {
355 /* here's the deal. we only try to create the resource
356 * fork if the user wants to open it for write acess. */
357 if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
369 ret = AFPERR_BADTYPE;
373 LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
380 /* try opening in read-only mode */
381 upath = mtoupath(vol, path);
383 if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
388 /* check for a read-only data fork */
389 if ((adflags != ADFLAGS_HF) &&
390 (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0))
393 adflags = ADFLAGS_DF;
399 /* see if client asked for the data fork */
400 if (fork == OPENFORK_DATA) {
401 if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
404 adflags = ADFLAGS_DF;
406 } else if (stat(upath, &st) != 0) {
417 ret = AFPERR_BADTYPE;
421 LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
428 if ((adflags & ADFLAGS_HF) &&
429 (ad_getoflags( ofork->of_ad, ADFLAGS_HF ) & O_CREAT)) {
430 ad_setentrylen( ofork->of_ad, ADEID_NAME, strlen( path ));
431 memcpy(ad_entry( ofork->of_ad, ADEID_NAME ), path,
432 ad_getentrylen( ofork->of_ad, ADEID_NAME ));
433 ad_flush( ofork->of_ad, adflags );
436 if (( ret = getforkparams(ofork, bitmap, rbuf + 2 * sizeof( u_int16_t ),
437 &buflen, attrbits )) != AFP_OK ) {
438 ad_close( ofork->of_ad, adflags );
442 *rbuflen = buflen + 2 * sizeof( u_int16_t );
443 bitmap = htons( bitmap );
444 memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
445 rbuf += sizeof( u_int16_t );
448 * synchronization locks:
451 * 1) attempt a read lock to see if we have read or write
453 * 2) if that succeeds, set a write lock to correspond to the
454 * deny mode requested.
455 * 3) whenever a file is read/written, locks get set which
459 /* don't try to lock non-existent rforks. */
460 if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
462 /* try to see if we have access. */
464 if (access & OPENACC_WR) {
465 ofork->of_flags |= AFPFORK_ACCWR;
466 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
467 AD_FILELOCK_WR, 1, ofrefnum);
470 if (!ret && (access & OPENACC_RD)) {
471 ofork->of_flags |= AFPFORK_ACCRD;
472 ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
473 AD_FILELOCK_RD, 1, ofrefnum);
476 /* can we access the fork? */
478 ad_close( ofork->of_ad, adflags );
481 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
482 return (AFPERR_DENYCONF);
485 /* now try to set the deny lock. if the fork is open for read or
486 * write, a read lock will already have been set. otherwise, we upgrade
487 * our lock to a write lock.
489 * NOTE: we can't write lock a read-only file. on those, we just
490 * make sure that we have a read lock set. that way, we at least prevent
491 * someone else from really setting a deny read/write on the file. */
492 lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
493 ADLOCK_WR : ADLOCK_RD;
494 ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid,
495 lockop | ADLOCK_FILELOCK |
496 ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
498 if (!ret && (access & OPENACC_DRD))
499 ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
500 ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
504 ad_close( ofork->of_ad, adflags );
507 case EAGAIN: /* return data anyway */
511 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
512 return( AFPERR_DENYCONF );
516 LOG(log_error, logtype_default, "afp_openfork: ad_lock: %s", strerror(errno) );
517 return( AFPERR_PARAM );
522 memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
528 return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
532 int afp_setforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
535 int ibuflen, *rbuflen;
539 u_int16_t ofrefnum, bitmap;
543 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
544 ibuf += sizeof( ofrefnum );
545 memcpy(&bitmap, ibuf, sizeof(bitmap));
546 bitmap = ntohs(bitmap);
547 ibuf += sizeof( bitmap );
548 memcpy(&size, ibuf, sizeof( size ));
549 size = ntohl( size );
552 if (( ofork = of_find( ofrefnum )) == NULL ) {
553 LOG(log_error, logtype_default, "afp_setforkparams: of_find: %s", strerror(errno) );
554 return( AFPERR_PARAM );
557 if (ofork->of_vol->v_flags & AFPVOL_RO)
560 if ((ofork->of_flags & AFPFORK_ACCWR) == 0)
561 return AFPERR_ACCESS;
566 if ((bitmap == (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_DATA)) {
567 err = ad_dtruncate( ofork->of_ad, size );
569 goto afp_setfork_err;
570 } else if ((bitmap == (1<<FILPBIT_RFLEN)) &&
571 (ofork->of_flags & AFPFORK_RSRC)) {
572 ad_refresh( ofork->of_ad );
573 err = ad_rtruncate(ofork->of_ad, size);
575 goto afp_setfork_err;
577 if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
578 LOG(log_error, logtype_default, "afp_setforkparams: ad_flush: %s",
580 return( AFPERR_PARAM );
583 return AFPERR_BITMAP;
586 if ( flushfork( ofork ) < 0 ) {
587 LOG(log_error, logtype_default, "afp_setforkparams: flushfork: %s", strerror(errno) );
602 return AFPERR_ACCESS;
613 /* for this to work correctly, we need to check for locks before each
614 * read and write. that's most easily handled by always doing an
615 * appropriate check before each ad_read/ad_write. other things
616 * that can change files like truncate are handled internally to those
619 #define ENDBIT(a) ((a) & 0x80)
620 #define UNLOCKBIT(a) ((a) & 0x01)
621 int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
624 int ibuflen, *rbuflen;
627 int32_t offset, length;
634 /* figure out parameters */
636 flags = *ibuf; /* first bit = endflag, lastbit = lockflag */
638 memcpy(&ofrefnum, ibuf, sizeof(ofrefnum));
639 ibuf += sizeof(ofrefnum);
641 if (( ofork = of_find( ofrefnum )) == NULL ) {
642 LOG(log_error, logtype_default, "afp_bytelock: of_find: %s", strerror(errno) );
643 return( AFPERR_PARAM );
646 if ( ofork->of_flags & AFPFORK_DATA) {
648 } else if (ofork->of_flags & AFPFORK_RSRC) {
653 memcpy(&offset, ibuf, sizeof( offset ));
654 offset = ntohl(offset);
655 ibuf += sizeof(offset);
657 memcpy(&length, ibuf, sizeof( length ));
658 length = ntohl(length);
659 if (length == 0xFFFFFFFF)
660 length = BYTELOCK_MAX;
661 else if (length <= 0) {
663 } else if ((length >= AD_FILELOCK_BASE) &&
664 (ad_hfileno(ofork->of_ad) == -1))
668 offset += ad_size(ofork->of_ad, eid);
670 if (offset < 0) /* error if we have a negative offset */
673 /* if the file is a read-only file, we use read locks instead of
674 * write locks. that way, we can prevent anyone from initiating
676 if (ad_lock(ofork->of_ad, eid, UNLOCKBIT(flags) ? ADLOCK_CLR :
677 ((ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
678 ADLOCK_WR : ADLOCK_RD), offset, length,
679 ofork->of_refnum) < 0) {
683 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_LOCK;
689 return UNLOCKBIT(flags) ? AFPERR_NORANGE : AFPERR_RANGEOVR;
698 offset = htonl(offset);
699 memcpy(rbuf, &offset, sizeof( offset ));
700 *rbuflen = sizeof( offset );
706 static __inline__ int crlf( of )
711 if ( ad_hfileno( of->of_ad ) == -1 ||
712 memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI ),
714 if (( em = getextmap( of->of_name )) == NULL ||
715 memcmp( "TEXT", em->em_type, sizeof( em->em_type )) == 0 ) {
721 if ( memcmp( ufinderi,
722 ad_entry( of->of_ad, ADEID_FINDERI ), 4 ) == 0 ) {
731 static __inline__ ssize_t read_file(struct ofork *ofork, int eid,
732 int offset, u_char nlmask,
733 u_char nlchar, char *rbuf,
734 int *rbuflen, const int xlate)
740 cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
742 LOG(log_error, logtype_default, "afp_read: ad_read: %s", strerror(errno) );
744 return( AFPERR_PARAM );
746 if ( cc < *rbuflen ) {
754 for ( p = rbuf, q = p + cc; p < q; ) {
755 if (( *p++ & nlmask ) == nlchar ) {
766 * If this file is of type TEXT, then swap \012 to \015.
769 for ( p = rbuf, q = p + cc; p < q; p++ ) {
770 if ( *p == '\012' ) {
772 } else if ( *p == '\015' ) {
781 return( AFPERR_EOF );
786 int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
789 int ibuflen, *rbuflen;
793 int32_t offset, saveoff, reqcount;
794 int cc, err, eid, xlate = 0;
796 u_char nlmask, nlchar;
799 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
800 ibuf += sizeof( u_short );
802 if (( ofork = of_find( ofrefnum )) == NULL ) {
803 LOG(log_error, logtype_default, "afp_read: of_find: %s", strerror(errno) );
808 if ((ofork->of_flags & AFPFORK_ACCRD) == 0) {
813 memcpy(&offset, ibuf, sizeof( offset ));
814 offset = ntohl( offset );
815 ibuf += sizeof( offset );
816 memcpy(&reqcount, ibuf, sizeof( reqcount ));
817 reqcount = ntohl( reqcount );
818 ibuf += sizeof( reqcount );
823 /* if we wanted to be picky, we could add in the following
824 * bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
826 if (reqcount < 0 || offset < 0) {
831 if ( ofork->of_flags & AFPFORK_DATA) {
833 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
834 } else if (ofork->of_flags & AFPFORK_RSRC) {
836 } else { /* fork wasn't opened. this should never really happen. */
841 /* zero request count */
847 /* reqcount isn't always truthful. we need to deal with that. */
848 if ((size = ad_size(ofork->of_ad, eid)) == 0) {
854 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
859 #define min(a,b) ((a)<(b)?(a):(b))
860 *rbuflen = min( reqcount, *rbuflen );
861 err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
866 /* dsi can stream requests. we can only do this if we're not checking
867 * for an end-of-line character. oh well. */
868 if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
869 DSI *dsi = obj->handle;
871 /* subtract off the offset */
873 if (reqcount > size) {
878 if (obj->options.flags & OPTION_DEBUG) {
879 printf( "(read) reply: %d/%d, %d\n", *rbuflen,
880 reqcount, dsi->clientID);
881 bprint(rbuf, *rbuflen);
886 /* dsi_readinit() returns size of next read buffer. by this point,
887 * we know that we're sending some data. if we fail, something
888 * horrible happened. */
889 if ((*rbuflen = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0)
892 /* due to the nature of afp packets, we have to exit if we get
893 an error. we can't do this with translation on. */
894 #ifdef HAVE_SENDFILE_READ
895 if (!(xlate || (obj->options.flags & OPTION_DEBUG))) {
896 if (ad_readfile(ofork->of_ad, eid, dsi->socket, offset,
897 dsi->datasize) < 0) {
901 LOG(log_error, logtype_default, "afp_read: ad_readfile: %s", strerror(errno));
911 #endif /* HAVE_SENDFILE_READ */
913 /* fill up our buffer. */
914 while (*rbuflen > 0) {
915 cc = read_file(ofork, eid, offset, nlmask, nlchar, rbuf,
921 if (obj->options.flags & OPTION_DEBUG) {
922 printf( "(read) reply: %d, %d\n", *rbuflen, dsi->clientID);
923 bprint(rbuf, *rbuflen);
926 /* dsi_read() also returns buffer size of next allocation */
927 cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */
936 LOG(log_error, logtype_default, "afp_read: %s", strerror(errno));
938 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
943 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
951 int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
954 int ibuflen, *rbuflen;
962 memcpy(&vid, ibuf, sizeof(vid));
963 if (( vol = getvolbyvid( vid )) == NULL ) {
964 return( AFPERR_PARAM );
971 int afp_flushfork(obj, ibuf, ibuflen, rbuf, rbuflen )
974 int ibuflen, *rbuflen;
981 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
983 if (( ofork = of_find( ofrefnum )) == NULL ) {
984 LOG(log_error, logtype_default, "afp_flushfork: of_find: %s", strerror(errno) );
985 return( AFPERR_PARAM );
988 if ( flushfork( ofork ) < 0 ) {
989 LOG(log_error, logtype_default, "afp_flushfork: %s", strerror(errno) );
995 /* this is very similar to closefork */
996 int flushfork( ofork )
1000 int len, err = 0, doflush = 0;
1002 if ( ad_dfileno( ofork->of_ad ) != -1 &&
1003 fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
1004 LOG(log_error, logtype_default, "flushfork: dfile(%d) %s",
1005 ad_dfileno(ofork->of_ad), strerror(errno) );
1009 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1011 /* read in the rfork length */
1012 len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
1013 ad_refresh(ofork->of_ad);
1015 /* set the date if we're dirty */
1016 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1017 (gettimeofday(&tv, NULL) == 0)) {
1018 ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
1019 ofork->of_flags &= ~AFPFORK_DIRTY;
1023 /* if we're actually flushing this fork, make sure to set the
1024 * length. otherwise, just use the stored length */
1025 if ((ofork->of_flags & AFPFORK_RSRC) &&
1026 (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
1027 ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
1032 /* flush the header (if it is a resource fork) */
1033 if (ofork->of_flags & AFPFORK_RSRC)
1034 if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
1037 if (fsync( ad_hfileno( ofork->of_ad )) < 0)
1041 LOG(log_error, logtype_default, "flushfork: hfile(%d) %s",
1042 ad_hfileno(ofork->of_ad), strerror(errno) );
1048 int afp_closefork(obj, ibuf, ibuflen, rbuf, rbuflen )
1051 int ibuflen, *rbuflen;
1053 struct ofork *ofork;
1055 int adflags, aint, doflush = 0;
1060 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1062 if (( ofork = of_find( ofrefnum )) == NULL ) {
1063 LOG(log_error, logtype_default, "afp_closefork: of_find: %s", strerror(errno) );
1064 return( AFPERR_PARAM );
1068 if ((ofork->of_flags & AFPFORK_DATA) &&
1069 (ad_dfileno( ofork->of_ad ) != -1)) {
1070 adflags |= ADFLAGS_DF;
1073 if ( ad_hfileno( ofork->of_ad ) != -1 ) {
1074 adflags |= ADFLAGS_HF;
1076 aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
1077 ad_refresh( ofork->of_ad );
1078 if ((ofork->of_flags & AFPFORK_DIRTY) &&
1079 (gettimeofday(&tv, NULL) == 0)) {
1080 ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
1086 * Only set the rfork's length if we're closing the rfork.
1088 if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
1089 ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
1090 ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
1094 ad_flush( ofork->of_ad, adflags );
1098 if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
1099 LOG(log_error, logtype_default, "afp_closefork: ad_close: %s", strerror(errno) );
1100 return( AFPERR_PARAM );
1103 of_dealloc( ofork );
1108 static __inline__ ssize_t write_file(struct ofork *ofork, int eid,
1109 off_t offset, char *rbuf,
1110 size_t rbuflen, const int xlate)
1116 * If this file is of type TEXT, swap \015 to \012.
1119 for ( p = rbuf, q = p + rbuflen; p < q; p++ ) {
1120 if ( *p == '\015' ) {
1122 } else if ( *p == '\012' ) {
1128 if (( cc = ad_write(ofork->of_ad, eid, offset, 0,
1129 rbuf, rbuflen)) < 0 ) {
1134 return( AFPERR_DFULL );
1136 LOG(log_error, logtype_default, "afp_write: ad_write: %s", strerror(errno) );
1137 return( AFPERR_PARAM );
1144 /* FPWrite. NOTE: on an error, we always use afp_write_err as
1145 * the client may have sent us a bunch of data that's not reflected
1146 * in reqcount et al. */
1147 int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
1150 int ibuflen, *rbuflen;
1152 struct ofork *ofork;
1153 int32_t offset, saveoff, reqcount;
1154 int endflag, eid, xlate = 0, err = AFP_OK;
1158 /* figure out parameters */
1160 endflag = ENDBIT(*ibuf);
1162 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1163 ibuf += sizeof( ofrefnum );
1164 memcpy(&offset, ibuf, sizeof( offset ));
1165 offset = ntohl( offset );
1166 ibuf += sizeof( offset );
1167 memcpy(&reqcount, ibuf, sizeof( reqcount ));
1168 reqcount = ntohl( reqcount );
1169 ibuf += sizeof( reqcount );
1171 if (( ofork = of_find( ofrefnum )) == NULL ) {
1172 LOG(log_error, logtype_default, "afp_write: of_find: %s", strerror(errno) );
1177 if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
1178 err = AFPERR_ACCESS;
1183 writtenfork = ofork;
1186 if ( ofork->of_flags & AFPFORK_DATA) {
1188 xlate = (ofork->of_vol->v_flags & AFPVOL_CRLF) ? crlf(ofork) : 0;
1189 } else if (ofork->of_flags & AFPFORK_RSRC) {
1192 err = AFPERR_ACCESS; /* should never happen */
1197 offset += ad_size(ofork->of_ad, eid);
1199 /* handle bogus parameters */
1200 if (reqcount < 0 || offset < 0) {
1205 /* offset can overflow on 64-bit capable filesystems.
1206 * report disk full if that's going to happen. */
1207 if (offset + reqcount < 0) {
1212 if (!reqcount) { /* handle request counts of 0 */
1214 offset = htonl(offset);
1215 memcpy(rbuf, &offset, sizeof(offset));
1220 if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff,
1226 /* this is yucky, but dsi can stream i/o and asp can't */
1227 switch (obj->proto) {
1230 if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
1232 LOG(log_error, logtype_default, "afp_write: asp_wrtcont: %s", strerror(errno) );
1233 return( AFPERR_PARAM );
1236 if (obj->options.flags & OPTION_DEBUG) {
1237 printf("(write) len: %d\n", *rbuflen);
1238 bprint(rbuf, *rbuflen);
1241 if ((cc = write_file(ofork, eid, offset, rbuf, *rbuflen,
1244 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1249 #endif /* no afp/asp */
1253 DSI *dsi = obj->handle;
1255 /* find out what we have already and write it out. */
1256 cc = dsi_writeinit(dsi, rbuf, *rbuflen);
1258 (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1259 dsi_writeflush(dsi);
1261 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1266 #if 0 /*def HAVE_SENDFILE_WRITE*/
1267 if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
1268 if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
1269 offset, dsi->datasize)) < 0) {
1277 LOG(log_error, logtype_default, "afp_write: ad_writefile: %s", strerror(errno) );
1278 goto afp_write_loop;
1280 dsi_writeflush(dsi);
1282 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1288 goto afp_write_done;
1290 #endif /* 0, was HAVE_SENDFILE_WRITE */
1292 /* loop until everything gets written. currently
1293 * dsi_write handles the end case by itself. */
1295 while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
1296 if ( obj->options.flags & OPTION_DEBUG ) {
1297 printf("(write) command cont'd: %d\n", cc);
1301 if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
1302 dsi_writeflush(dsi);
1304 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
1315 ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
1316 if ( ad_hfileno( ofork->of_ad ) != -1 )
1317 ofork->of_flags |= AFPFORK_DIRTY;
1319 offset = htonl( offset );
1320 #if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
1321 bcopy(&offset, rbuf, sizeof(offset));
1322 #else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1323 memcpy(rbuf, &offset, sizeof(offset));
1324 #endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
1325 *rbuflen = sizeof(offset);
1329 if (obj->proto == AFPPROTO_DSI) {
1330 dsi_writeinit(obj->handle, rbuf, *rbuflen);
1331 dsi_writeflush(obj->handle);
1334 *rbuflen = (err == AFP_OK) ? sizeof(offset) : 0;
1339 int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1342 int ibuflen, *rbuflen;
1344 struct ofork *ofork;
1346 u_int16_t ofrefnum, bitmap;
1349 memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
1350 ibuf += sizeof( ofrefnum );
1351 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1352 bitmap = ntohs( bitmap );
1353 ibuf += sizeof( bitmap );
1356 if (( ofork = of_find( ofrefnum )) == NULL ) {
1357 LOG(log_error, logtype_default, "afp_getforkparams: of_find: %s", strerror(errno) );
1358 return( AFPERR_PARAM );
1361 if (( ret = getforkparams( ofork, bitmap,
1362 rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
1366 *rbuflen = buflen + sizeof( u_short );
1367 bitmap = htons( bitmap );
1368 memcpy(rbuf, &bitmap, sizeof( bitmap ));