/// <summary> /// Returns a fully recursive listing inside the specified (directory) item /// </summary> /// <param name="p">The clientItem (should be of type directory) to list inside</param> /// <param name="skipIgnored">if true, ignored items are not returned</param> private IEnumerable <ClientItem> ListRecursiveInside(ClientItem p, bool skipIgnored = true) { yield return(p); var cpath = controller.GetCommonPath(p.FullPath, false); var list = new List <ClientItem>(List(cpath, skipIgnored).ToList()); if (ListingFailed) { yield break; } if (skipIgnored) { list.RemoveAll(x => !controller.ItemGetsSynced(x.FullPath, false)); } foreach (var f in list.Where(x => x.Type == ClientItemType.File)) { yield return(f); } foreach (var d in list.Where(x => x.Type == ClientItemType.Folder)) { foreach (var f in ListRecursiveInside(d, skipIgnored)) { yield return(f); } } }
/// <summary> /// Raised when a file was changed /// </summary> /// <param name="source"></param> /// <param name="e"></param> private void FileChanged(object source, FileSystemEventArgs e) { string cpath = controller.GetCommonPath(e.FullPath, true); if (!controller.ItemGetsSynced(cpath) || !File.Exists(e.FullPath)) { return; } int retries = 0; while (true) { if (!Common.FileIsUsed(e.FullPath)) { break; } // Exit after 5 retries if (retries > 5) { return; } // Sleep for half a second, then check again System.Threading.Thread.Sleep(500); retries++; } #if __MonoCs__ // Ignore temp files on linux if (Common._name(cpath).StartsWith(".goutputstream-") || Common._name(cpath).EndsWith("~")) { return; } #endif var fli = new FileInfo(e.FullPath); controller.SyncQueue.Add(new SyncQueueItem(controller) { Item = new ClientItem { Name = e.Name, FullPath = e.FullPath, Type = ClientItemType.File, Size = fli.Length, LastWriteTime = fli.LastWriteTime }, SyncTo = SyncTo.Remote, ActionType = e.ChangeType == WatcherChangeTypes.Changed ? ChangeAction.changed : ChangeAction.created }); }
/// <summary> /// Raised when file/folder is renamed /// </summary> private async void OnRenamed(object source, RenamedEventArgs e) { Log.Write(l.Debug, $"Item was renamed: {e.OldName}"); if (!_controller.ItemGetsSynced(e.FullPath, true)) { return; } var isFile = Common.PathIsFile(e.FullPath); // Find if renamed from/to temporary file var renamedFromTempFile = new FileInfo(e.OldFullPath).Attributes.HasFlag(FileAttributes.Temporary); var renamedToTempFile = new FileInfo(e.FullPath).Attributes.HasFlag(FileAttributes.Temporary); // Get common path to old (renamed) file var oldCommon = _controller.GetCommonPath(e.OldFullPath, true); Log.Write(l.Debug, $"isFile: {isFile} renamedFromTempFile: {renamedFromTempFile} renamedToTempFile: {renamedToTempFile} inFileLog: {_controller.FileLog.Contains(oldCommon)}"); // Add to queue if (isFile && renamedFromTempFile && !renamedToTempFile && !_controller.FileLog.Contains(oldCommon)) { await AddToQueue(e, ChangeAction.changed); } else { await AddToQueue(e, ChangeAction.renamed); } }
/// <summary> /// Returns a fully recursive listing inside the specified (directory) item /// </summary> /// <param name="p">The clientItem (should be of type directory) to list inside</param> /// <param name="skipIgnored">if true, ignored items are not returned</param> private async Task <IEnumerable <ClientItem> > ListRecursiveInside(ClientItem p, bool skipIgnored = true) { var cpath = Controller.GetCommonPath(p.FullPath, false); var list = await List(cpath, skipIgnored); if (ListingFailed) { return(default(IEnumerable <ClientItem>)); } if (skipIgnored) { list = list.Where(x => !Controller.ItemSkipped(x)); } var subItems = list.Where(x => x.Type == ClientItemType.File).ToList(); foreach (var d in list.Where(x => x.Type == ClientItemType.Folder)) { subItems.Add(d); foreach (var f in await ListRecursiveInside(d, skipIgnored)) { subItems.Add(f); } } return(subItems); }
/// <summary> /// Check a local folder and all of its subitems for changes /// </summary> private void CheckLocalFolder(SyncQueueItem folder) { if (!_controller.ItemGetsSynced(folder.CommonPath) && folder.CommonPath != ".") { return; } var cp = (folder.Item.FullPath == _controller.Paths.Local) ? "." : folder.CommonPath; var cpExists = cp == "." || _controller.Client.Exists(cp); if (!cpExists) { folder.AddedOn = DateTime.Now; base.Add(folder); } var remoteFilesList = cpExists ? new List <string>(_controller.Client.ListRecursive(cp).Select(x => x.FullPath)) : new List <string>(); remoteFilesList = remoteFilesList.ConvertAll(x => _controller.GetCommonPath(x, false)); if (_controller.Client.ListingFailed) { folder.Status = StatusType.Failure; folder.CompletedOn = DateTime.Now; _completedList.Add(folder); _controller.Client.Reconnect(); return; } var di = new DirectoryInfo(folder.LocalPath); foreach (var d in di.GetDirectories("*", SearchOption.AllDirectories).Where(x => !remoteFilesList.Contains(_controller.GetCommonPath(x.FullName, true)))) { if (!_controller.ItemGetsSynced(d.FullName, true)) { continue; } // TODO: Base add instead? Add(new SyncQueueItem(_controller) { Item = new ClientItem { Name = d.Name, FullPath = d.FullName, Type = ClientItemType.Folder, LastWriteTime = DateTime.Now, // Doesn't matter Size = 0x0 // Doesn't matter }, ActionType = ChangeAction.changed, Status = StatusType.Waiting, SyncTo = SyncTo.Remote }); } foreach (var f in di.GetFiles("*", SearchOption.AllDirectories)) { var cpath = _controller.GetCommonPath(f.FullName, true); if (!_controller.ItemGetsSynced(cpath)) { continue; } if (!remoteFilesList.Contains(cpath) || _controller.FileLog.GetLocal(cpath) != f.LastWriteTime) { // TODO: Base add instead? Add(new SyncQueueItem(_controller) { Item = new ClientItem { Name = f.Name, FullPath = f.FullName, Type = ClientItemType.File, LastWriteTime = File.GetLastWriteTime(f.FullName), Size = new FileInfo(f.FullName).Length }, ActionType = ChangeAction.changed, Status = StatusType.Waiting, SyncTo = SyncTo.Remote }); } } }
/// <summary> /// Check a local folder and all of its subitems for changes /// </summary> private async Task CheckLocalFolder(SyncQueueItem folder) { if (!_controller.ItemGetsSynced(folder.CommonPath) && folder.CommonPath != ".") { return; } var cp = (folder.Item.FullPath == _controller.Paths.Local) ? "." : folder.CommonPath; var cpExists = cp == "." || _controller.Client.Exists(cp); if (!cpExists) { folder.AddedOn = DateTime.Now; base.Add(folder); } var remoteFilesList = cpExists ? (await _controller.Client.ListRecursive(cp)).Select(x => x.FullPath).ToList() : new List <string>(); remoteFilesList = remoteFilesList.ConvertAll(x => _controller.GetCommonPath(x, false)); if (_controller.Client.ListingFailed) { folder.Status = StatusType.Failure; folder.CompletedOn = DateTime.Now; _completedList.Add(folder, StatusType.Failure); await _controller.Client.Reconnect(); return; } var di = new DirectoryInfo(folder.LocalPath); foreach (var d in di.GetDirectories("*", SearchOption.AllDirectories)) { var cpath = _controller.GetCommonPath(d.FullName, true); if (remoteFilesList.Contains(cpath)) { continue; } if (!_controller.ItemGetsSynced(d.FullName, true)) { continue; } base.Add(new SyncQueueItem(_controller) { Item = new ClientItem(d) { FullPath = d.FullName }, ActionType = ChangeAction.changed, Status = StatusType.Waiting, SyncTo = SyncTo.Remote }); } foreach (var f in di.GetFiles("*", SearchOption.AllDirectories)) { var cpath = _controller.GetCommonPath(f.FullName, true); if (!_controller.ItemGetsSynced(cpath)) { continue; } if (!remoteFilesList.Contains(cpath) || _controller.FileLog.GetLocal(cpath) != f.LastWriteTime) { base.Add(new SyncQueueItem(_controller) { Item = new ClientItem(f), ActionType = ChangeAction.changed, Status = StatusType.Waiting, SyncTo = SyncTo.Remote }); } } }
/// <summary> /// Check a local folder and all of its subitems for changes /// </summary> private async Task CheckLocalFolder(SyncQueueItem folder) { if (_controller.ItemSkipped(folder.Item) && folder.CommonPath != ".") { return; } var cp = (folder.Item.FullPath == _controller.Paths.Local) ? "." : folder.CommonPath; var cpExists = cp == "." || _controller.Client.Exists(cp); if (!cpExists) { folder.AddedOn = DateTime.Now; base.Add(folder); } var remoteFilesList = cpExists ? (await _controller.Client.ListRecursive(cp)).Select(x => x.FullPath).ToList() : new List <string>(); remoteFilesList = remoteFilesList.ConvertAll(x => _controller.GetCommonPath(x, false)); if (_controller.Client.ListingFailed) { folder.Status = StatusType.Failure; folder.CompletedOn = DateTime.Now; _completedList.Add(folder, StatusType.Failure); await _controller.Client.Reconnect(); return; } var di = new DirectoryInfo(folder.LocalPath); foreach (var d in di.GetDirectories("*", SearchOption.AllDirectories)) { var cpath = _controller.GetCommonPath(d.FullName, true); if (remoteFilesList.Contains(cpath)) { continue; } if (_controller.ItemSkipped(d)) { continue; } base.Add(new SyncQueueItem(_controller) { Item = new ClientItem(d) { FullPath = d.FullName }, ActionType = ChangeAction.changed, Status = StatusType.Waiting, SyncTo = SyncTo.Remote }); } foreach (var f in di.GetFiles("*", SearchOption.AllDirectories)) { if (_controller.ItemSkipped(f)) { continue; } var sqi = new SyncQueueItem(_controller) { Item = new ClientItem(f), ActionType = ChangeAction.changed, Status = StatusType.Waiting, SyncTo = SyncTo.Remote }; var cpath = sqi.CommonPath; if (!_controller.FileLog.Contains(cpath) && remoteFilesList.Contains(cpath)) { // untracked file, exists both locally and on server. var areIdentical = await _controller.Client.FilesAreIdentical(cpath, f.FullName); if (areIdentical) { _controller.FileLog.PutFile(sqi); continue; } } else if (remoteFilesList.Contains(cpath) && _controller.FileLog.GetLocal(cpath) == f.LastWriteTime) { // tracked file, local file unmodified. continue; } // local file should be uploaded. base.Add(sqi); } }