/// <summary> /// helper function for adding items in the copy queue /// </summary> /// <param name="myCollection"></param> /// <param name="queueTHRESHOLD"></param> /// <param name="destError"></param> /// <param name="coFolder"></param> private void FillQueue(ConcurrentQueue <CopyOperation> myCollection, int queueTHRESHOLD, Exception destError, CopyOperation coFolder) { if (destError != null) { throw new ArgumentException("Thread Copy Destination has failed", destError); } while (myCollection.Count > queueTHRESHOLD) { if (forceExceptionalStop) { return; } Thread.Sleep(100); } myCollection.Enqueue(coFolder); }
/// <summary> /// Copy the source folder content into a destination folder /// </summary> /// <param name="srcPath">source folder</param> /// <param name="destPath">destination folder</param> /// <returns>true if success</returns> private bool CopyFolderAndFilesWithImpersonation(string configID, string srcPath, string domainSrc, string userSrc, string passSrc, string destPath, string domainDest, string userDest, string passDest, out Exception outEx) { outEx = null; myCollection = new ConcurrentQueue <CopyOperation>(); byte[] buffer = new byte[bufferSize]; bool finished = false; Exception srcError = null; Exception destError = null; Thread thSource = new Thread(() => { try { //FileLogging.Log($"begin thSrc.", LogLevel.Info); using (Impersonation.LogonUser(domainSrc, userSrc, passSrc, LogonType.Network))//LogonType.Interactive { WindowsIdentity wid_current = WindowsIdentity.GetCurrent(); //FileLogging.Log($"impersonated thSrc. {wid_current.Name}", LogLevel.Info); //scan all of the directories var lstDirectories = Directory.GetDirectories(srcPath, "*", SearchOption.AllDirectories); dirCount = lstDirectories.LongCount(); foreach (string dirPath in lstDirectories) { CopyOperation coFolder = new CopyOperation { Operation = OperationType.WriteFolder, Argument = dirPath.Replace(srcPath, string.Empty) }; FillQueue(myCollection, queueTHRESHOLD, destError, coFolder); if (forceExceptionalStop) { return; } //FileLogging.Log($"q-d: {coFolder.Argument}", LogLevel.Info); } //scan all files var lstFiles = Directory.GetFiles(srcPath, "*.*", SearchOption.AllDirectories); fileCount = lstFiles.LongCount(); foreach (string newPath in lstFiles) { using (FileStream fs = File.Open(newPath, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read)) { int readB; long offset = 0; while ((readB = fs.Read(buffer, 0, bufferSize)) > 0) { CopyOperation coFile = new CopyOperation { Operation = OperationType.WriteFile, Argument = newPath.Replace(srcPath, string.Empty), Offset = offset, Content = buffer.SubArray(0, readB) }; FillQueue(myCollection, queueTHRESHOLD, destError, coFile); if (forceExceptionalStop) { return; } //FileLogging.Log($"q-f: {coFile.Argument} - {coFile.Offset}", LogLevel.Info); offset += readB; } } } //YEY! finished = true; //wic.Undo(); } } catch (Exception err) { srcError = err; forceExceptionalStop = true; finished = true; } }); Thread thDest = new Thread(() => { try { //FileLogging.Log($"begin thDest.", LogLevel.Info); Thread.Sleep(200); long dirIndex = 0, fileIndex = 0; string lastFile = string.Empty; DateTime lastSent = DateTime.MinValue; int copyPercent; using (Impersonation.LogonUser(domainDest, userDest, passDest, LogonType.NewCredentials))//LogonType.NewCredentials { WindowsIdentity wid_current = WindowsIdentity.GetCurrent(); //FileLogging.Log($"impersonated thDest. {wid_current.Name}", LogLevel.Info); while (!finished || myCollection.Count > 0) { while (myCollection.Count == 0 && !forceExceptionalStop) { Thread.Sleep(100); } if (forceExceptionalStop) { return; } CopyOperation item = null; if (myCollection.TryDequeue(out item)) { switch (item.Operation) { case OperationType.WriteFolder: string newFolder = UncCombine(destPath, item.Argument); Directory.CreateDirectory(newFolder); dirIndex++; break; case OperationType.WriteFile: string destFile = UncCombine(destPath, item.Argument); using (var fs = ((item.Offset == 0) && File.Exists(destFile)) ? File.Create(destFile) : File.OpenWrite(destFile)) { fs.Seek(item.Offset, SeekOrigin.Begin); fs.Write(item.Content, 0, item.Content.Length); } if (destFile != lastFile) { fileIndex++; lastFile = destFile; } break; default: break; } //update report status DateTime now = DateTime.UtcNow; if (now > lastSent) { copyPercent = Convert.ToInt32(20 * (dirCount > 0 ? (double)dirIndex / dirCount : 1) + 80 * (fileCount > 0 ? (double)fileIndex / fileCount : 1)); lastSent = now + TimeSpan.FromMilliseconds(SignalRController.SIGNALR_REFRESH_INTERVAL); ReportAgentStatus(item.Operation == OperationType.WriteFolder ? StatusType.CopyFolders : StatusType.CopyFiles, item.Operation == OperationType.WriteFolder ? $"Copy folders in progress {dirIndex}/{dirCount} ..." : $"Copy files in progress {fileIndex}/{fileCount} ..." , copyPercent, configID); } } else { throw new ArgumentException("Could not extract item from queue"); } } } } catch (Exception err) { destError = err; forceExceptionalStop = true; } }); //clear exception forceExceptionalStop = false; thDest.Start(); thSource.Start(); //wait to complete or fail thSource.Join(); thDest.Join(); myCollection = new ConcurrentQueue <CopyOperation>(); if (srcError != null) { outEx = srcError; logger.Error($"srcErr: {srcError}"); return(false); } if (destError != null) { outEx = destError; logger.Error($"destErr: {destError}"); return(false); } if (externalError != null) { outEx = externalError; logger.Debug($"externalError: {destError}"); return(false); } logger.Error($"LAN Copy completed!"); return(true); }