afs_open(struct vcache **avcp, afs_int32 aflags, afs_ucred_t *acred) #endif { afs_int32 code; struct vrequest treq; struct vcache *tvc; int writing; struct afs_fakestat_state fakestate; AFS_STATCNT(afs_open); if ((code = afs_InitReq(&treq, acred))) return code; #ifdef AFS_SGI64_ENV /* avcpp can be, but is not necesarily, bhp's vnode. */ tvc = VTOAFS(BHV_TO_VNODE(bhv)); #else tvc = *avcp; #endif afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, aflags); afs_InitFakeStat(&fakestate); AFS_DISCON_LOCK(); code = afs_EvalFakeStat(&tvc, &fakestate, &treq); if (code) goto done; code = afs_VerifyVCache(tvc, &treq); if (code) goto done; ObtainReadLock(&tvc->lock); if (AFS_IS_DISCONNECTED && (afs_DCacheMissingChunks(tvc) != 0)) { ReleaseReadLock(&tvc->lock); /* printf("Network is down in afs_open: missing chunks\n"); */ code = ENETDOWN; goto done; } ReleaseReadLock(&tvc->lock); if (aflags & (FWRITE | FTRUNC)) writing = 1; else writing = 0; if (vType(tvc) == VDIR) { /* directory */ if (writing) { code = EISDIR; goto done; } else { if (!afs_AccessOK (tvc, ((tvc->f.states & CForeign) ? PRSFS_READ : PRSFS_LOOKUP), &treq, CHECK_MODE_BITS)) { code = EACCES; /* printf("afs_Open: no access for dir\n"); */ goto done; } } } else { #ifdef AFS_SUN5_ENV if (AFS_NFSXLATORREQ(acred) && (aflags & FREAD)) { if (!afs_AccessOK (tvc, PRSFS_READ, &treq, CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) { code = EACCES; goto done; } } #endif #ifdef AFS_AIX41_ENV if (aflags & FRSHARE) { /* * Hack for AIX 4.1: * Apparently it is possible for a file to get mapped without * either VNOP_MAP or VNOP_RDWR being called, if (1) it is a * sharable library, and (2) it has already been loaded. We must * ensure that the credp is up to date. We detect the situation * by checking for O_RSHARE at open time. */ /* * We keep the caller's credentials since an async daemon will * handle the request at some point. We assume that the same * credentials will be used. */ ObtainWriteLock(&tvc->lock, 140); if (!tvc->credp || (tvc->credp != acred)) { crhold(acred); if (tvc->credp) { struct ucred *crp = tvc->credp; tvc->credp = NULL; crfree(crp); } tvc->credp = acred; } ReleaseWriteLock(&tvc->lock); } #endif /* normal file or symlink */ osi_FlushText(tvc); /* only needed to flush text if text locked last time */ #ifdef AFS_BOZONLOCK_ENV afs_BozonLock(&tvc->pvnLock, tvc); #endif osi_FlushPages(tvc, acred); #ifdef AFS_BOZONLOCK_ENV afs_BozonUnlock(&tvc->pvnLock, tvc); #endif } /* set date on file if open in O_TRUNC mode */ if (aflags & FTRUNC) { /* this fixes touch */ ObtainWriteLock(&tvc->lock, 123); tvc->f.m.Date = osi_Time(); tvc->f.states |= CDirty; ReleaseWriteLock(&tvc->lock); } ObtainReadLock(&tvc->lock); if (writing) tvc->execsOrWriters++; tvc->opens++; #if defined(AFS_SGI_ENV) || defined (AFS_LINUX26_ENV) if (writing && tvc->cred == NULL) { crhold(acred); tvc->cred = acred; } #endif ReleaseReadLock(&tvc->lock); if ((afs_preCache != 0) && (writing == 0) && (vType(tvc) != VDIR) && (!afs_BBusy())) { struct dcache *tdc; afs_size_t offset, len; tdc = afs_GetDCache(tvc, 0, &treq, &offset, &len, 1); ObtainSharedLock(&tdc->mflock, 865); if (!(tdc->mflags & DFFetchReq)) { struct brequest *bp; /* start the daemon (may already be running, however) */ UpgradeSToWLock(&tdc->mflock, 666); tdc->mflags |= DFFetchReq; /* guaranteed to be cleared by BKG or GetDCache */ /* last parm (1) tells bkg daemon to do an afs_PutDCache when it is done, since we don't want to wait for it to finish before doing so ourselves. */ bp = afs_BQueue(BOP_FETCH, tvc, B_DONTWAIT, 0, acred, (afs_size_t) 0, (afs_size_t) 1, tdc, (void *)0, (void *)0); if (!bp) { tdc->mflags &= ~DFFetchReq; } ReleaseWriteLock(&tdc->mflock); } else { ReleaseSharedLock(&tdc->mflock); } } done: afs_PutFakeStat(&fakestate); AFS_DISCON_UNLOCK(); code = afs_CheckCode(code, &treq, 4); /* avoid AIX -O bug */ afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, 999999); return code; }
int afs_getattr(OSI_VC_DECL(avc), struct vattr *attrs, afs_ucred_t *acred) #endif { afs_int32 code; struct vrequest *treq = NULL; struct unixuser *au; int inited = 0; OSI_VC_CONVERT(avc); AFS_STATCNT(afs_getattr); afs_Trace2(afs_iclSetp, CM_TRACE_GETATTR, ICL_TYPE_POINTER, avc, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->f.m.Length)); if (afs_fakestat_enable && avc->mvstat == AFS_MVSTAT_MTPT) { struct afs_fakestat_state fakestat; struct vrequest *ureq = NULL; code = afs_CreateReq(&ureq, acred); if (code) { return code; } afs_InitFakeStat(&fakestat); code = afs_TryEvalFakeStat(&avc, &fakestat, ureq); if (code) { afs_PutFakeStat(&fakestat); afs_DestroyReq(ureq); return code; } code = afs_CopyOutAttrs(avc, attrs); afs_PutFakeStat(&fakestat); afs_DestroyReq(ureq); return code; } #if defined(AFS_SUN5_ENV) if (flags & ATTR_HINT) { code = afs_CopyOutAttrs(avc, attrs); return code; } #endif #if defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV) if (avc->f.states & CUBCinit) { code = afs_CopyOutAttrs(avc, attrs); return code; } #endif AFS_DISCON_LOCK(); if (afs_shuttingdown != AFS_RUNNING) { AFS_DISCON_UNLOCK(); return EIO; } if (!(avc->f.states & CStatd)) { if (!(code = afs_CreateReq(&treq, acred))) { code = afs_VerifyVCache2(avc, treq); inited = 1; } } else code = 0; #if defined(AFS_SUN5_ENV) if (code == 0) osi_FlushPages(avc, acred); #endif if (code == 0) { osi_FlushText(avc); /* only needed to flush text if text locked last time */ code = afs_CopyOutAttrs(avc, attrs); if (afs_nfsexporter) { if (!inited) { if ((code = afs_CreateReq(&treq, acred))) { return code; } inited = 1; } if (AFS_NFSXLATORREQ(acred)) { if ((vType(avc) != VDIR) && !afs_AccessOK(avc, PRSFS_READ, treq, CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) { afs_DestroyReq(treq); return EACCES; } } if ((au = afs_FindUser(treq->uid, -1, READ_LOCK))) { struct afs_exporter *exporter = au->exporter; if (exporter && !(afs_nfsexporter->exp_states & EXP_UNIXMODE)) { unsigned int ubits; /* * If the remote user wishes to enforce default Unix mode semantics, * like in the nfs exporter case, we OR in the user bits * into the group and other bits. We need to do this * because there is no RFS_ACCESS call and thus nfs * clients implement nfs_access by interpreting the * mode bits in the traditional way, which of course * loses with afs. */ ubits = (attrs->va_mode & 0700) >> 6; attrs->va_mode = attrs->va_mode | ubits | (ubits << 3); /* If it's the root of AFS, replace the inode number with the * inode number of the mounted on directory; otherwise this * confuses getwd()... */ #ifdef AFS_LINUX22_ENV if (avc == afs_globalVp) { struct inode *ip = AFSTOV(avc)->i_sb->s_root->d_inode; attrs->va_nodeid = ip->i_ino; /* VTOI()? */ } #else if ( #if defined(AFS_DARWIN_ENV) vnode_isvroot(AFSTOV(avc)) #elif defined(AFS_NBSD50_ENV) AFSTOV(avc)->v_vflag & VV_ROOT #else AFSTOV(avc)->v_flag & VROOT #endif ) { struct vnode *vp = AFSTOV(avc); #ifdef AFS_DARWIN80_ENV /* XXX vp = vnode_mount(vp)->mnt_vnodecovered; */ vp = 0; #else vp = vp->v_vfsp->vfs_vnodecovered; if (vp) { /* Ignore weird failures */ #ifdef AFS_SGI62_ENV attrs->va_nodeid = VnodeToIno(vp); #else struct inode *ip; ip = (struct inode *)VTOI(vp); if (ip) /* Ignore weird failures */ attrs->va_nodeid = ip->i_number; #endif } #endif } #endif /* AFS_LINUX22_ENV */ } afs_PutUser(au, READ_LOCK); } }