/// <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; }
/// <summary> /// Delete the selected relative paths recursively. /// </summary> public void DeletePath(List<String> pathArray) { GateEntry("DeletePath"); // Disallow all user operations until the pipeline stabilized. Share.DisallowUserOp("DeletePath() called", AllowedOpStatus.None); try { // Check for transfers. ThrowIfContainFileTransfer(pathArray); // Get the entries to delete, both locally and remotely. HashedSet<String> seenSet = new HashedSet<String>(); List<String> fileArray = new List<String>(); List<String> dirArray = new List<String>(); KfsPhase1Payload payload = new KfsPhase1Payload(); foreach (String path in pathArray) { // Get the paths in leaf-first order, so that we delete entries in // directories before their parents. foreach (KfsStatusPath sp in Share.StatusView.GetPathArray(path, true)) { // Skip already processed paths. if (seenSet.Contains(sp.Path)) continue; // Remember that we have processed that path. seenSet.Add(sp.Path); // Sanity check. if (sp.IsUndetermined() || sp.IsTypeConflict()) throw new GateSyncException(); // Handle remote deletion. if (sp.HasServerFile()) payload.AddDeleteOp(true, sp.ServerObject.Inode, sp.ServerObject.CommitID); else if (sp.HasServerDir()) payload.AddDeleteOp(false, sp.ServerObject.Inode, sp.ServerObject.CommitID); // Handle local deletion. if (sp.HasLocalFile()) fileArray.Add(sp.Path); else if (sp.HasLocalDir()) dirArray.Add(sp.Path); } } // Delete the files and directories locally. foreach (String path in fileArray) { try { string absPath = Share.MakeAbsolute(path); File.SetAttributes(absPath, FileAttributes.Normal); File.Delete(absPath); } // Silently ignore NotFoundExceptions since we WANT // to have this path removed from the disk. catch (FileNotFoundException) { } catch (DirectoryNotFoundException) { } } foreach (String path in dirArray) { try { string absPath = Share.MakeAbsolute(path); File.SetAttributes(absPath, FileAttributes.Normal); Directory.Delete(Share.MakeAbsolute(path)); } // Silently ignore NotFoundExceptions since we WANT // to have this path removed from the disk. catch (FileNotFoundException) { } catch (DirectoryNotFoundException) { } } // Request the deletion on the server. Debug.Assert(Share.MetaDataManager.Status == MetaDataManagerStatus.Idle); if (payload.OpList.Count > 0) Share.MetaDataManager.QueueOperation(payload, null, MetaDataTask.Delete); } catch (IOException ex) { Misc.KwmTellUser("Unable to delete the selected file or folder : " + Environment.NewLine + Environment.NewLine + ex.Message, "Error Deleting File or Folder", MessageBoxIcon.Error); } catch (Exception ex) { HandleException(ex); } GateExit("DeletePath"); }
/// <summary> /// Add an operation to delete the ghost specified in the payload /// specified. /// </summary> private void DeleteGhost(KfsServerObject o, KfsPhase1Payload p) { Debug.Assert(o.IsGhost()); p.AddDeleteOp(true, o.Inode, o.CommitID); }