* directory or online at http://www.openafs.org/dl/license10.html
*/
+#include <afsconfig.h>
#include <afs/param.h>
+#include <roken.h>
+
#include <afs/stds.h>
#include <windows.h>
cm_lock_data_t **ldpp)
{
long rights;
- long code;
+ long code = 0;
osi_assertx(ldpp != NULL, "null cm_lock_data_t");
*ldpp = NULL;
/* Always allow delete; the RPC will tell us if it's OK */
- if (desiredAccess == DELETE)
- return 0;
-
rights = 0;
+ if (desiredAccess == DELETE)
+ goto done_2;
+
if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
rights |= (scp->fileType == CM_SCACHETYPE_DIRECTORY ? PRSFS_LOOKUP : PRSFS_READ);
if (desiredAccess & AFS_ACCESS_WRITE)
rights |= PRSFS_WRITE;
+ if (desiredAccess & DELETE)
+ rights |= PRSFS_DELETE;
+
lock_ObtainWrite(&scp->rw);
code = cm_SyncOp(scp, NULL, userp, reqp, rights,
_done:
lock_ReleaseWrite(&scp->rw);
+ done_2:
osi_Log3(afsd_logp,"cm_CheckNTOpen scp 0x%p ldp 0x%p code 0x%x", scp, *ldpp, code);
return code;
}
code = ENOENT;
- code = cm_BeginDirOp(scp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ code = cm_BeginDirOp(scp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
if (code == 0) {
#ifdef USE_BPLUS
tp = bufferp->datap + entryInBuffer;
dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
+ /*
+ * here are some consistency checks
+ */
+ if (dep->flag != CM_DIR_FFIRST ||
+ strlen(dep->name) > 256) {
+ code = CM_ERROR_INVAL;
+ osi_Log2(afsd_logp,
+ "cm_ApplyDir invalid directory entry for scp %p bufp %p",
+ scp, bufferp);
+ osi_Log4(afsd_logp,"... cell %u vol %u vnode %u uniq %u",
+ scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
+ bufferp->dataVersion = CM_BUF_VERSION_BAD;
+ break;
+ }
+
/* while we're here, compute the next entry's location, too,
* since we'll need it when writing out the cookie into the
* dir listing stream.
long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
{
long code;
- cm_buf_t *bufp = NULL;
- osi_hyper_t thyper;
- int tlen;
if (scp->mountPointStringp[0])
return 0;
} else
#endif /* AFS_FREELANCE_CLIENT */
{
- /* otherwise, we have to read it in */
- lock_ReleaseWrite(&scp->rw);
+ char temp[MOUNTPOINTLEN];
+ osi_hyper_t thyper;
+ /* otherwise, we have to read it in */
thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(scp, &thyper, reqp, &bufp);
-
- lock_ObtainWrite(&scp->rw);
+ code = cm_GetData(scp, &thyper, temp, MOUNTPOINTLEN, userp, reqp);
if (code)
return code;
- while (1) {
- code = cm_SyncOp(scp, bufp, userp, reqp, 0,
- CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
- if (code)
- goto done;
-
- cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
-
- if (cm_HaveBuffer(scp, bufp, 0))
- break;
-
- /* otherwise load buffer */
- code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
- if (code)
- goto done;
- }
- /* locked, has callback, has valid data in buffer */
- if ((tlen = scp->length.LowPart) > MOUNTPOINTLEN - 1)
- return CM_ERROR_TOOBIG;
- if (tlen <= 0) {
- code = CM_ERROR_INVAL;
- goto done;
- }
-
- /* someone else did the work while we were out */
- if (scp->mountPointStringp[0]) {
- code = 0;
- goto done;
- }
-
- /* otherwise, copy out the link */
- memcpy(scp->mountPointStringp, bufp->datap, tlen);
-
- /* now make it null-terminated. Note that the original contents of a
- * link that is a mount point is "#volname." where "." is there just to
- * be turned into a null. That is, we can trash the last char of the
- * link without damaging the vol name. This is a stupid convention,
- * but that's the protocol.
+ /*
+ * scp->length is the actual length of the mount point string.
+ * It is current because cm_GetData merged the most up to date
+ * status info into scp and has not dropped the rwlock since.
*/
- scp->mountPointStringp[tlen-1] = 0;
- code = 0;
+ if (scp->length.LowPart > MOUNTPOINTLEN - 1)
+ return CM_ERROR_TOOBIG;
+ if (scp->length.LowPart == 0)
+ return CM_ERROR_INVAL;
- done:
- if (bufp)
- buf_Release(bufp);
+ /* convert the terminating dot to a NUL */
+ temp[thyper.LowPart - 1] = 0;
+ memcpy(scp->mountPointStringp, temp, thyper.LowPart);
}
+
return code;
}
int usedBplus = 0;
#endif
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
if (code == 0) {
#ifdef USE_BPLUS
code = cm_BPlusDirLookup(&dirop, nnamep, &rock.fid);
if (cnamep[0] == '.') {
if (cm_GetCell_Gen(&fnamep[1], &fullname[1], CM_FLAG_CREATE)) {
found = 1;
- code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
+ code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell", 1, &rock.fid);
if ( cm_FsStrCmpI(&fnamep[1], &fullname[1])) {
/*
* Do not permit symlinks that are one of:
} else {
if (cm_GetCell_Gen(fnamep, fullname, CM_FLAG_CREATE)) {
found = 1;
- code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
+ code = cm_FreelanceAddMount(fullname, fullname, "root.cell", 0, &rock.fid);
if ( cm_FsStrCmpI(fnamep, fullname)) {
/*
* Do not permit symlinks that are one of:
/* tscp is now held */
lock_ObtainWrite(&tscp->rw);
- code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
- CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
- if (code) {
- lock_ReleaseWrite(&tscp->rw);
- cm_ReleaseSCache(tscp);
- goto done;
+
+ /*
+ * Do not get status if we do not already have a callback.
+ * The process of reading the mount point string will obtain status information
+ * in a single RPC. No reason to add a second round trip.
+ *
+ * If we do have a callback, use cm_SyncOp to get status in case the
+ * current cm_user_t is not the same as the one that obtained the
+ * mount point string contents.
+ */
+ if (cm_HaveCallback(tscp)) {
+ code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
+ CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code) {
+ lock_ReleaseWrite(&tscp->rw);
+ cm_ReleaseSCache(tscp);
+ goto done;
+ }
+ cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
}
- cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
/* tscp is now locked */
if (!(flags & CM_FLAG_NOMOUNTCHASE)
if (fnamep == NULL) {
code = -1;
#ifdef USE_BPLUS
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
if (code == 0) {
code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
if (code == 0)
#endif
code = cm_Lookup(dscp, cnamep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+ if (code)
+ goto done;
+
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO) {
+ code = CM_ERROR_READONLY;
+ goto done;
+ }
/* make sure we don't screw up the dir status during the merge */
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &dirop);
lock_ObtainWrite(&dscp->rw);
sflags = CM_SCACHESYNC_STOREDATA;
*/
long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
{
- long code;
- cm_buf_t *bufp;
- long temp;
- osi_hyper_t thyper;
+ long code = 0;
lock_AssertWrite(&linkScp->rw);
if (!linkScp->mountPointStringp[0]) {
} else
#endif /* AFS_FREELANCE_CLIENT */
{
- /* read the link data from the file server*/
- lock_ReleaseWrite(&linkScp->rw);
+ char temp[MOUNTPOINTLEN];
+ osi_hyper_t thyper;
+
+ /* read the link data from the file server */
thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(linkScp, &thyper, reqp, &bufp);
- lock_ObtainWrite(&linkScp->rw);
- if (code)
+ code = cm_GetData(linkScp, &thyper, temp, MOUNTPOINTLEN, userp, reqp);
+ if (code)
return code;
- while (1) {
- code = cm_SyncOp(linkScp, bufp, userp, reqp, 0,
- CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
- if (code) {
- buf_Release(bufp);
- return code;
- }
- cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
-
- if (cm_HaveBuffer(linkScp, bufp, 0))
- break;
- code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
- if (code) {
- buf_Release(bufp);
- return code;
- }
- } /* while loop to get the data */
-
- /* now if we still have no link read in,
- * copy the data from the buffer */
- if ((temp = linkScp->length.LowPart) >= MOUNTPOINTLEN) {
- buf_Release(bufp);
+ /*
+ * linkScp->length is the actual length of the symlink target string.
+ * It is current because cm_GetData merged the most up to date
+ * status info into scp and has not dropped the rwlock since.
+ */
+ if (linkScp->length.LowPart > MOUNTPOINTLEN - 1)
return CM_ERROR_TOOBIG;
- }
+ if (linkScp->length.LowPart == 0)
+ return CM_ERROR_INVAL;
- /* otherwise, it fits; make sure it is still null (could have
- * lost race with someone else referencing this link above),
- * and if so, copy in the data.
- */
- if (!linkScp->mountPointStringp[0]) {
- strncpy(linkScp->mountPointStringp, bufp->datap, temp);
- linkScp->mountPointStringp[temp] = 0; /* null terminate */
- }
- buf_Release(bufp);
+ /* convert the terminating dot to a NUL */
+ temp[thyper.LowPart - 1] = 0;
+ memcpy(linkScp->mountPointStringp, temp, thyper.LowPart);
}
if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
- } /* don't have sym link contents cached */
+ } /* don't have symlink contents cached */
- return 0;
+ return code;
}
/* called with a held vnode and a path suffix, with the held vnode being a
*newSpaceBufferp = NULL;
lock_ObtainWrite(&linkScp->rw);
+ /*
+ * Do not get status if we do not already have a callback.
+ * The process of reading the symlink string will obtain status information
+ * in a single RPC. No reason to add a second round trip.
+ *
+ * If we do have a callback, use cm_SyncOp to get status in case the
+ * current cm_user_t is not the same as the one that obtained the
+ * symlink string contents.
+ */
+ if (cm_HaveCallback(linkScp)) {
+ code = cm_SyncOp(linkScp, NULL, userp, reqp, 0,
+ CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+ if (code) {
+ lock_ReleaseWrite(&linkScp->rw);
+ cm_ReleaseSCache(linkScp);
+ goto done;
+ }
+ cm_SyncOpDone(linkScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ }
code = cm_HandleLink(linkScp, userp, reqp);
if (code)
goto done;
StringCbCopyA((char *) tsp->data, sizeof(tsp->data), linkp+cm_mountRootLen+1);
else
tsp->data[0] = 0;
- *newRootScpp = cm_data.rootSCachep;
- cm_HoldSCache(cm_data.rootSCachep);
+ *newRootScpp = cm_RootSCachep(userp, reqp);
+ cm_HoldSCache(*newRootScpp);
} else if (linkp[0] == '\\' && linkp[1] == '\\') {
if (!strnicmp(&linkp[2], cm_NetbiosName, (len = (long)strlen(cm_NetbiosName))))
{
if (*p == '\\')
*p = '/';
}
- *newRootScpp = cm_data.rootSCachep;
- cm_HoldSCache(cm_data.rootSCachep);
+ *newRootScpp = cm_RootSCachep(userp, reqp);
+ cm_HoldSCache(*newRootScpp);
} else {
linkScp->fileType = CM_SCACHETYPE_DFSLINK;
StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
* but this seems to create problems. instead, we will just
* reject the link */
StringCchCopyA(tsp->data,lengthof(tsp->data), linkp+1);
- *newRootScpp = cm_data.rootSCachep;
- cm_HoldSCache(cm_data.rootSCachep);
+ *newRootScpp = cm_RootSCachep(userp, reqp);
+ cm_HoldSCache(*newRootScpp);
#else
/* we still copy the link data into the response so that
* the user can see what the link points to
case VOFFLINE:
case VSALVAGE:
case VNOSERVICE:
+ case VIO:
code = (&bbp->stats[0])->errorCode;
break;
default:
return cm_SetLength(scp, &attrp->length, userp, reqp);
lock_ObtainWrite(&scp->rw);
+ /* Check for RO volume */
+ if (scp->flags & CM_SCACHEFLAG_RO) {
+ code = CM_ERROR_READONLY;
+ lock_ReleaseWrite(&scp->rw);
+ return code;
+ }
+
/* otherwise, we have to make an RPC to get the status */
code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
if (code) {
}
#endif /* AFS_FREELANCE_CLIENT */
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
/* before starting the RPC, mark that we're changing the file data, so
* that someone who does a chmod will know to wait until our call
* completes.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
}
#endif /* AFS_FREELANCE_CLIENT */
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
/* before starting the RPC, mark that we're changing the directory
* data, so that someone who does a chmod on the dir will wait until
* our call completes.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
return CM_ERROR_CROSSDEVLINK;
}
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
cm_dirOp_t dirop;
fschar_t *fnamep = NULL;
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO)
+ return CM_ERROR_READONLY;
+
memset(&volSync, 0, sizeof(volSync));
/* before starting the RPC, mark that we're changing the directory data,
* so that someone who does a chmod on the dir will wait until our
* call completes.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
if (fnamep == NULL) {
code = -1;
#ifdef USE_BPLUS
- code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+ code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &dirop);
if (code == 0) {
code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
if (code == 0)
if (code)
goto done;
+ /* Check for RO volume */
+ if (dscp->flags & CM_SCACHEFLAG_RO) {
+ code = CM_ERROR_READONLY;
+ goto done;
+ }
+
/* before starting the RPC, mark that we're changing the directory data,
* so that someone who does a chmod on the dir will wait until our
* call completes.
*/
- cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, CM_DIROP_FLAG_NONE,
+ &dirop);
lock_ObtainWrite(&dscp->rw);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
lock_ReleaseWrite(&dscp->rw);
} else {
code = 0;
}
+
+ /* Check for RO volume */
+ if (code == 0 &&
+ (oldDscp->flags & CM_SCACHEFLAG_RO) || (newDscp->flags & CM_SCACHEFLAG_RO)) {
+ code = CM_ERROR_READONLY;
+ }
+
if (code)
goto done;
if (oldNamep == NULL) {
code = -1;
#ifdef USE_BPLUS
- code = cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_READ, &oldDirOp);
+ code = cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_READ,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
if (code == 0) {
code = cm_BPlusDirLookupOriginalName(&oldDirOp, cOldNamep, &oldNamep);
if (code == 0)
}
oneDir = 1;
- cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, cOldNamep);
cm_dnlcRemove(oldDscp, cNewNamep);
}
if (oldDscp->fid.vnode < newDscp->fid.vnode) {
- cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, cOldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
if (code != 0)
cm_EndDirOp(&oldDirOp);
if (code == 0) {
- cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &newDirOp);
lock_ObtainWrite(&newDscp->rw);
cm_dnlcRemove(newDscp, cNewNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
}
else {
/* lock the new vnode entry first */
- cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &newDirOp);
lock_ObtainWrite(&newDscp->rw);
cm_dnlcRemove(newDscp, cNewNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
if (code != 0)
cm_EndDirOp(&newDirOp);
if (code == 0) {
- cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE,
+ CM_DIROP_FLAG_NONE, &oldDirOp);
lock_ObtainWrite(&oldDscp->rw);
cm_dnlcRemove(oldDscp, cOldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,