* afs_index
*/
-#include "../afs/param.h" /* Should be always first */
+#include <afsconfig.h>
+#include "../afs/param.h"
+
+RCSID("$Header$");
+
#include "../afs/sysincludes.h" /* Standard vendor system headers */
#include "../afs/afsincludes.h" /* Afs-based standard headers */
#include "../afs/afs_stats.h" /* statistics */
extern afs_rwlock_t afs_xcbhash;
extern struct afs_exporter *afs_nfsexporter;
extern char *afs_sysname;
+extern char *afs_sysnamelist[];
+extern int afs_sysnamecount;
extern struct afs_q VLRU; /*vcache LRU*/
#ifdef AFS_LINUX22_ENV
extern struct inode_operations afs_symlink_iops, afs_dir_iops;
volnamep = &avc->linkData[1];
tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
}
- if (!tcell) return ENODEV;
+ if (!tcell) return ENOENT;
mtptCell = tcell->cell; /* The cell for the mountpoint */
if (tcell->lcellp) {
}
}
- if (!tvp) return ENOENT; /* Couldn't find the volume */
+ if (!tvp) return ENODEV; /* Couldn't find the volume */
/* Don't cross mountpoint from a BK to a BK volume */
if ((avc->states & CBackup) && (tvp->states & VBackup)) {
tfid.Cell = tvp->cell;
afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
- if (!tvp) return ENOENT; /* oops, can't do it */
+ if (!tvp) return ENODEV; /* oops, can't do it */
}
if (avc->mvid == 0)
return 1;
}
-Check_AtSys(avc, aname, outb, areq)
- register struct vcache *avc;
- char *aname, **outb;
- struct vrequest *areq;
-{
- register char *tname;
- register int error = 0, offset = -1;
-
- for (tname=aname; *tname; tname++) /*Move to the end of the string*/;
-
- /*
- * If the current string is 4 chars long or more, check to see if the
- * tail end is "@sys".
- */
- if ((tname >= aname + 4) && (AFS_EQ_ATSYS(tname-4)))
- offset = (tname - 4) - aname;
- if (offset < 0) {
- tname = aname;
- } else {
- tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
- if (offset)
- strncpy(tname, aname, offset);
- if (!afs_nfsexporter)
- strcpy(tname+offset, (afs_sysname ? afs_sysname : SYS_NAME ));
- else {
- register struct unixuser *au;
- register afs_int32 error;
- au = afs_GetUser(areq->uid, avc->fid.Cell, 0); afs_PutUser(au, 0);
- if (au->exporter) {
- error = EXP_SYSNAME(au->exporter, (char *)0, tname+offset);
- if (error)
- strcpy(tname+offset, "@sys");
- } else {
- strcpy(tname+offset, (afs_sysname ? afs_sysname : SYS_NAME ));
- }
- }
- error = 1;
- }
- *outb = tname;
- return error;
-}
-
-
-char *afs_getsysname(areq, adp)
+afs_getsysname(areq, adp, bufp)
register struct vrequest *areq;
- register struct vcache *adp; {
+ register struct vcache *adp;
+ register char *bufp;
+{
static char sysname[MAXSYSNAME];
register struct unixuser *au;
register afs_int32 error;
+ if (!afs_nfsexporter) {
+ strcpy(bufp, afs_sysname);
+ return 0;
+ }
AFS_STATCNT(getsysname);
- /* this whole interface is wrong, it should take a buffer ptr and copy
- * the data out.
- */
au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
afs_PutUser(au, 0);
if (au->exporter) {
- error = EXP_SYSNAME(au->exporter, (char *)0, sysname);
- if (error) return "@sys";
- else return sysname;
+ error = EXP_SYSNAME(au->exporter, (char *)0, bufp);
+ if (error)
+ strcpy(bufp, "@sys");
+ return -1;
} else {
- return (afs_sysname == 0? SYS_NAME : afs_sysname);
+ strcpy(bufp, afs_sysname);
+ return 0;
}
}
-void afs_HandleAtName(aname, aresult, areq, adp)
- register char *aname;
- register char *aresult;
- register struct vrequest *areq;
- register struct vcache *adp; {
- register int tlen;
- AFS_STATCNT(HandleAtName);
- tlen = strlen(aname);
- if (tlen >= 4 && strcmp(aname+tlen-4, "@sys")==0) {
- strncpy(aresult, aname, tlen-4);
- strcpy(aresult+tlen-4, afs_getsysname(areq, adp));
- }
- else strcpy(aresult, aname);
+Check_AtSys(avc, aname, state, areq)
+ register struct vcache *avc;
+ char *aname;
+ struct sysname_info *state;
+ struct vrequest *areq;
+{
+ if (AFS_EQ_ATSYS(aname)) {
+ state->offset = 0;
+ state->name = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
+ state->allocked = 1;
+ state->index = afs_getsysname(areq, avc, state->name);
+ } else {
+ state->offset = -1;
+ state->allocked = 0;
+ state->index = 0;
+ state->name = aname;
}
+}
+
+Next_AtSys(avc, areq, state)
+ register struct vcache *avc;
+ struct vrequest *areq;
+ struct sysname_info *state;
+{
+ if (state->index == -1)
+ return 0; /* No list */
+
+ /* Check for the initial state of aname != "@sys" in Check_AtSys*/
+ if (state->offset == -1 && state->allocked == 0) {
+ register char *tname;
+ /* Check for .*@sys */
+ for (tname=state->name; *tname; tname++)
+ /*Move to the end of the string*/;
+ if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname-4))) {
+ state->offset = (tname - 4) - state->name;
+ tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+ strncpy(tname, state->name, state->offset);
+ state->name = tname;
+ state->allocked = 1;
+ state->index = afs_getsysname(areq, avc, state->name+state->offset);
+ return 1;
+ } else
+ return 0; /* .*@sys doesn't match either */
+ } else if (++(state->index) >= afs_sysnamecount
+ || !afs_sysnamelist[state->index])
+ return 0; /* end of list */
+ strcpy(state->name+state->offset, afs_sysnamelist[state->index]);
+ return 1;
+}
#if (defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV))
extern int BlobScan(ino64_t *afile, afs_int32 ablob);
#else
+#if defined AFS_LINUX_64BIT_KERNEL
+extern int BlobScan(long *afile, afs_int32 ablob);
+#else
extern int BlobScan(afs_int32 *afile, afs_int32 ablob);
#endif
+#endif
/* called with an unlocked directory and directory cookie. Areqp
/* actually a serious error, probably should panic. Probably will
* panic soon, oh well. */
ReleaseReadLock(&afs_xvcache);
+ afs_warnuser("afs_DoBulkStat: VLRU empty!");
goto done;
}
if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
refpanic ("Bulkstat VLRU inconsistent6");
ReleaseWriteLock(&afs_xvcache);
+ ObtainWriteLock(&afs_xcbhash, 494);
+
/* We need to check the flags again. We may have missed
* something while we were waiting for a lock.
*/
if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
flagIndex++;
ReleaseWriteLock(&tvcp->lock);
+ ReleaseWriteLock(&afs_xcbhash);
afs_PutVCache(tvcp);
continue;
}
tvcp->v.v_op = &afs_symlink_iops;
#endif
- ObtainWriteLock(&afs_xcbhash, 494);
-
- /* We need to check the flags once more. We may have missed
- * something while we were waiting for a lock.
- */
- if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
- flagIndex++;
- ReleaseWriteLock(&afs_xcbhash);
- ReleaseWriteLock(&tvcp->lock);
- afs_PutVCache(tvcp);
- continue;
- }
-
/* do some accounting for bulk stats: mark this entry as
* loaded, so we can tell if we use it before it gets
* recycled.
int flags;
struct vnode *rdir;
#else
+#if defined(UKERNEL)
+afs_lookup(adp, aname, avcp, acred, flags)
+ int flags;
+#else
afs_lookup(adp, aname, avcp, acred)
-#endif
+#endif /* UKERNEL */
+#endif /* SUN5 || SGI */
OSI_VC_DECL(adp);
struct vcache **avcp;
char *aname;
extern afs_int32 afs_mariner; /*Writing activity to log?*/
OSI_VC_CONVERT(adp)
afs_hyper_t versionNo;
+ int no_read_access = 0;
+ struct sysname_info sysState; /* used only for @sys checking */
AFS_STATCNT(afs_lookup);
#ifdef AFS_OSF_ENV
goto done;
}
- /* lookup the name aname in the appropriate dir, and return a cache entry
- on the resulting fid */
-
- /*
- * check for, and handle "@sys" if it's there. We should be able
- * to avoid the alloc and the strcpy with a little work, but it's
- * not pressing. If there aren't any remote users (ie, via the
- * NFS translator), we have a slightly easier job.
- * the faster way to do this is to check for *aname == '@' and if
- * it's there, check for @sys, otherwise, assume there's no @sys
- * then, if the lookup fails, check for .*@sys...
- */
- if (!AFS_EQ_ATSYS(aname)) {
- tname = aname;
- }
- else {
- tname = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
- if (!afs_nfsexporter)
- strcpy(tname, (afs_sysname ? afs_sysname : SYS_NAME ));
- else {
- register struct unixuser *au;
- register afs_int32 error;
- au = afs_GetUser(treq.uid, adp->fid.Cell, 0); afs_PutUser(au, 0);
- if (au->exporter) {
- error = EXP_SYSNAME(au->exporter, (char *)0, tname);
- if (error)
- strcpy(tname, "@sys");
- } else {
- strcpy(tname, (afs_sysname ? afs_sysname : SYS_NAME ));
- }
- }
- }
-
/* come back to here if we encounter a non-existent object in a read-only
volume's directory */
else code = 0;
/* watch for ".." in a volume root */
- if (adp->mvstat == 2 && tname[0] == '.' && tname[1] == '.' && !tname[2]) {
+ if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
/* looking up ".." in root via special hacks */
if (adp->mvid == (struct VenusFid *) 0 || adp->mvid->Fid.Volume == 0) {
#ifdef AFS_OSF_ENV
else adp->last_looker = treq.uid;
}
+ /* Check for read access as well. We need read access in order to
+ stat files, but not to stat subdirectories. */
+ if (!afs_AccessOK(adp, PRSFS_READ, &treq, CHECK_MODE_BITS))
+ no_read_access = 1;
/* special case lookup of ".". Can we check for it sooner in this code,
* for instance, way up before "redo:" ??
* I'm not fiddling with the LRUQ here, either, perhaps I should, or else
* invent a lightweight version of GetVCache.
*/
- if (tname[0] == '.' && !tname[1]) { /* special case */
+ if (aname[0] == '.' && !aname[1]) { /* special case */
ObtainReadLock(&afs_xvcache);
osi_vnhold(adp, 0);
ReleaseReadLock(&afs_xvcache);
goto done;
}
+ Check_AtSys(adp, aname, &sysState, &treq);
+ tname = sysState.name;
+
+ /* 1st Check_AtSys and lookup by tname is required here, for now,
+ because the dnlc is *not* told to remove entries for the parent
+ dir of file/dir op that afs_LocalHero likes, but dnlc is informed
+ if the cached entry for the parent dir is invalidated for a
+ non-local change.
+ Otherwise, we'd be able to do a dnlc lookup on an entry ending
+ w/@sys and know the dnlc was consistent with reality. */
tvc = osi_dnlc_lookup (adp, tname, WRITE_LOCK);
*avcp = tvc; /* maybe wasn't initialized, but it is now */
-#ifdef AFS_LINUX22_ENV
if (tvc) {
- if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
- AFS_RELE(tvc);
- *avcp = 0;
- }
- else {
+ if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
+ /* need read access on dir to stat non-directory / non-link */
+ afs_PutVCache(tvc, WRITE_LOCK);
+ *avcp = (struct vcache *)0;
+ code = EACCES;
+ goto done;
+ }
+#ifdef AFS_LINUX22_ENV
+ if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
+ AFS_RELE(tvc);
+ *avcp = 0;
+ }
+ else {
+ code = 0;
+ hit = 1;
+ goto done;
+ }
+#else /* non - LINUX */
code = 0;
hit = 1;
goto done;
- }
- }
-#else /* non - LINUX */
- if (tvc) {
- code = 0;
- hit = 1;
- goto done;
- }
#endif /* linux22 */
+ }
{
register struct dcache *tdc;
/* now we will just call dir package with appropriate inode.
Dirs are always fetched in their entirety for now */
- /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
ObtainReadLock(&adp->lock);
/*
/* Save the version number for when we call osi_dnlc_enter */
hset(versionNo, tdc->f.versionNo);
+ /*
+ * check for, and handle "@sys" if it's there. We should be able
+ * to avoid the alloc and the strcpy with a little work, but it's
+ * not pressing. If there aren't any remote users (ie, via the
+ * NFS translator), we have a slightly easier job.
+ * the faster way to do this is to check for *aname == '@' and if
+ * it's there, check for @sys, otherwise, assume there's no @sys
+ * then, if the lookup fails, check for .*@sys...
+ */
+ /* above now implemented by Check_AtSys and Next_AtSys */
+
+ /* lookup the name in the appropriate dir, and return a cache entry
+ on the resulting fid */
theDir = tdc->f.inode;
- code = afs_dir_LookupOffset(&theDir, tname, &tfid.Fid, &dirCookie);
- if (code == ENOENT && tname == aname) {
- int len;
- len = strlen(aname);
- if (len >= 4 && AFS_EQ_ATSYS(aname+len-4)) {
- tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
- afs_HandleAtName(aname, tname, &treq, adp);
- code = afs_dir_LookupOffset(&theDir, tname, &tfid.Fid, &dirCookie);
- }
+ code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
+
+ /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
+ while (code == ENOENT && Next_AtSys(adp, &treq, &sysState)) {
+ code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
}
+ tname = sysState.name;
+
ReleaseReadLock(&adp->lock);
afs_PutDCache(tdc);
tvc->parentVnode = adp->fid.Fid.Vnode;
tvc->parentUnique = adp->fid.Fid.Unique;
tvc->states &= ~CBulkStat;
+
+#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
+ if (!(flags & AFS_LOOKUP_NOEVAL))
+ /* don't eval mount points */
+#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
if (tvc->mvstat == 1) {
/* a mt point, possibly unevaluated */
struct volume *tvolp;
ObtainWriteLock(&tvc->lock,133);
code = EvalMountPoint(tvc, adp, &tvolp, &treq);
ReleaseWriteLock(&tvc->lock);
+
+ if (code) {
+ if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
+ goto done;
+ }
+
/* next, we want to continue using the target of the mt point */
if (tvc->mvid && (tvc->states & CMValid)) {
struct vcache *uvc;
if (afs_mariner)
afs_AddMarinerName(aname, tvc);
+
+#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
+ if (!(flags & AFS_LOOKUP_NOEVAL))
+ /* Here we don't enter the name into the DNLC because we want the
+ evaluated mount dir to be there (the vcache for the mounted volume)
+ rather than the vc of the mount point itself. we can still find the
+ mount point's vc in the vcache by its fid. */
+#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
if (!hit) {
osi_dnlc_enter (adp, aname, tvc, &versionNo);
}