/* avc must be held. Returns bit map of mode bits. Ignores file mode bits */ afs_int32 afs_GetAccessBits(register struct vcache *avc, register afs_int32 arights, register struct vrequest *areq) { AFS_STATCNT(afs_GetAccessBits); /* see if anyuser has the required access bits */ if ((arights & avc->f.anyAccess) == arights) { return arights; } /* look in per-pag cache */ if (avc->Access) { /* not beautiful, but Sun's cc will tolerate it */ struct axscache *ac; ac = afs_FindAxs(avc->Access, areq->uid); if (ac) { return (arights & ac->axess); } } if (!(avc->f.states & CForeign)) { /* If there aren't any bits cached for this user (but the vnode * _is_ cached, obviously), make sure this user has valid tokens * before bothering with the RPC. */ struct unixuser *tu; tu = afs_FindUser(areq->uid, avc->f.fid.Cell, READ_LOCK); if (!tu) { return (arights & avc->f.anyAccess); } if ((tu->vid == UNDEFVID) || !(tu->states & UHasTokens) || (tu->states & UTokensBad)) { afs_PutUser(tu, READ_LOCK); return (arights & avc->f.anyAccess); } else { afs_PutUser(tu, READ_LOCK); } } if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) { /* If we get this far, we have to ask the network. But we can't, so * they're out of luck... */ return 0; } else { /* Ok, user has valid tokens, go ask the server. */ struct AFSFetchStatus OutStatus; afs_int32 code; code = afs_FetchStatus(avc, &avc->f.fid, areq, &OutStatus); return (code ? 0 : OutStatus.CallerAccess & arights); } }
/** * forceConnectFS is set whenever we must recompute the connection. UTokensBad * is true only if we know that the tokens are bad. We thus clear this flag * when we get a new set of tokens.. * Having force... true and UTokensBad true simultaneously means that the tokens * went bad and we're supposed to create a new, unauthenticated, connection. * * @param aserver Server to connect to. * @param aport Connection port. * @param acell The cell where all of this happens. * @param areq The request. * @param aforce Force connection? * @param locktype Type of lock to be used. * * @return The established connection. */ struct afs_conn * afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell, struct vrequest *areq, int aforce, afs_int32 locktype, struct rx_connection **rxconn) { struct unixuser *tu; struct afs_conn *tc = NULL; struct srvAddr *sa = NULL; *rxconn = NULL; AFS_STATCNT(afs_ConnByHost); if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) { afs_warnuser("afs_ConnByHost: disconnected\n"); return NULL; } /* 1. look for an existing connection 2. create a connection at an address believed to be up (if aforce is true, create a connection at the first address) */ tu = afs_GetUser(areq->uid, acell, SHARED_LOCK); for (sa = aserver->addr; sa; sa = sa->next_sa) { tc = afs_ConnBySA(sa, aport, acell, tu, aforce, 0 /*don't create one */ , locktype, rxconn); if (tc) break; } if (!tc) { for (sa = aserver->addr; sa; sa = sa->next_sa) { tc = afs_ConnBySA(sa, aport, acell, tu, aforce, 1 /*create one */ , locktype, rxconn); if (tc) break; } } afs_PutUser(tu, SHARED_LOCK); return tc; } /*afs_ConnByHost */
int afspag_PSetTokens(char *ain, afs_int32 ainSize, struct AFS_UCRED **acred) { afs_int32 i; register struct unixuser *tu; struct afspag_cell *tcell; struct ClearToken clear; char *stp; int stLen; afs_int32 flag, set_parent_pag = 0; afs_int32 pag, uid; AFS_STATCNT(PSetTokens); if (!afs_resourceinit_flag) { return EIO; } memcpy((char *)&i, ain, sizeof(afs_int32)); ain += sizeof(afs_int32); stp = ain; /* remember where the ticket is */ if (i < 0 || i > MAXKTCTICKETLEN) return EINVAL; /* malloc may fail */ stLen = i; ain += i; /* skip over ticket */ memcpy((char *)&i, ain, sizeof(afs_int32)); ain += sizeof(afs_int32); if (i != sizeof(struct ClearToken)) { return EINVAL; } memcpy((char *)&clear, ain, sizeof(struct ClearToken)); if (clear.AuthHandle == -1) clear.AuthHandle = 999; /* more rxvab compat stuff */ ain += sizeof(struct ClearToken); if (ainSize != 2 * sizeof(afs_int32) + stLen + sizeof(struct ClearToken)) { /* still stuff left? we've got primary flag and cell name. Set these */ memcpy((char *)&flag, ain, sizeof(afs_int32)); /* primary id flag */ ain += sizeof(afs_int32); /* skip id field */ /* rest is cell name, look it up */ /* some versions of gcc appear to need != 0 in order to get this right */ if ((flag & 0x8000) != 0) { /* XXX Use Constant XXX */ flag &= ~0x8000; set_parent_pag = 1; } tcell = afspag_GetCell(ain); } else { /* default to primary cell, primary id */ flag = 1; /* primary id */ tcell = afspag_GetPrimaryCell(); } if (!tcell) return ESRCH; if (set_parent_pag) { #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV) #if defined(AFS_DARWIN_ENV) struct proc *p = current_proc(); /* XXX */ #else struct proc *p = curproc; /* XXX */ #endif #ifndef AFS_DARWIN80_ENV uprintf("Process %d (%s) tried to change pags in PSetTokens\n", p->p_pid, p->p_comm); #endif setpag(p, acred, -1, &pag, 1); #else #ifdef AFS_OSF_ENV setpag(u.u_procp, acred, -1, &pag, 1); /* XXX u.u_procp is a no-op XXX */ #else setpag(acred, -1, &pag, 1); #endif #endif } pag = PagInCred(*acred); uid = (pag == NOPAG) ? (*acred)->cr_uid : pag; /* now we just set the tokens */ tu = afs_GetUser(uid, tcell->cellnum, WRITE_LOCK); if (!tu->cellinfo) tu->cellinfo = (void *)tcell; tu->vid = clear.ViceId; if (tu->stp != NULL) { afs_osi_Free(tu->stp, tu->stLen); } tu->stp = (char *)afs_osi_Alloc(stLen); tu->stLen = stLen; memcpy(tu->stp, stp, stLen); tu->ct = clear; #ifndef AFS_NOSTATS afs_stats_cmfullperf.authent.TicketUpdates++; afs_ComputePAGStats(); #endif /* AFS_NOSTATS */ tu->states |= UHasTokens; tu->states &= ~UTokensBad; afs_SetPrimary(tu, flag); tu->tokenTime = osi_Time(); afs_PutUser(tu, WRITE_LOCK); return 0; }
/** * Try setting up a connection to the server containing the specified fid. * Gets the volume, checks if it's up and does the connection by server address. * * @param afid * @param areq Request filled in by the caller. * @param locktype Type of lock that will be used. * * @return The conn struct, or NULL. */ struct afs_conn * afs_Conn(struct VenusFid *afid, struct vrequest *areq, afs_int32 locktype, struct rx_connection **rxconn) { u_short fsport = AFS_FSPORT; struct volume *tv; struct afs_conn *tconn = NULL; struct srvAddr *lowp = NULL; struct unixuser *tu; int notbusy; int i; struct srvAddr *sa1p; *rxconn = NULL; AFS_STATCNT(afs_Conn); /* Get fid's volume. */ tv = afs_GetVolume(afid, areq, READ_LOCK); if (!tv) { if (areq) { afs_FinalizeReq(areq); areq->volumeError = 1; } return NULL; } if (tv->serverHost[0] && tv->serverHost[0]->cell) { fsport = tv->serverHost[0]->cell->fsport; } else { VNOSERVERS++; } /* First is always lowest rank, if it's up */ if ((tv->status[0] == not_busy) && tv->serverHost[0] && !(tv->serverHost[0]->addr->sa_flags & SRVR_ISDOWN) && !(((areq->idleError > 0) || (areq->tokenError > 0)) && (areq->skipserver[0] == 1))) lowp = tv->serverHost[0]->addr; /* Otherwise we look at all of them. There are seven levels of * not_busy. This means we will check a volume seven times before it * is marked offline. Ideally, we only need two levels, but this * serves a second purpose of waiting some number of seconds before * the client decides the volume is offline (ie: a clone could finish * in this time). */ for (notbusy = not_busy; (!lowp && (notbusy <= end_not_busy)); notbusy++) { for (i = 0; i < AFS_MAXHOSTS && tv->serverHost[i]; i++) { if (((areq->tokenError > 0)||(areq->idleError > 0)) && (areq->skipserver[i] == 1)) continue; if (tv->status[i] != notbusy) { if (tv->status[i] == rd_busy || tv->status[i] == rdwr_busy) { if (!areq->busyCount) areq->busyCount++; } else if (tv->status[i] == offline) { if (!areq->volumeError) areq->volumeError = VOLMISSING; } continue; } for (sa1p = tv->serverHost[i]->addr; sa1p; sa1p = sa1p->next_sa) { if (sa1p->sa_flags & SRVR_ISDOWN) continue; if (!lowp || (lowp->sa_iprank > sa1p->sa_iprank)) lowp = sa1p; } } } afs_PutVolume(tv, READ_LOCK); if (lowp) { tu = afs_GetUser(areq->uid, afid->Cell, SHARED_LOCK); tconn = afs_ConnBySA(lowp, fsport, afid->Cell, tu, 0 /*!force */ , 1 /*create */ , locktype, rxconn); afs_PutUser(tu, SHARED_LOCK); } return tconn; } /*afs_Conn */
/*------------------------------------------------------------------------ * EXPORTED afs_Analyze * * Description: * Analyze the outcome of an RPC operation, taking whatever support * actions are necessary. * * Arguments: * aconn : Ptr to the relevant connection on which the call was made. * acode : The return code experienced by the RPC. * afid : The FID of the file involved in the action. This argument * may be null if none was involved. * areq : The request record associated with this operation. * op : which RPC we are analyzing. * cellp : pointer to a cell struct. Must provide either fid or cell. * * Returns: * Non-zero value if the related RPC operation should be retried, * zero otherwise. * * Environment: * This routine is typically called in a do-while loop, causing the * embedded RPC operation to be called repeatedly if appropriate * until whatever error condition (if any) is intolerable. * * Side Effects: * As advertised. * * NOTE: * The retry return value is used by afs_StoreAllSegments to determine * if this is a temporary or permanent error. *------------------------------------------------------------------------*/ int afs_Analyze(register struct afs_conn *aconn, afs_int32 acode, struct VenusFid *afid, register struct vrequest *areq, int op, afs_int32 locktype, struct cell *cellp) { afs_int32 i; struct srvAddr *sa; struct server *tsp; struct volume *tvp; afs_int32 shouldRetry = 0; afs_int32 serversleft = 1; struct afs_stats_RPCErrors *aerrP; afs_int32 markeddown; if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) { /* On reconnection, act as connected. XXX: for now.... */ /* SXW - This may get very tired after a while. We should try and * intercept all RPCs before they get here ... */ /*printf("afs_Analyze: disconnected\n");*/ afs_FinalizeReq(areq); if (aconn) { /* SXW - I suspect that this will _never_ happen - we shouldn't * get a connection because we're disconnected !!!*/ afs_PutConn(aconn, locktype); } return 0; } AFS_STATCNT(afs_Analyze); afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op, ICL_TYPE_POINTER, aconn, ICL_TYPE_INT32, acode, ICL_TYPE_LONG, areq->uid); aerrP = (struct afs_stats_RPCErrors *)0; if ((op >= 0) && (op < AFS_STATS_NUM_FS_RPC_OPS)) aerrP = &(afs_stats_cmfullperf.rpc.fsRPCErrors[op]); afs_FinalizeReq(areq); if (!aconn && areq->busyCount) { /* one RPC or more got VBUSY/VRESTARTING */ tvp = afs_FindVolume(afid, READ_LOCK); if (tvp) { afs_warnuser("afs: Waiting for busy volume %u (%s) in cell %s\n", (afid ? afid->Fid.Volume : 0), (tvp->name ? tvp->name : ""), ((tvp->serverHost[0] && tvp->serverHost[0]->cell) ? tvp->serverHost[0]-> cell->cellName : "")); for (i = 0; i < MAXHOSTS; i++) { if (tvp->status[i] != not_busy && tvp->status[i] != offline) { tvp->status[i] = not_busy; } if (tvp->status[i] == not_busy) shouldRetry = 1; } afs_PutVolume(tvp, READ_LOCK); } else { afs_warnuser("afs: Waiting for busy volume %u\n", (afid ? afid->Fid.Volume : 0)); } if (areq->busyCount > 100) { if (aerrP) (aerrP->err_Volume)++; areq->volumeError = VOLBUSY; shouldRetry = 0; } else { VSleep(afs_BusyWaitPeriod); /* poll periodically */ } if (shouldRetry != 0) areq->busyCount++; return shouldRetry; /* should retry */ } if (!aconn || !aconn->srvr) { if (!areq->volumeError) { if (aerrP) (aerrP->err_Network)++; if (hm_retry_int && !(areq->flags & O_NONBLOCK) && /* "hard" mount */ ((afid && afs_IsPrimaryCellNum(afid->Cell)) || (cellp && afs_IsPrimaryCell(cellp)))) { if (!afid) { afs_warnuser ("afs: hard-mount waiting for a vlserver to return to service\n"); VSleep(hm_retry_int); afs_CheckServers(1, cellp); shouldRetry = 1; } else { tvp = afs_FindVolume(afid, READ_LOCK); if (!tvp || (tvp->states & VRO)) { shouldRetry = hm_retry_RO; } else { shouldRetry = hm_retry_RW; } if (tvp) afs_PutVolume(tvp, READ_LOCK); if (shouldRetry) { afs_warnuser ("afs: hard-mount waiting for volume %u\n", afid->Fid.Volume); VSleep(hm_retry_int); afs_CheckServers(1, cellp); } } } /* if (hm_retry_int ... */ else { areq->networkError = 1; } } return shouldRetry; } /* Find server associated with this connection. */ sa = aconn->srvr; tsp = sa->server; /* Before we do anything with acode, make sure we translate it back to * a system error */ if ((acode & ~0xff) == ERROR_TABLE_BASE_uae) acode = et_to_sys_error(acode); if (acode == 0) { /* If we previously took an error, mark this volume not busy */ if (areq->volumeError) { tvp = afs_FindVolume(afid, READ_LOCK); if (tvp) { for (i = 0; i < MAXHOSTS; i++) { if (tvp->serverHost[i] == tsp) { tvp->status[i] = not_busy; } } afs_PutVolume(tvp, READ_LOCK); } } afs_PutConn(aconn, locktype); return 0; } /* If network troubles, mark server as having bogued out again. */ /* VRESTARTING is < 0 because of backward compatibility issues * with 3.4 file servers and older cache managers */ #ifdef AFS_64BIT_CLIENT if (acode == -455) acode = 455; #endif /* AFS_64BIT_CLIENT */ if ((acode < 0) && (acode != VRESTARTING)) { if (acode == RX_CALL_TIMEOUT) { serversleft = afs_BlackListOnce(areq, afid, tsp); areq->idleError++; if (serversleft) { shouldRetry = 1; } else { shouldRetry = 0; } /* By doing this, we avoid ever marking a server down * in an idle timeout case. That's because the server is * still responding and may only be letting a single vnode * time out. We otherwise risk having the server continually * be marked down, then up, then down again... */ goto out; } markeddown = afs_ServerDown(sa); ForceNewConnections(sa); /**multi homed clients lock:afs_xsrvAddr? */ if (aerrP) (aerrP->err_Server)++; #if 0 /* retry *once* when the server is timed out in case of NAT */ if (markeddown && acode == RX_CALL_DEAD) { aconn->forceConnectFS = 1; shouldRetry = 1; } #endif } if (acode == VBUSY || acode == VRESTARTING) { if (acode == VBUSY) { areq->busyCount++; if (aerrP) (aerrP->err_VolumeBusies)++; } else areq->busyCount = 1; tvp = afs_FindVolume(afid, READ_LOCK); if (tvp) { for (i = 0; i < MAXHOSTS; i++) { if (tvp->serverHost[i] == tsp) { tvp->status[i] = rdwr_busy; /* can't tell which yet */ /* to tell which, have to look at the op code. */ } } afs_PutVolume(tvp, READ_LOCK); } else { afs_warnuser("afs: Waiting for busy volume %u in cell %s\n", (afid ? afid->Fid.Volume : 0), tsp->cell->cellName); VSleep(afs_BusyWaitPeriod); /* poll periodically */ } shouldRetry = 1; acode = 0; } else if (acode == VICETOKENDEAD || (acode & ~0xff) == ERROR_TABLE_BASE_RXK) { /* any rxkad error is treated as token expiration */ struct unixuser *tu; /* * I'm calling these errors protection errors, since they involve * faulty authentication. */ if (aerrP) (aerrP->err_Protection)++; tu = afs_FindUser(areq->uid, tsp->cell->cellNum, READ_LOCK); if (tu) { if (acode == VICETOKENDEAD) { aconn->forceConnectFS = 1; } else if (acode == RXKADEXPIRED) { aconn->forceConnectFS = 0; /* don't check until new tokens set */ aconn->user->states |= UTokensBad; afs_warnuser ("afs: Tokens for user of AFS id %d for cell %s have expired\n", tu->vid, aconn->srvr->server->cell->cellName); } else { serversleft = afs_BlackListOnce(areq, afid, tsp); areq->tokenError++; if (serversleft) { afs_warnuser ("afs: Tokens for user of AFS id %d for cell %s: rxkad error=%d\n", tu->vid, aconn->srvr->server->cell->cellName, acode); shouldRetry = 1; } else { areq->tokenError = 0; aconn->forceConnectFS = 0; /* don't check until new tokens set */ aconn->user->states |= UTokensBad; afs_warnuser ("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d)\n", tu->vid, aconn->srvr->server->cell->cellName, acode); } } afs_PutUser(tu, READ_LOCK); } else { /* The else case shouldn't be possible and should probably be replaced by a panic? */ if (acode == VICETOKENDEAD) { aconn->forceConnectFS = 1; } else if (acode == RXKADEXPIRED) { aconn->forceConnectFS = 0; /* don't check until new tokens set */ aconn->user->states |= UTokensBad; afs_warnuser ("afs: Tokens for user %d for cell %s have expired\n", areq->uid, aconn->srvr->server->cell->cellName); } else { aconn->forceConnectFS = 0; /* don't check until new tokens set */ aconn->user->states |= UTokensBad; afs_warnuser ("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d)\n", areq->uid, aconn->srvr->server->cell->cellName, acode); } } shouldRetry = 1; /* Try again (as root). */ } /* Check for access violation. */ else if (acode == EACCES) { /* should mark access error in non-existent per-user global structure */ if (aerrP) (aerrP->err_Protection)++; areq->accessError = 1; if (op == AFS_STATS_FS_RPCIDX_STOREDATA) areq->permWriteError = 1; shouldRetry = 0; } /* check for ubik errors; treat them like crashed servers */ else if (acode >= ERROR_TABLE_BASE_U && acode < ERROR_TABLE_BASE_U + 255) { afs_ServerDown(sa); if (aerrP) (aerrP->err_Server)++; shouldRetry = 1; /* retryable (maybe one is working) */ VSleep(1); /* just in case */ } /* Check for bad volume data base / missing volume. */ else if (acode == VSALVAGE || acode == VOFFLINE || acode == VNOVOL || acode == VNOSERVICE || acode == VMOVED) { struct cell *tcell; int same; shouldRetry = 1; areq->volumeError = VOLMISSING; if (aerrP) (aerrP->err_Volume)++; if (afid && (tcell = afs_GetCell(afid->Cell, 0))) { same = VLDB_Same(afid, areq); tvp = afs_FindVolume(afid, READ_LOCK); if (tvp) { for (i = 0; i < MAXHOSTS && tvp->serverHost[i]; i++) { if (tvp->serverHost[i] == tsp) { if (tvp->status[i] == end_not_busy) tvp->status[i] = offline; else tvp->status[i]++; } else if (!same) { tvp->status[i] = not_busy; /* reset the others */ } } afs_PutVolume(tvp, READ_LOCK); } } } else if (acode >= ERROR_TABLE_BASE_VL && acode <= ERROR_TABLE_BASE_VL + 255) { /* vlserver errors */ shouldRetry = 0; areq->volumeError = VOLMISSING; } else if (acode >= 0) { if (aerrP) (aerrP->err_Other)++; if (op == AFS_STATS_FS_RPCIDX_STOREDATA) areq->permWriteError = 1; shouldRetry = 0; /* Other random Vice error. */ } else if (acode == RX_MSGSIZE) { /* same meaning as EMSGSIZE... */ VSleep(1); /* Just a hack for desperate times. */ if (aerrP) (aerrP->err_Other)++; shouldRetry = 1; /* packet was too big, please retry call */ } if (acode < 0 && acode != RX_MSGSIZE && acode != VRESTARTING) { /* If we get here, code < 0 and we have network/Server troubles. * areq->networkError is not set here, since we always * retry in case there is another server. However, if we find * no connection (aconn == 0) we set the networkError flag. */ afs_MarkServerUpOrDown(sa, SRVR_ISDOWN); if (aerrP) (aerrP->err_Server)++; VSleep(1); /* Just a hack for desperate times. */ shouldRetry = 1; } out: /* now unlock the connection and return */ afs_PutConn(aconn, locktype); return (shouldRetry); } /*afs_Analyze */
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); } }