code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp, NULL);
if (code == 0) {
- cm_Unlock(scp, sLockType, LOffset, LLength, key, userp, reqp);
+ cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, reqp);
} else {
/* In this case, we allow the file open to go through even
though we can't enforce mandatory locking on the
lock_ObtainWrite(&scp->rw);
if (*ldpp) {
cm_Unlock(scp, (*ldpp)->sLockType, (*ldpp)->LOffset, (*ldpp)->LLength,
- (*ldpp)->key, userp, reqp);
+ (*ldpp)->key, 0, userp, reqp);
free(*ldpp);
*ldpp = NULL;
}
long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
{
long code;
- cm_buf_t *bufp;
+ cm_buf_t *bufp = NULL;
osi_hyper_t thyper;
int tlen;
if (scp->mountPointStringp[0])
return 0;
- /* otherwise, we have to read it in */
- lock_ReleaseWrite(&scp->rw);
-
- thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(scp, &thyper, &bufp);
+#ifdef AFS_FREELANCE_CLIENT
+ /* File servers do not have data for freelance entries */
+ if (cm_freelanceEnabled &&
+ scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ scp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ code = cm_FreelanceFetchMountPointString(scp);
+ } else
+#endif /* AFS_FREELANCE_CLIENT */
+ {
+ /* otherwise, we have to read it in */
+ lock_ReleaseWrite(&scp->rw);
- lock_ObtainWrite(&scp->rw);
- if (code)
- return code;
+ thyper.LowPart = thyper.HighPart = 0;
+ code = buf_Get(scp, &thyper, &bufp);
- while (1) {
- code = cm_SyncOp(scp, bufp, userp, reqp, 0,
- CM_SCACHESYNC_READ | CM_SCACHESYNC_NEEDCALLBACK);
+ lock_ObtainWrite(&scp->rw);
if (code)
- goto done;
+ 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);
+ cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
- if (cm_HaveBuffer(scp, bufp, 0))
- break;
+ if (cm_HaveBuffer(scp, bufp, 0))
+ break;
- /* otherwise load buffer */
- code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
- if (code)
+ /* 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;
- }
- /* 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;
- }
+ /* 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);
+ /* 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->mountPointStringp[tlen-1] = 0;
- code = 0;
+ /* 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->mountPointStringp[tlen-1] = 0;
+ code = 0;
- done:
- if (bufp)
- buf_Release(bufp);
+ done:
+ if (bufp)
+ buf_Release(bufp);
+ }
return code;
}
code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
}
}
- if (!found || code < 0) { /* add mount point failed, so give up */
+ if (!found || code) { /* add mount point failed, so give up */
if (flags & CM_FLAG_CHECKPATH)
code = CM_ERROR_NOSUCHPATH;
else
lock_AssertWrite(&linkScp->rw);
if (!linkScp->mountPointStringp[0]) {
- /* read the link data */
- lock_ReleaseWrite(&linkScp->rw);
- thyper.LowPart = thyper.HighPart = 0;
- code = buf_Get(linkScp, &thyper, &bufp);
- lock_ObtainWrite(&linkScp->rw);
- 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);
+
+#ifdef AFS_FREELANCE_CLIENT
+ /* File servers do not have data for freelance entries */
+ if (cm_freelanceEnabled &&
+ linkScp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+ linkScp->fid.volume==AFS_FAKE_ROOT_VOL_ID )
+ {
+ code = cm_FreelanceFetchMountPointString(linkScp);
+ } else
+#endif /* AFS_FREELANCE_CLIENT */
+ {
+ /* read the link data from the file server*/
+ lock_ReleaseWrite(&linkScp->rw);
+ thyper.LowPart = thyper.HighPart = 0;
+ code = buf_Get(linkScp, &thyper, &bufp);
+ lock_ObtainWrite(&linkScp->rw);
+ if (code)
return code;
- }
- cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+ 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;
+ if (cm_HaveBuffer(linkScp, bufp, 0))
+ break;
- code = cm_GetBuffer(linkScp, bufp, NULL, userp, reqp);
- if (code) {
+ 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);
- return code;
+ return CM_ERROR_TOOBIG;
+ }
+
+ /* 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 */
}
- } /* 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);
- return CM_ERROR_TOOBIG;
}
+
+ if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
+ linkScp->fileType = CM_SCACHETYPE_DFSLINK;
- /* 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 */
-
- if ( !strnicmp(linkScp->mountPointStringp, "msdfs:", strlen("msdfs:")) )
- linkScp->fileType = CM_SCACHETYPE_DFSLINK;
- }
- buf_Release(bufp);
} /* don't have sym link contents cached */
return 0;
cm_dirOp_t newDirOp;
fschar_t * newNamep = NULL;
int free_oldNamep = FALSE;
+ cm_scache_t *oldScp = NULL, *newScp = NULL;
if (cOldNamep == NULL || cNewNamep == NULL ||
cm_ClientStrLen(cOldNamep) == 0 ||
cm_ClientStrLen(cNewNamep) == 0)
return CM_ERROR_INVAL;
+ /*
+ * Before we permit the operation, make sure that we do not already have
+ * an object in the destination directory that has a case-insensitive match
+ * for this name UNLESS the matching object is the object we are renaming.
+ */
+ code = cm_Lookup(oldDscp, cOldNamep, 0, userp, reqp, &oldScp);
+ if (code) {
+ osi_Log2(afsd_logp, "cm_Rename oldDscp 0x%p cOldName %S old name lookup failed",
+ oldDscp, osi_LogSaveStringW(afsd_logp, cOldNamep));
+ goto done;
+ }
+
+ code = cm_Lookup(newDscp, cNewNamep, CM_FLAG_CASEFOLD, userp, reqp, &newScp);
+ if (code == 0) {
+ /* found a matching object with the new name */
+ if (cm_FidCmp(&oldScp->fid, &newScp->fid)) {
+ /* and they don't match so return an error */
+ osi_Log2(afsd_logp, "cm_Rename newDscp 0x%p cNewName %S new name already exists",
+ newDscp, osi_LogSaveStringW(afsd_logp, cNewNamep));
+ code = CM_ERROR_EXISTS;
+ }
+ cm_ReleaseSCache(newScp);
+ newScp = NULL;
+ } else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
+ code = CM_ERROR_EXISTS;
+ } else {
+ code = 0;
+ }
+ if (code)
+ goto done;
+
if (oldNamep == NULL) {
code = -1;
#ifdef USE_BPLUS
userp, CM_MERGEFLAG_DIROP);
lock_ReleaseWrite(&oldDscp->rw);
- if (code == 0) {
- if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
-
+ if (code == 0 && cm_CheckDirOpForSingleChange(&oldDirOp)) {
#ifdef USE_BPLUS
- diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
- if (diropCode == CM_ERROR_INEXACT_MATCH)
- diropCode = 0;
- else if (diropCode == EINVAL)
+ diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
+ if (diropCode == CM_ERROR_INEXACT_MATCH)
+ diropCode = 0;
+ else if (diropCode == EINVAL)
#endif
- diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
+ diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
- if (diropCode == 0) {
- if (oneDir) {
- diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
-#ifdef USE_BPLUS
- cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
+ if (diropCode == 0) {
+ if (oneDir) {
+ diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
+#ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
#endif
- }
+ }
- if (diropCode == 0) {
- diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
+ if (diropCode == 0) {
+ diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
#ifdef USE_BPLUS
- cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
-#endif
- }
+ cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
+#endif
}
}
}
userp, CM_MERGEFLAG_DIROP);
lock_ReleaseWrite(&newDscp->rw);
+#if 0
+ /*
+ * The following optimization does not work.
+ * When the file server processed a RXAFS_Rename() request the
+ * FID of the object being moved between directories is not
+ * preserved. The client does not know the new FID nor the
+ * version number of the target. Not only can we not create
+ * the directory entry in the new directory, but we can't
+ * preserve the cached data for the file. It must be re-read
+ * from the file server. - jaltman, 2009/02/20
+ */
if (code == 0) {
/* we only make the local change if we successfully made
the change in the old directory AND there was only one
#endif
}
}
+#endif /* 0 */
cm_EndDirOp(&newDirOp);
}
+ /*
+ * After the rename the file server has invalidated the callbacks
+ * on the file that was moved nor do we have a directory reference
+ * to it anymore.
+ */
+ lock_ObtainWrite(&oldScp->rw);
+ cm_DiscardSCache(oldScp);
+ lock_ReleaseWrite(&oldScp->rw);
+
done:
+ if (oldScp)
+ cm_ReleaseSCache(oldScp);
+
if (free_oldNamep)
free(oldNamep);
unsigned char sLockType,
LARGE_INTEGER LOffset, LARGE_INTEGER LLength,
cm_key_t key,
+ afs_uint32 flags,
cm_user_t *userp,
cm_req_t *reqp)
{
cm_file_lock_t *fileLock;
osi_queue_t *q;
int release_userp = FALSE;
+ int exact_match = !(flags & CM_UNLOCK_FLAG_MATCH_RANGE);
+ int lock_found = 0;
+ LARGE_INTEGER RangeEnd;
osi_Log4(afsd_logp, "cm_Unlock scp 0x%p type 0x%x offset %d length %d",
scp, sLockType, (unsigned long)LOffset.QuadPart, (unsigned long)LLength.QuadPart);
- osi_Log3(afsd_logp, "... key <0x%x,0x%x,0x%x>",
- key.process_id, key.session_id, key.file_id);
+ osi_Log4(afsd_logp, "... key <0x%x,0x%x,0x%x> flags 0x%x",
+ key.process_id, key.session_id, key.file_id, flags);
+
+ if (!exact_match)
+ RangeEnd.QuadPart = LOffset.QuadPart + LLength.QuadPart;
+ try_again:
lock_ObtainRead(&cm_scacheLock);
for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
osi_assertx(FALSE, "invalid fid value");
}
#endif
- if (!IS_LOCK_DELETED(fileLock) &&
- cm_KeyEquals(&fileLock->key, &key, 0) &&
- fileLock->range.offset == LOffset.QuadPart &&
- fileLock->range.length == LLength.QuadPart) {
- break;
+ if (exact_match) {
+ if (!IS_LOCK_DELETED(fileLock) &&
+ cm_KeyEquals(&fileLock->key, &key, 0) &&
+ fileLock->range.offset == LOffset.QuadPart &&
+ fileLock->range.length == LLength.QuadPart) {
+ lock_found = 1;
+ break;
+ }
+ } else {
+
+ if (!IS_LOCK_DELETED(fileLock) &&
+ cm_KeyEquals(&fileLock->key, &key, 0) &&
+ fileLock->range.offset >= LOffset.QuadPart &&
+ fileLock->range.offset < RangeEnd.QuadPart &&
+ (fileLock->range.offset + fileLock->range.length) <= RangeEnd.QuadPart) {
+ lock_found = 1;
+ break;
+ }
}
}
if (!q) {
- osi_Log0(afsd_logp, "cm_Unlock lock not found; failure");
-
lock_ReleaseRead(&cm_scacheLock);
- /* The lock didn't exist anyway. *shrug* */
- return CM_ERROR_RANGE_NOT_LOCKED;
+ if (lock_found && !exact_match) {
+ code = 0;
+ goto done;
+ } else {
+ osi_Log0(afsd_logp, "cm_Unlock lock not found; failure");
+
+ /* The lock didn't exist anyway. *shrug* */
+ return CM_ERROR_RANGE_NOT_LOCKED;
+ }
}
/* discard lock record */
}
}
- if (release_userp)
+ if (release_userp) {
cm_ReleaseUser(userp);
+ release_userp = FALSE;
+ }
+
+ if (!exact_match)
+ goto try_again; /* might be more than one lock in the range */
done:
}
scp->serverLock = -1;
- scp->lockDataVersion = -1;
+ scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
lock_ReleaseWrite(&cm_scacheLock);
}