/*
- * $Id: fork.c,v 1.22 2002-02-14 05:59:51 jmarcus Exp $
+ * $Id: fork.c,v 1.40 2002-11-14 17:13:45 srittau Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
#include "volume.h"
#define BYTELOCK_MAX 0x7FFFFFFFU
+#define BYTELOCK_MAXL 0x7FFFFFFFFFFFFFFFULL
struct ofork *writtenfork;
+extern int getmetadata(struct vol *vol,
+ u_int16_t bitmap,
+ char *path, struct dir *dir, struct stat *st,
+ char *buf, int *buflen, struct adouble *adp, int attrbits );
static int getforkparams(ofork, bitmap, buf, buflen, attrbits )
struct ofork *ofork;
int *buflen;
const u_int16_t attrbits;
{
-#ifndef USE_LASTDID
- struct stat hst, lst, *lstp;
-#else /* USE_LASTDID */
- struct stat hst;
-#endif
struct stat st;
- struct extmap *em;
- char *data, *nameoff = NULL, *upath;
- int bit = 0, isad = 1;
- u_int32_t aint;
- u_int16_t ashort;
+ char *upath;
- if ( ad_hfileno( ofork->of_ad ) == -1 ) {
- isad = 0;
- } else {
- aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
- if ( ad_refresh( ofork->of_ad ) < 0 ) {
- LOG(log_error, logtype_default, "getforkparams: ad_refresh: %s", strerror(errno) );
- return( AFPERR_PARAM );
- }
- /* See afp_closefork() for why this is bad */
- ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
- }
+ struct adouble *adp;
+ struct dir *dir;
+ struct vol *vol;
+
/* can only get the length of the opened fork */
- if (((bitmap & (1<<FILPBIT_DFLEN)) && (ofork->of_flags & AFPFORK_RSRC)) ||
- ((bitmap & (1<<FILPBIT_RFLEN)) && (ofork->of_flags & AFPFORK_DATA))) {
+ if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
+ && (ofork->of_flags & AFPFORK_RSRC))
+ ||
+ ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
+ && (ofork->of_flags & AFPFORK_DATA))) {
return( AFPERR_BITMAP );
}
- if ( bitmap & ( 1<<FILPBIT_DFLEN | 1<<FILPBIT_FNUM |
- (1 << FILPBIT_CDATE) | (1 << FILPBIT_MDATE) |
- (1 << FILPBIT_BDATE))) {
- upath = mtoupath(ofork->of_vol, ofork->of_name);
+ if ( ad_hfileno( ofork->of_ad ) == -1 ) {
+ adp = NULL;
+ } else {
+ adp = ofork->of_ad;
+ }
+
+ vol = ofork->of_vol;
+ dir = ofork->of_dir;
+
+ if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
+ (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
+ (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
if ( ad_dfileno( ofork->of_ad ) == -1 ) {
+ upath = mtoupath(vol, ofork->of_name);
+ if (movecwd(vol, dir) < 0)
+ return( AFPERR_NOOBJ );
if ( stat( upath, &st ) < 0 )
return( AFPERR_NOOBJ );
} else {
}
}
}
+ return getmetadata(vol, bitmap, ofork->of_name, dir, &st, buf, buflen, adp, attrbits );
+}
- data = buf;
- while ( bitmap != 0 ) {
- while (( bitmap & 1 ) == 0 ) {
- bitmap = bitmap>>1;
- bit++;
- }
-
- switch ( bit ) {
- case FILPBIT_ATTR :
- if ( isad ) {
- ad_getattr(ofork->of_ad, &ashort);
- } else {
- ashort = 0;
- }
- if (attrbits)
- ashort = htons(ntohs(ashort) | attrbits);
- memcpy(data, &ashort, sizeof( ashort ));
- data += sizeof( ashort );
- break;
-
- case FILPBIT_PDID :
- memcpy(data, &ofork->of_dir->d_did, sizeof( aint ));
- data += sizeof( aint );
- break;
-
- case FILPBIT_CDATE :
- if (!isad ||
- (ad_getdate(ofork->of_ad, AD_DATE_CREATE, &aint) < 0))
- aint = AD_DATE_FROM_UNIX(st.st_mtime);
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- break;
-
- case FILPBIT_MDATE :
- if (!isad ||
- (ad_getdate(ofork->of_ad, AD_DATE_MODIFY, &aint) < 0) ||
- (AD_DATE_TO_UNIX(aint) < st.st_mtime))
- aint = AD_DATE_FROM_UNIX(st.st_mtime);
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- break;
-
- case FILPBIT_BDATE :
- if (!isad ||
- (ad_getdate(ofork->of_ad, AD_DATE_BACKUP, &aint) < 0))
- aint = AD_DATE_START;
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- break;
-
- case FILPBIT_FINFO :
- memcpy(data, isad ?
- (void *) ad_entry(ofork->of_ad, ADEID_FINDERI) :
- (void *) ufinderi, 32);
- if ( !isad ||
- memcmp( ad_entry( ofork->of_ad, ADEID_FINDERI ),
- ufinderi, 8 ) == 0 ) {
- memcpy(data, ufinderi, 8 );
- if (( em = getextmap( ofork->of_name )) != NULL ) {
- memcpy(data, em->em_type, sizeof( em->em_type ));
- memcpy(data + 4, em->em_creator,
- sizeof( em->em_creator ));
- }
- }
- data += 32;
- break;
-
- case FILPBIT_LNAME :
- nameoff = data;
- data += sizeof(u_int16_t);
- break;
-
- case FILPBIT_SNAME :
- memset(data, 0, sizeof(u_int16_t));
- data += sizeof(u_int16_t);
- break;
-
- case FILPBIT_FNUM :
- aint = 0;
-#if AD_VERSION > AD_VERSION1
- /* look in AD v2 header */
- if (isad)
- memcpy(&aint, ad_entry(ofork->of_ad, ADEID_DID), sizeof(aint));
-#endif /* AD_VERSION > AD_VERSION1 */
+/* -------------------------
+*/
+#define SHARE 0
+#define EXCL 1
+static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what, int mode)
+{
+ int lockmode;
+ int lockop;
+
+ /* NOTE: we can't write lock a read-only file. on those, we just
+ * make sure that we have a read lock set. that way, we at least prevent
+ * someone else from really setting a deny read/write on the file.
+ */
+ lockmode = (ad_getoflags(adp, eid) & O_RDWR) ?ADLOCK_WR : ADLOCK_RD;
+ lockop = (mode == EXCL)?lockmode:ADLOCK_RD;
+
+ return ad_lock(adp, eid, lockop | ADLOCK_FILELOCK | ADLOCK_UPGRADE,
+ what, 1, ofrefnum);
+}
-#ifdef CNID_DB
- aint = cnid_add(ofork->of_vol->v_db, &st,
- ofork->of_dir->d_did,
- upath, strlen(upath), aint);
- if (aint == CNID_INVALID) {
- switch (errno) {
- case CNID_ERR_PARAM:
- LOG(log_error, logtype_default, "getforkparams: Incorrect parameters passed to cnid_add");
- return(AFPERR_PARAM);
- case CNID_ERR_PATH:
- return(AFPERR_PARAM);
- case CNID_ERR_DB:
- case CNID_ERR_MAX:
- return(AFPERR_MISC);
- }
- }
-#endif /* CNID_DB */
-
- if (aint == 0) {
-#ifdef USE_LASTDID
- aint = htonl(( st.st_dev << 16 ) | ( st.st_ino & 0x0000ffff ));
-#else /* USE_LASTDID */
- lstp = lstat(upath, &lst) < 0 ? &st : &lst;
-#ifdef DID_MTAB
- aint = htonl( afpd_st_cnid ( lstp ) );
-#else /* DID_MTAB */
- aint = htonl(CNID(lstp, 1));
-#endif /* DID_MTAB */
-#endif /* USE_LASTDID */
- }
+/* -------------------------
+*/
+extern int ad_testlock(struct adouble *adp, int eid, int off);
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- break;
+static int getforkmode(struct adouble *adp, int eid, int what)
+{
+ return ad_testlock(adp, eid, what);
+}
- case FILPBIT_DFLEN :
- aint = htonl( st.st_size );
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- break;
+static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
+{
+ int ret;
+ int readset;
+ int writeset;
+ int denyreadset;
+ int denywriteset;
+ int mode;
+
+ if (! (access & (OPENACC_WR | OPENACC_RD | OPENACC_DWR | OPENACC_DRD))) {
+ return setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_NONE, SHARE);
+ }
- case FILPBIT_RFLEN :
- if ( isad ) {
- aint = htonl( ad_getentrylen( ofork->of_ad, ADEID_RFORK ));
- } else {
- aint = 0;
- }
- memcpy(data, &aint, sizeof( aint ));
- data += sizeof( aint );
- break;
+ if ((access & (OPENACC_RD | OPENACC_DRD))) {
+ if ((readset = getforkmode(adp, eid, AD_FILELOCK_OPEN_RD)) <0)
+ return readset;
+ if ((denyreadset = getforkmode(adp, eid, AD_FILELOCK_DENY_RD)) <0)
+ return denyreadset;
- default :
- return( AFPERR_BITMAP );
+ if ((access & OPENACC_RD) && denyreadset) {
+ errno = EACCES;
+ return -1;
+ }
+ if ((access & OPENACC_DRD) && readset) {
+ errno = EACCES;
+ return -1;
+ }
+ /* boolean logic is not enough, because getforkmode is not always telling the
+ * true
+ */
+ mode = ((access & OPENACC_DRD))?EXCL: SHARE;
+ if ((access & OPENACC_RD)) {
+ ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD, mode);
+ if (ret)
+ return ret;
+ }
+ if ((access & OPENACC_DRD)) {
+ ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_RD, SHARE);
+ if (ret)
+ return ret;
}
- bitmap = bitmap>>1;
- bit++;
}
-
- if ( nameoff ) {
- ashort = htons( data - buf );
- memcpy(nameoff, &ashort, sizeof( ashort ));
- aint = strlen( ofork->of_name );
- aint = ( aint > MACFILELEN ) ? MACFILELEN : aint;
- *data++ = aint;
- memcpy(data, ofork->of_name, aint );
- data += aint;
+ /* ------------same for writing -------------- */
+ if ((access & (OPENACC_WR | OPENACC_DWR))) {
+ if ((writeset = getforkmode(adp, eid, AD_FILELOCK_OPEN_WR)) <0)
+ return writeset;
+ if ((denywriteset = getforkmode(adp, eid, AD_FILELOCK_DENY_WR)) <0)
+ return denywriteset;
+
+ if ((access & OPENACC_WR) && denywriteset) {
+ errno = EACCES;
+ return -1;
+ }
+ if ((access & OPENACC_DWR) && writeset) {
+ errno = EACCES;
+ return -1;
+ }
+ mode = ((access & OPENACC_DWR))?EXCL: SHARE;
+ if ((access & OPENACC_WR)) {
+ ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR, mode);
+ if (ret)
+ return ret;
+ }
+ if ((access & OPENACC_DWR)) {
+ ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_DENY_WR, SHARE);
+ if (ret)
+ return ret;
+ }
}
-
- *buflen = data - buf;
- return( AFP_OK );
+ return 0;
}
+/* ----------------------- */
int afp_openfork(obj, ibuf, ibuflen, rbuf, rbuflen )
AFPObj *obj;
char *ibuf, *rbuf;
u_int32_t did;
u_int16_t vid, bitmap, access, ofrefnum, attrbits = 0;
char fork, *path, *upath;
-
+ struct stat *st;
+ u_int16_t bshort;
+ struct path *s_path;
+
ibuf++;
fork = *ibuf++;
memcpy(&vid, ibuf, sizeof( vid ));
memcpy(&did, ibuf, sizeof( did ));
ibuf += sizeof( int );
- if (( dir = dirsearch( vol, did )) == NULL ) {
+ if (( dir = dirlookup( vol, did )) == NULL ) {
return( AFPERR_NOOBJ );
}
return AFPERR_VLOCK;
}
- if (( path = cname( vol, dir, &ibuf )) == NULL ) {
- return( AFPERR_NOOBJ );
+ if (( s_path = cname( vol, dir, &ibuf )) == NULL ) {
+ return AFPERR_NOOBJ;
}
- if ( fork == OPENFORK_DATA ) {
- eid = ADEID_DFORK;
- adflags = ADFLAGS_DF|ADFLAGS_HF;
- } else {
- eid = ADEID_RFORK;
- adflags = ADFLAGS_HF;
+ if (*s_path->m_name == '\0') {
+ /* it's a dir ! */
+ return AFPERR_BADTYPE;
+ }
+
+ /* stat() data fork st is set because it's not a dir */
+ switch ( s_path->st_errno ) {
+ case 0:
+ break;
+ case ENOENT:
+ return AFPERR_NOOBJ;
+ case EACCES:
+ return (access & OPENACC_WR) ? AFPERR_LOCK : AFPERR_ACCESS;
+ default:
+ LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
+ return AFPERR_PARAM;
+ }
+ /* FIXME should we check first ? */
+ upath = s_path->u_name;
+ if (check_access(upath, access ) < 0) {
+ return AFPERR_ACCESS;
}
+ st = &s_path->st;
/* XXX: this probably isn't the best way to do this. the already
open bits should really be set if the fork is opened by any
program, not just this one. however, that's problematic to do
if we can't write lock files somewhere. opened is also passed to
- ad_open so that we can keep file locks together. */
- if ((opened = of_findname(vol, curdir, path))) {
- attrbits = ((opened->of_flags & AFPFORK_RSRC) ? ATTRBIT_ROPEN : 0) |
- ((opened->of_flags & AFPFORK_DATA) ? ATTRBIT_DOPEN : 0);
+ ad_open so that we can keep file locks together.
+ FIXME: add the fork we are opening?
+ */
+ if ((opened = of_findname(s_path))) {
+ attrbits = ((opened->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
+ attrbits |= ((opened->of_ad->ad_hf.adf_refcount > opened->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
+
adsame = opened->of_ad;
}
+ if ( fork == OPENFORK_DATA ) {
+ eid = ADEID_DFORK;
+ adflags = ADFLAGS_DF|ADFLAGS_HF;
+ } else {
+ eid = ADEID_RFORK;
+ adflags = ADFLAGS_HF;
+ }
+
+ path = s_path->m_name;
if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid,
- adsame)) == NULL ) {
+ adsame, st)) == NULL ) {
return( AFPERR_NFILE );
}
+
+ ret = AFPERR_NOOBJ;
if (access & OPENACC_WR) {
/* try opening in read-write mode */
- upath = mtoupath(vol, path);
- ret = AFPERR_NOOBJ;
if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
switch ( errno ) {
case EROFS:
ret = AFPERR_VLOCK;
case EACCES:
goto openfork_err;
-
break;
case ENOENT:
- {
- struct stat st;
-
- /* see if client asked for the data fork */
- if (fork == OPENFORK_DATA) {
- if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
- goto openfork_err;
- }
- adflags = ADFLAGS_DF;
-
- } else if (stat(upath, &st) == 0) {
- /* here's the deal. we only try to create the resource
- * fork if the user wants to open it for write acess. */
- if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
- goto openfork_err;
- } else
+ if (fork == OPENFORK_DATA) {
+ if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
+ goto openfork_err;
+ }
+ adflags = ADFLAGS_DF;
+
+ /* here's the deal. we only try to create the resource
+ * fork if the user wants to open it for write acess. */
+ if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
goto openfork_err;
}
break;
goto openfork_err;
break;
default:
- LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
ret = AFPERR_PARAM;
goto openfork_err;
break;
}
} else {
/* try opening in read-only mode */
- upath = mtoupath(vol, path);
ret = AFPERR_NOOBJ;
if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
switch ( errno ) {
adflags = ADFLAGS_DF;
break;
case ENOENT:
- {
- struct stat st;
-
- /* see if client asked for the data fork */
- if (fork == OPENFORK_DATA) {
- if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
- goto openfork_err;
- }
- adflags = ADFLAGS_DF;
-
- } else if (stat(upath, &st) != 0) {
+ /* see if client asked for the data fork */
+ if (fork == OPENFORK_DATA) {
+ if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
goto openfork_err;
}
+ adflags = ADFLAGS_DF;
}
break;
case EMFILE :
goto openfork_err;
break;
default:
- LOG(log_error, logtype_default, "afp_openfork: ad_open: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_openfork: ad_open: %s", strerror(errno) );
goto openfork_err;
break;
}
memcpy(rbuf, &bitmap, sizeof( u_int16_t ));
rbuf += sizeof( u_int16_t );
+ /* check WriteInhibit bit, the test is done here, after some Mac trafic capture */
+ ad_getattr(ofork->of_ad, &bshort);
+ if ((bshort & htons(ATTRBIT_NOWRITE)) && (access & OPENACC_WR)) {
+ ad_close( ofork->of_ad, adflags );
+ of_dealloc( ofork );
+ ofrefnum = 0;
+ memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
+ return(AFPERR_OLOCK);
+ }
+
/*
* synchronization locks:
- *
- * here's the ritual:
- * 1) attempt a read lock to see if we have read or write
- * privileges.
- * 2) if that succeeds, set a write lock to correspond to the
- * deny mode requested.
- * 3) whenever a file is read/written, locks get set which
- * prevent conflicts.
*/
/* don't try to lock non-existent rforks. */
if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
- /* try to see if we have access. */
- ret = 0;
- if (access & OPENACC_WR) {
- ofork->of_flags |= AFPFORK_ACCWR;
- ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
- AD_FILELOCK_WR, 1, ofrefnum);
- }
-
- if (!ret && (access & OPENACC_RD)) {
- ofork->of_flags |= AFPFORK_ACCRD;
- ret = ad_lock(ofork->of_ad, eid, ADLOCK_RD | ADLOCK_FILELOCK,
- AD_FILELOCK_RD, 1, ofrefnum);
- }
-
+ ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
/* can we access the fork? */
- if (ret < 0) {
- ad_close( ofork->of_ad, adflags );
- of_dealloc( ofork );
- ofrefnum = 0;
- memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
- return (AFPERR_DENYCONF);
- }
-
- /* now try to set the deny lock. if the fork is open for read or
- * write, a read lock will already have been set. otherwise, we upgrade
- * our lock to a write lock.
- *
- * NOTE: we can't write lock a read-only file. on those, we just
- * make sure that we have a read lock set. that way, we at least prevent
- * someone else from really setting a deny read/write on the file. */
- lockop = (ad_getoflags(ofork->of_ad, eid) & O_RDWR) ?
- ADLOCK_WR : ADLOCK_RD;
- ret = (access & OPENACC_DWR) ? ad_lock(ofork->of_ad, eid,
- lockop | ADLOCK_FILELOCK |
- ADLOCK_UPGRADE, AD_FILELOCK_WR, 1,
- ofrefnum) : 0;
- if (!ret && (access & OPENACC_DRD))
- ret = ad_lock(ofork->of_ad, eid, lockop | ADLOCK_FILELOCK |
- ADLOCK_UPGRADE, AD_FILELOCK_RD, 1, ofrefnum);
-
if (ret < 0) {
ret = errno;
ad_close( ofork->of_ad, adflags );
break;
default:
*rbuflen = 0;
- LOG(log_error, logtype_default, "afp_openfork: ad_lock: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_openfork: ad_lock: %s", strerror(errno) );
return( AFPERR_PARAM );
}
}
+ if ((access & OPENACC_WR))
+ ofork->of_flags |= AFPFORK_ACCWR;
+ if ((access & OPENACC_RD))
+ ofork->of_flags |= AFPFORK_ACCRD;
}
memcpy(rbuf, &ofrefnum, sizeof(ofrefnum));
*rbuflen = 0;
if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
+ LOG(log_error, logtype_afpd, "afp_setforkparams: of_find could not locate open fork refnum: %u", ofrefnum );
return( AFPERR_PARAM );
}
goto afp_setfork_err;
if (ad_flush( ofork->of_ad, ADFLAGS_HF ) < 0) {
- LOG(log_error, logtype_default, "afp_setforkparams: ad_flush: %s",
+ LOG(log_error, logtype_afpd, "afp_setforkparams: ad_flush: %s",
strerror(errno) );
return( AFPERR_PARAM );
}
#ifdef AFS
if ( flushfork( ofork ) < 0 ) {
- LOG(log_error, logtype_default, "afp_setforkparams: flushfork: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_setforkparams: flushfork: %s", strerror(errno) );
}
#endif /* AFS */
*/
#define ENDBIT(a) ((a) & 0x80)
#define UNLOCKBIT(a) ((a) & 0x01)
-int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj *obj;
+
+static off_t get_off_t(ibuf, is64)
+char **ibuf;
+int is64;
+{
+ u_int32_t temp;
+ off_t ret;
+
+ memcpy(&temp, *ibuf, sizeof( temp ));
+ ret = ntohl(temp); /* ntohl is unsigned */
+ *ibuf += sizeof(temp);
+
+ if (is64) {
+ memcpy(&temp, *ibuf, sizeof( temp ));
+ *ibuf += sizeof(temp);
+ ret = ntohl(temp)| (ret << 32);
+ }
+ return ret;
+}
+
+/* ---------------------- */
+static int set_off_t(offset, rbuf, is64)
+off_t offset;
+char *rbuf;
+int is64;
+{
+ u_int32_t temp;
+ int ret;
+
+ ret = 0;
+ if (is64) {
+ temp = htonl(offset >> 32);
+ memcpy(rbuf, &temp, sizeof( temp ));
+ rbuf += sizeof(temp);
+ ret = sizeof( temp );
+ offset &= 0xffffffff;
+ }
+ temp = htonl(offset);
+ memcpy(rbuf, &temp, sizeof( temp ));
+ ret += sizeof( temp );
+
+ return ret;
+}
+
+/* ---------------------- */
+static int byte_lock(obj, ibuf, ibuflen, rbuf, rbuflen, is64 )
+AFPObj *obj;
char *ibuf, *rbuf;
-int ibuflen, *rbuflen;
+int ibuflen, *rbuflen;
+int is64;
{
struct ofork *ofork;
- int32_t offset, length;
+ off_t offset, length;
int eid;
u_int16_t ofrefnum;
u_int8_t flags;
ibuf += sizeof(ofrefnum);
if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_bytelock: of_find: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_bytelock: of_find");
return( AFPERR_PARAM );
}
} else
return AFPERR_PARAM;
- memcpy(&offset, ibuf, sizeof( offset ));
- offset = ntohl(offset);
- ibuf += sizeof(offset);
-
- memcpy(&length, ibuf, sizeof( length ));
- length = ntohl(length);
- if (length == 0xFFFFFFFF)
- length = BYTELOCK_MAX;
- else if (length <= 0) {
- return AFPERR_PARAM;
- } else if ((length >= AD_FILELOCK_BASE) &&
- (ad_hfileno(ofork->of_ad) == -1))
- return AFPERR_LOCK;
+ offset = get_off_t(&ibuf, is64);
+ length = get_off_t(&ibuf, is64);
+ if (is64) {
+ if (length == -1)
+ length = BYTELOCK_MAXL;
+ else if (length <= 0) {
+ return AFPERR_PARAM;
+ } else if ((length >= AD_FILELOCK_BASE) &&
+ (ad_hfileno(ofork->of_ad) == -1)) {
+ return AFPERR_LOCK;
+ }
+ }
+ else {
+ if (length == 0xFFFFFFFF)
+ length = BYTELOCK_MAX;
+ else if (!length || (length & (1 << 31))) {
+ return AFPERR_PARAM;
+ } else if ((length >= AD_FILELOCK_BASE) &&
+ (ad_hfileno(ofork->of_ad) == -1)) {
+ return AFPERR_LOCK;
+ }
+ }
+
if (ENDBIT(flags))
offset += ad_size(ofork->of_ad, eid);
break;
}
}
-
- offset = htonl(offset);
- memcpy(rbuf, &offset, sizeof( offset ));
- *rbuflen = sizeof( offset );
+ *rbuflen = set_off_t (offset, rbuf, is64);
return( AFP_OK );
}
-#undef UNLOCKBIT
+/* --------------------------- */
+int afp_bytelock(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj *obj;
+char *ibuf, *rbuf;
+int ibuflen, *rbuflen;
+{
+ return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
+}
+
+/* --------------------------- */
+int afp_bytelock_ext(obj, ibuf, ibuflen, rbuf, rbuflen )
+AFPObj *obj;
+char *ibuf, *rbuf;
+int ibuflen, *rbuflen;
+{
+ return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
+}
+
+#undef UNLOCKBIT
+/* --------------------------- */
static __inline__ int crlf( of )
struct ofork *of;
{
cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen);
if ( cc < 0 ) {
- LOG(log_error, logtype_default, "afp_read: ad_read: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_read: ad_read: %s", strerror(errno) );
*rbuflen = 0;
return( AFPERR_PARAM );
}
return AFP_OK;
}
-int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
+/* -----------------------------
+ * with ddp, afp_read can return fewer bytes than in reqcount
+ * so return EOF only if read actually past end of file not
+ * if offset +reqcount > size of file
+ * e.g.:
+ * getfork size ==> 10430
+ * read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
+ * read fork offset 4264 size 6128 ==> 4264 (without EOF)
+ * read fork offset 9248 size 1508 ==> 1182 (EOF)
+ * 10752 is a bug in Mac 7.5.x finder
+ *
+ * with dsi, should we check that reqcount < server quantum?
+*/
+static int read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
AFPObj *obj;
char *ibuf, *rbuf;
int ibuflen, *rbuflen;
+int is64;
{
struct ofork *ofork;
off_t size;
- int32_t offset, saveoff, reqcount, savereqcount;
- int cc, err, saveerr, eid, xlate = 0;
+ off_t offset, saveoff, reqcount, savereqcount;
+ int cc, err, eid, xlate = 0;
u_int16_t ofrefnum;
u_char nlmask, nlchar;
-
+
ibuf += 2;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
ibuf += sizeof( u_short );
if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_read: of_find: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_read: of_find");
err = AFPERR_PARAM;
goto afp_read_err;
}
err = AFPERR_ACCESS;
goto afp_read_err;
}
+ offset = get_off_t(&ibuf, is64);
+ reqcount = get_off_t(&ibuf, is64);
- memcpy(&offset, ibuf, sizeof( offset ));
- offset = ntohl( offset );
- ibuf += sizeof( offset );
- memcpy(&reqcount, ibuf, sizeof( reqcount ));
- reqcount = ntohl( reqcount );
- ibuf += sizeof( reqcount );
-
- nlmask = *ibuf++;
- nlchar = *ibuf++;
-
+ if (is64) {
+ nlmask = nlchar = 0;
+ }
+ else {
+ nlmask = *ibuf++;
+ nlchar = *ibuf++;
+ }
/* if we wanted to be picky, we could add in the following
* bit: if (afp_version == 11 && !(nlmask == 0xFF || !nlmask))
*/
goto afp_read_err;
}
- /* subtract off the offset */
- size -= offset;
savereqcount = reqcount;
- if (reqcount > size) {
- reqcount = size;
- err = AFPERR_EOF;
- }
-
saveoff = offset;
- /* if EOF lock on the old reqcount, some prg may need it */
if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
err = AFPERR_LOCK;
goto afp_read_err;
#define min(a,b) ((a)<(b)?(a):(b))
*rbuflen = min( reqcount, *rbuflen );
- saveerr = err;
err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
xlate);
if (err < 0)
goto afp_read_done;
- if (saveerr < 0) {
- err = saveerr;
- goto afp_read_done;
- }
+
/* dsi can stream requests. we can only do this if we're not checking
* for an end-of-line character. oh well. */
if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
if (obj->options.flags & OPTION_DEBUG) {
printf( "(read) reply: %d/%d, %d\n", *rbuflen,
- reqcount, dsi->clientID);
+ (int) reqcount, dsi->clientID);
bprint(rbuf, *rbuflen);
}
+ /* subtract off the offset */
+ size -= offset;
+ if (reqcount > size) {
+ reqcount = size;
+ err = AFPERR_EOF;
+ }
offset += *rbuflen;
if (errno == EINVAL)
goto afp_read_loop;
else {
- LOG(log_error, logtype_default, "afp_read: ad_readfile: %s", strerror(errno));
+ LOG(log_error, logtype_afpd, "afp_read: ad_readfile: %s", strerror(errno));
goto afp_read_exit;
}
}
goto afp_read_done;
afp_read_exit:
- LOG(log_error, logtype_default, "afp_read: %s", strerror(errno));
+ LOG(log_error, logtype_afpd, "afp_read: %s", strerror(errno));
dsi_readdone(dsi);
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
obj->exit(1);
return err;
}
+/* ---------------------- */
+int afp_read(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj *obj;
+char *ibuf, *rbuf;
+int ibuflen, *rbuflen;
+{
+ return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
+
+/* ---------------------- */
+int afp_read_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj *obj;
+char *ibuf, *rbuf;
+int ibuflen, *rbuflen;
+{
+ return read_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
+
+/* ---------------------- */
int afp_flush(obj, ibuf, ibuflen, rbuf, rbuflen )
AFPObj *obj;
char *ibuf, *rbuf;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_flushfork: of_find: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_flushfork: of_find");
return( AFPERR_PARAM );
}
if ( flushfork( ofork ) < 0 ) {
- LOG(log_error, logtype_default, "afp_flushfork: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_flushfork: %s", strerror(errno) );
}
return( AFP_OK );
struct ofork *ofork;
{
struct timeval tv;
- int len, err = 0, doflush = 0;
+
+ int err = 0, doflush = 0;
if ( ad_dfileno( ofork->of_ad ) != -1 &&
fsync( ad_dfileno( ofork->of_ad )) < 0 ) {
- LOG(log_error, logtype_default, "flushfork: dfile(%d) %s",
+ LOG(log_error, logtype_afpd, "flushfork: dfile(%d) %s",
ad_dfileno(ofork->of_ad), strerror(errno) );
err = -1;
}
- if ( ad_hfileno( ofork->of_ad ) != -1 ) {
+ if ( ad_hfileno( ofork->of_ad ) != -1 &&
+ (ofork->of_flags & AFPFORK_RSRC)) {
/* read in the rfork length */
- len = ad_getentrylen(ofork->of_ad, ADEID_RFORK);
ad_refresh(ofork->of_ad);
/* set the date if we're dirty */
- if ((ofork->of_flags & AFPFORK_DIRTY) &&
- (gettimeofday(&tv, NULL) == 0)) {
+ if ((ofork->of_flags & AFPFORK_DIRTY) && !gettimeofday(&tv, NULL)) {
ad_setdate(ofork->of_ad, AD_DATE_MODIFY|AD_DATE_UNIX, tv.tv_sec);
ofork->of_flags &= ~AFPFORK_DIRTY;
doflush++;
}
- /* if we're actually flushing this fork, make sure to set the
- * length. otherwise, just use the stored length */
- if ((ofork->of_flags & AFPFORK_RSRC) &&
- (len != ad_getentrylen(ofork->of_ad, ADEID_RFORK))) {
- ad_setentrylen(ofork->of_ad, ADEID_RFORK, len);
- doflush++;
- }
-
-
- /* flush the header (if it is a resource fork) */
- if (ofork->of_flags & AFPFORK_RSRC)
- if (doflush && (ad_flush(ofork->of_ad, ADFLAGS_HF) < 0))
+ /* flush the header */
+ if (doflush && ad_flush(ofork->of_ad, ADFLAGS_HF) < 0)
err = -1;
if (fsync( ad_hfileno( ofork->of_ad )) < 0)
err = -1;
if (err < 0)
- LOG(log_error, logtype_default, "flushfork: hfile(%d) %s",
+ LOG(log_error, logtype_afpd, "flushfork: hfile(%d) %s",
ad_hfileno(ofork->of_ad), strerror(errno) );
}
{
struct ofork *ofork;
struct timeval tv;
- int adflags, aint, doflush = 0;
+ int adflags, doflush = 0;
u_int16_t ofrefnum;
*rbuflen = 0;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_closefork: of_find: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_closefork: of_find");
return( AFPERR_PARAM );
}
if ( ad_hfileno( ofork->of_ad ) != -1 ) {
adflags |= ADFLAGS_HF;
-
- aint = ad_getentrylen( ofork->of_ad, ADEID_RFORK );
- ad_refresh( ofork->of_ad );
- if ((ofork->of_flags & AFPFORK_DIRTY) &&
- (gettimeofday(&tv, NULL) == 0)) {
- ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,
- tv.tv_sec);
- doflush++;
- }
-
/*
* Only set the rfork's length if we're closing the rfork.
*/
- if ((ofork->of_flags & AFPFORK_RSRC) && aint !=
- ad_getentrylen( ofork->of_ad, ADEID_RFORK )) {
- ad_setentrylen( ofork->of_ad, ADEID_RFORK, aint );
- doflush++;
- }
- if ( doflush ) {
- ad_flush( ofork->of_ad, adflags );
+ if ((ofork->of_flags & AFPFORK_RSRC)) {
+ ad_refresh( ofork->of_ad );
+ if ((ofork->of_flags & AFPFORK_DIRTY) &&
+ !gettimeofday(&tv, NULL)) {
+ ad_setdate(ofork->of_ad, AD_DATE_MODIFY | AD_DATE_UNIX,tv.tv_sec);
+ doflush++;
+ }
+ if ( doflush ) {
+ ad_flush( ofork->of_ad, adflags );
+ }
}
}
if ( ad_close( ofork->of_ad, adflags ) < 0 ) {
- LOG(log_error, logtype_default, "afp_closefork: ad_close: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_closefork: ad_close: %s", strerror(errno) );
return( AFPERR_PARAM );
}
case ENOSPC :
return( AFPERR_DFULL );
default :
- LOG(log_error, logtype_default, "afp_write: ad_write: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_write: ad_write: %s", strerror(errno) );
return( AFPERR_PARAM );
}
}
/* FPWrite. NOTE: on an error, we always use afp_write_err as
* the client may have sent us a bunch of data that's not reflected
* in reqcount et al. */
-int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
+static int write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, is64)
AFPObj *obj;
char *ibuf, *rbuf;
int ibuflen, *rbuflen;
+int is64;
{
struct ofork *ofork;
- int32_t offset, saveoff, reqcount;
+ off_t offset, saveoff, reqcount;
int endflag, eid, xlate = 0, err = AFP_OK;
u_int16_t ofrefnum;
ssize_t cc;
ibuf++;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
ibuf += sizeof( ofrefnum );
- memcpy(&offset, ibuf, sizeof( offset ));
- offset = ntohl( offset );
- ibuf += sizeof( offset );
- memcpy(&reqcount, ibuf, sizeof( reqcount ));
- reqcount = ntohl( reqcount );
- ibuf += sizeof( reqcount );
+
+ offset = get_off_t(&ibuf, is64);
+ reqcount = get_off_t(&ibuf, is64);
if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_write: of_find: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_write: of_find");
err = AFPERR_PARAM;
goto afp_write_err;
}
if (!reqcount) { /* handle request counts of 0 */
err = AFP_OK;
- offset = htonl(offset);
- memcpy(rbuf, &offset, sizeof(offset));
+ *rbuflen = set_off_t (offset, rbuf, is64);
goto afp_write_err;
}
case AFPPROTO_ASP:
if (asp_wrtcont(obj->handle, rbuf, rbuflen) < 0) {
*rbuflen = 0;
- LOG(log_error, logtype_default, "afp_write: asp_wrtcont: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_write: asp_wrtcont: %s", strerror(errno) );
return( AFPERR_PARAM );
}
cc = AFPERR_DFULL;
break;
default :
- LOG(log_error, logtype_default, "afp_write: ad_writefile: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
goto afp_write_loop;
}
dsi_writeflush(dsi);
/* loop until everything gets written. currently
* dsi_write handles the end case by itself. */
-afp_write_loop:
while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
if ( obj->options.flags & OPTION_DEBUG ) {
printf("(write) command cont'd: %d\n", cc);
break;
}
-afp_write_done:
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
if ( ad_hfileno( ofork->of_ad ) != -1 )
ofork->of_flags |= AFPFORK_DIRTY;
- offset = htonl( offset );
-#if defined(__GNUC__) && defined(HAVE_GCC_MEMCPY_BUG)
- bcopy(&offset, rbuf, sizeof(offset));
-#else /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
- memcpy(rbuf, &offset, sizeof(offset));
-#endif /* __GNUC__ && HAVE_GCC_MEMCPY_BUG */
- *rbuflen = sizeof(offset);
+ *rbuflen = set_off_t (offset, rbuf, is64);
return( AFP_OK );
afp_write_err:
return err;
}
+/* ---------------------------- */
+int afp_write(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj *obj;
+char *ibuf, *rbuf;
+int ibuflen, *rbuflen;
+{
+ return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
+
+/* ----------------------------
+ * FIXME need to deal with SIGXFSZ signal
+*/
+int afp_write_ext(obj, ibuf, ibuflen, rbuf, rbuflen)
+AFPObj *obj;
+char *ibuf, *rbuf;
+int ibuflen, *rbuflen;
+{
+ return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
+/* ---------------------------- */
int afp_getforkparams(obj, ibuf, ibuflen, rbuf, rbuflen )
AFPObj *obj;
char *ibuf, *rbuf;
struct ofork *ofork;
int buflen, ret;
u_int16_t ofrefnum, bitmap;
+ u_int16_t attrbits = 0;
ibuf += 2;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
*rbuflen = 0;
if (( ofork = of_find( ofrefnum )) == NULL ) {
- LOG(log_error, logtype_default, "afp_getforkparams: of_find: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_getforkparams: of_find");
return( AFPERR_PARAM );
}
+ attrbits = ((ofork->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
+ attrbits |= ((ofork->of_ad->ad_hf.adf_refcount > ofork->of_ad->ad_df.adf_refcount) ? ATTRBIT_ROPEN : 0);
+
+ if ( ad_hfileno( ofork->of_ad ) != -1 ) {
+ if ( ad_refresh( ofork->of_ad ) < 0 ) {
+ LOG(log_error, logtype_afpd, "getforkparams: ad_refresh: %s", strerror(errno) );
+ return( AFPERR_PARAM );
+ }
+ }
if (( ret = getforkparams( ofork, bitmap,
- rbuf + sizeof( u_short ), &buflen, 0 )) != AFP_OK ) {
+ rbuf + sizeof( u_short ), &buflen, attrbits )) != AFP_OK ) {
return( ret );
}