/// <summary> /// Move a given relative path to a new name, in the same directory. /// </summary> public void RenamePath(string srcPath, string newName) { Debug.Assert(KfsPath.IsValidFileName(newName)); // Disallow all user operations until the pipeline stabilized. Share.DisallowUserOp("RenamePath() called", AllowedOpStatus.None); GateEntry("RenamePath"); try { // Check that the new name has no invalid characters. if (!KfsPath.IsValidFileName(newName)) throw new GateIllegalException("Invalid name (" + newName + "). Note that files and folders cannot contain any of the following characters:\n*, \\, /, ?, :, |, <, >."); // Get the relative path to the source directory. String dirPath = KfsPath.DirName(srcPath); // Make sure the source exists. GatePathType srcType = GetInternalPathType(srcPath); if (srcType != GatePathType.Dir && srcType != GatePathType.File) throw new GateSyncException(); // Make sure the destination does not exist. String dstPath = dirPath + newName; GatePathType dstType = GetInternalPathType(dstPath); if (dstType != GatePathType.None) throw new GateIllegalException("A file or folder with the name you specified " + "already exists. Please specify a different name."); // Check for transfers. List<String> transferPathArray = new List<String>(); transferPathArray.Add(srcPath); transferPathArray.Add(dstPath); ThrowIfContainFileTransfer(transferPathArray); // Get information about the source and the destination. bool fileFlag = (srcType == GatePathType.File); KfsServerObject srcObject = Share.ServerView.GetObjectByPath(srcPath); // The source exists only locally. if (srcObject == null) { // Move the file or directory locally. if (fileFlag) File.Move(Share.MakeAbsolute(srcPath), Share.MakeAbsolute(dstPath)); else Directory.Move(Share.MakeAbsolute(srcPath), Share.MakeAbsolute(dstPath)); } // Ask the server to move the file. else { KfsPhase1Payload payload = new KfsPhase1Payload(); KfsServerObject dirObject = Share.ServerView.GetObjectByPath(dirPath); payload.AddMoveOp(fileFlag, srcObject.Inode, srcObject.CommitID, dirObject.Inode, dirObject.CommitID, newName); // Request the move on the server. Debug.Assert(Share.MetaDataManager.Status == MetaDataManagerStatus.Idle); Share.MetaDataManager.QueueOperation(payload, null, MetaDataTask.Move); } } catch (Exception ex) { HandleException(ex); } GateExit("RenamePath"); }
/// <summary> /// Helper method for MovePath(). 'fromLoc' and 'toLoc' must end with a /// delimiter when non-empty. /// </summary> private bool MovePathRecursive(String fromLoc, String toLoc, List<String> srcArray, KfsPhase1Payload payload, bool topLevelFlag, ref String typeConflictAction) { // Remember whether we moved all the sources we had to move. bool allMovedFlag = true; // Add the missing local directories for the destination. Share.AddMissingLocalDirectories(toLoc); // Move the sources. String fileExistAction = "a"; String dirExistAction = "a"; foreach (String srcName in srcArray) { // Get the objects involved. String srcRelPath = fromLoc + srcName; String dstRelPath = toLoc + srcName; String srcFullPath = Share.MakeAbsolute(srcRelPath); String dstFullPath = Share.MakeAbsolute(dstRelPath); KfsStatusPath srcStatus = Share.StatusView.GetPath(srcRelPath); KfsStatusPath dstStatus = Share.StatusView.GetPath(dstRelPath); Debug.Assert(srcStatus != null, "srcStatus == null"); KfsServerObject srcObject = srcStatus.ServerObject; KfsServerObject dstObject = (dstStatus == null) ? null : dstStatus.ServerObject; GatePathType srcType = GetInternalPathType(srcRelPath); GatePathType dstType = GetInternalPathType(dstRelPath); // Stale types, get out of here. if (srcType == GatePathType.None || srcType == GatePathType.Stale || dstType == GatePathType.Stale) throw new GateSyncException(); // There is a type conflict. else if (dstType != GatePathType.None && srcType != dstType) { String prompt = "The entry " + srcRelPath + " conflicts with the entry " + dstRelPath + "."; ShowChoiceDialog(prompt, "sc", ref typeConflictAction); allMovedFlag = false; continue; } // Add the 'to' directory remotely if the source exists remotely. if (srcObject != null) AddMissingServerDirectories(toLoc, payload); // We are in a directory-directory situation. if (srcType == GatePathType.Dir && dstType == GatePathType.Dir) { if (topLevelFlag) { // Skip or overwrite the directory. String prompt = "This folder already contains a folder named '" + dstRelPath + "'." + Environment.NewLine + "If the files in the existing folder have the same name as files in the folder you are moving, they will be replaced. Do you still want to move this folder?"; String res = ShowChoiceDialog(prompt, "swc", ref dirExistAction); if (res == "s") { allMovedFlag = false; continue; } } // Move all files and directories contained in the source directory. String newFromLoc = srcRelPath + "/"; String newToLoc = dstRelPath + "/"; List<String> newSrcArray = new List<String>(); foreach (String name in srcStatus.ChildTree.Keys) newSrcArray.Add(name); bool subMovedFlag = MovePathRecursive(newFromLoc, newToLoc, newSrcArray, payload, false, ref typeConflictAction); // All subdirectories and files were moved. if (subMovedFlag) { // Ask the server to delete the source if it exists remotely. if (srcStatus.HasServerDir()) { payload.AddDeleteOp(false, srcObject.Inode, srcObject.CommitID); } // Otherwise, delete the source locally since the server won't do it // for us. else { File.SetAttributes(srcFullPath, FileAttributes.Normal); Directory.Delete(srcFullPath); } } // Not all subdirectories and files were moved. else allMovedFlag = false; } // We are in a file-none, file-file or dir-none situation. else { // Remember whether we are in a file-none or file-file situation. bool fileFlag = (srcType == GatePathType.File); // The destination exists. if (dstStatus != null) { // Skip the source or overwrite the destination. if (topLevelFlag && dstStatus.OnServerAndNotGhost()) { String prompt = "The file " + dstRelPath + " already exists."; String res = ShowChoiceDialog(prompt, "swc", ref fileExistAction); if (res == "s") { allMovedFlag = false; continue; } } // Delete the destination file locally if it exists. if (File.Exists(dstFullPath)) { File.SetAttributes(dstFullPath, FileAttributes.Normal); File.Delete(dstFullPath); } } // The source exists only locally. if (srcObject == null) { // The destination exists. if (dstStatus != null) { // If the destination file exists remotely and it is not a ghost, // pretend its current version was downloaded. This will make the // source appear as ModifiedCurrent or UnmodifiedCurrent. if (dstStatus.OnServerAndNotGhost()) { KfsServerFile f = dstObject as KfsServerFile; Debug.Assert(f != null); f.UpdateDownloadVersion(f.CurrentVersion, true); } } // Move the file or directory locally. if (fileFlag) File.Move(srcFullPath, dstFullPath); else Directory.Move(srcFullPath, dstFullPath); } // The source exists remotely. else { // The destination file also exists remotely. Remove it. if (dstObject != null) payload.AddDeleteOp(true, dstObject.Inode, dstObject.CommitID); // Ask the server to move the file. UInt64 parentInode; UInt64 parentCommitID; String parentRelPath; GetServerObjectPath(dstRelPath, out parentInode, out parentCommitID, out parentRelPath); payload.AddMoveOp(fileFlag, srcObject.Inode, srcObject.CommitID, parentInode, parentCommitID, parentRelPath); } } } return allMovedFlag; }