public bool RefreshHigherChanges(ulong id) { // first remove changes from this id RemoveHigherChanges(RootFolder, id); bool save = false; OpStorage storage = Storages.GetStorage(id); if (storage == null) return save; // this is the first step in auto-integration // go through this id's storage file, and add any changes or updates to our own system string path = Storages.GetFilePath(storage); if (!File.Exists(path)) return save; try { using (TaggedStream filex = new TaggedStream(path, Protocol)) using (IVCryptoStream crypto = IVCryptoStream.Load(filex, storage.File.Header.FileKey)) { PacketStream stream = new PacketStream(crypto, Protocol, FileAccess.Read); ulong currentUID = 0; LocalFolder currentFolder = RootFolder; LocalFile currentFile = null; bool ignoreCurrent = false; bool readingProject = false; G2Header header = null; while (stream.ReadPacket(ref header)) { if (header.Name == StoragePacket.Root) { StorageRoot root = StorageRoot.Decode(header); readingProject = (root.ProjectID == ProjectID); } if (readingProject) { if (header.Name == StoragePacket.Folder) { StorageFolder readFolder = StorageFolder.Decode(header); // if new uid if (currentUID != readFolder.UID) { // if only 1 entry in changes for previous file, remove it, its probably a dupe of local // and integration needs more than one file to happen if (currentFolder.HigherChanges.ContainsKey(id) && currentFolder.HigherChanges[id].Count == 1) currentFolder.HigherChanges.Remove(id); // set new id currentUID = readFolder.UID; // check scope ignoreCurrent = false; if (readFolder.Scope.Count > 0 && !Core.Trust.IsInScope(readFolder.Scope, Core.UserID, ProjectID)) ignoreCurrent = true; bool added = false; while (!added) { if (currentFolder.Info.UID == readFolder.ParentUID) { LocalFolder subFolder = null; if (currentFolder.Folders.SafeTryGetValue(currentUID, out subFolder)) currentFolder = subFolder; else { // if ignoring, add folder so we can traverse id's file, but dont save changes to local storage mapping if (ignoreCurrent) { currentFolder = new LocalFolder(currentFolder, readFolder); break; } // check for conflicting name currentFolder.Folders.LockReading(delegate() { foreach (LocalFolder subfolder in currentFolder.Folders.Values) if (!subfolder.Info.IsFlagged(StorageFlags.Archived) && subfolder.Info.Name == readFolder.Name) subfolder.Info.Name = subfolder.Info.Name + ".fix"; }); // if not found, create folder currentFolder = currentFolder.AddFolderInfo(readFolder); save = true; } added = true; } else if (currentFolder.Parent == null) break; // error, couldn't find parent of folder that was read else if (currentFolder.Parent.GetType() == typeof(LocalFolder)) currentFolder = currentFolder.Parent; else break; } } // if file does not equal null if (currentFolder != null && !ignoreCurrent) { // log change if file newer than ours // if if not in higher's history // or if file integrated by higher by a node we would have inherited from // we look for our own file in higher changes, if there then we can auto integrate if (readFolder.Date >= currentFolder.Info.Date) if (readFolder.IntegratedID == 0 || readFolder.IntegratedID == Core.UserID || Core.Trust.IsAdjacent(readFolder.IntegratedID, ProjectID)) currentFolder.AddHigherChange(id, readFolder); } } if (header.Name == StoragePacket.File) { StorageFile readFile = StorageFile.Decode(header); // if new uid if (currentUID != readFile.UID) { // if only 1 entry in changes for previous file, remove it, its probably a dupe of local // and integration needs more than one file to happen if (currentFile != null && currentFile.HigherChanges.ContainsKey(id) && currentFile.HigherChanges[id].Count == 1) currentFile.HigherChanges.Remove(id); // set new id currentUID = readFile.UID; currentFile = null; // check scope ignoreCurrent = false; if (readFile.Scope.Count > 0 && !Core.Trust.IsInScope(readFile.Scope, Core.UserID, ProjectID)) { ignoreCurrent = true; continue; } // if file exists with UID, else add file as temp, mark as changed if (!currentFolder.Files.SafeTryGetValue(currentUID, out currentFile)) { // check for conflicting name currentFolder.Files.LockReading(delegate() { foreach (LocalFile checkFile in currentFolder.Files.Values) if (!checkFile.Info.IsFlagged(StorageFlags.Archived) && checkFile.Info.Name == readFile.Name) checkFile.Info.Name = checkFile.Info.Name + ".fix"; }); currentFile = currentFolder.AddFileInfo(readFile); save = true; if (!Storages.FileExists(currentFile.Info)) Storages.DownloadFile(id, currentFile.Info); } } // if file does not equal null if (currentFile != null && !ignoreCurrent) { if (readFile.Date >= currentFile.Info.Date) if (readFile.IntegratedID == 0 || readFile.IntegratedID == Core.UserID || Core.Trust.IsAdjacent(readFile.IntegratedID, ProjectID)) currentFile.AddHigherChange(id, readFile); } } } } } } catch { } return save; }
private FolderNode LoadWorking(TreeListNode parent, LocalFolder folder) { FolderNode node = new FolderNode(this, folder.Info, parent, false); node.Archived = folder.Archived; node.Integrated = folder.Integrated; if (SelectedFolder != null && node.Details.UID == SelectedFolder.Details.UID) { node.Selected = true; SelectedFolder = node; } if (!folder.Info.IsFlagged(StorageFlags.Archived) || GhostsButton.Checked) GuiUtils.InsertSubNode(parent, node); if (parent.GetType() == typeof(FolderNode)) { FolderNode parentNode = (FolderNode)parent; parentNode.Folders[folder.Info.UID] = node; } if (node.Details.IsFlagged(StorageFlags.Modified)) node.EnsureVisible(); folder.Folders.LockReading(delegate() { foreach (LocalFolder sub in folder.Folders.Values) LoadWorking(node, sub); }); folder.Files.LockReading(delegate() { foreach (LocalFile file in folder.Files.Values) { FileItem item = new FileItem(this, node, file.Info, false); item.Archived = file.Archived; item.Integrated = file.Integrated; node.Files[file.Info.UID] = item; } }); return node; }
public void ReadyChange(LocalFolder folder) { Modified = true; PeriodicSave = true; folder.Modify(Core.TimeNow, folder.Info.Clone()); }
public void ReadyChange(LocalFolder folder, StorageFolder newInfo) { Modified = true; PeriodicSave = true; folder.Modify(Core.TimeNow, newInfo); }
public void LockFolder(string dirpath, LocalFolder folder, bool subs, List<LockError> errors ) { folder.Files.LockReading(delegate() { foreach (LocalFile file in folder.Files.Values) Storages.LockFileCompletely(Core.UserID, ProjectID, dirpath, file.Archived, errors); }); folder.Info.RemoveFlag(StorageFlags.Unlocked); if (subs) folder.Folders.LockReading(delegate() { foreach (LocalFolder subfolder in folder.Folders.Values) LockFolder(dirpath + Path.DirectorySeparatorChar + subfolder.Info.Name, subfolder, subs, errors); }); try { string path = RootPath + dirpath; if (Directory.Exists(path) && Directory.GetDirectories(path).Length == 0 && Directory.GetFiles(path).Length == 0) Directory.Delete(path, true); } catch { } Storages.CallFolderUpdate(ProjectID, Utilities.StripOneLevel(dirpath), folder.Info.UID, WorkingChange.Updated); }
public void MoveFolder(LocalFolder sourceFolder, string destPath, List<string> errors) { // cant move root folder ;) if (sourceFolder.Parent == null) return; LocalFolder parentFolder = sourceFolder.Parent; LocalFolder destFolder = GetLocalFolder(destPath); if (destFolder == null || destFolder == parentFolder) return; // prevent folder from being moved inside of itself LocalFolder oneUp = destFolder; while (oneUp != null) { if (oneUp == sourceFolder) return; oneUp = oneUp.Parent; } // if name exists with diff uid, return error destFolder.Folders.LockReading(delegate() { foreach (LocalFolder check in destFolder.Folders.Values) if (check.Info.UID != sourceFolder.Info.UID && String.Compare(check.Info.Name, sourceFolder.Info.Name, true) == 0) { errors.Add("Folder with same name exists at " + destPath); return; } }); // if uid exists in destination, merge histories with diff hashes WorkingChange destChange = WorkingChange.Created; WorkingChange sourceChange = WorkingChange.Updated; if (destFolder.Folders.SafeContainsKey(sourceFolder.Info.UID)) { destFolder.Folders.SafeAdd(sourceFolder.Info.UID, sourceFolder); destChange = WorkingChange.Updated; } else destFolder.AddFolder(sourceFolder); // make note file was moved at source in destination LocalFolder ghost = new LocalFolder(parentFolder, sourceFolder.Info.Clone()); ReadyChange(sourceFolder); sourceFolder.Parent = destFolder; string parentPath = parentFolder.GetPath(); sourceFolder.Info.Note = "Moved from " + (parentPath == "" ? Path.DirectorySeparatorChar.ToString() : parentPath); sourceFolder.Info.ParentUID = destFolder.Info.UID; parentFolder.Folders.SafeRemove(sourceFolder.Info.UID); // only leave a ghost if this file has a committed history if (sourceFolder.Archived.SafeCount > 1 || !sourceFolder.Info.IsFlagged(StorageFlags.Modified)) { ghost.Archived.SafeAddFirst(ghost.Info); parentFolder.AddFolder(ghost); ReadyChange(ghost); // created ghost needs to have 2 entries because applydiff() looks for date of previous file to apply change ghost.Info.Note = "Moved to " + (destPath == "" ? Path.DirectorySeparatorChar.ToString() : destPath); ghost.Info.SetFlag(StorageFlags.Archived); } else sourceChange = WorkingChange.Removed; // move actual file if unlocked on disk, create new folder if need be string name = sourceFolder.Info.Name; if (File.Exists(RootPath + parentFolder.GetPath() + Path.DirectorySeparatorChar + name)) { Directory.CreateDirectory(RootPath + destPath); // exceptions handled by caller File.Move(RootPath + parentFolder.GetPath() + Path.DirectorySeparatorChar + name, RootPath + destPath + Path.DirectorySeparatorChar + name); } // file created at destination, updated at source Storages.CallFolderUpdate(ProjectID, destPath, sourceFolder.Info.UID, destChange); Storages.CallFolderUpdate(ProjectID, parentFolder.GetPath(), sourceFolder.Info.UID, sourceChange); }
public LocalFolder AddFolderInfo(StorageFolder info) { LocalFolder folder = null; if (!Folders.SafeTryGetValue(info.UID, out folder)) { folder = new LocalFolder(this, info); Folders.SafeAdd(info.UID, folder); } // if this is integration info, add to integration map if (info.IntegratedID != 0) folder.Integrated.SafeAdd(info.IntegratedID, info); // if history info, add to files history else folder.Archived.SafeAddLast(info); return folder; }
public WorkingStorage(StorageService storages, uint project) { Storages = storages; Core = Storages.Core; Protocol = storages.Protocol; RootPath = Storages.GetRootPath(Core.UserID, project); ProjectID = project; StorageFolder packet = new StorageFolder(); packet.Name = Core.Trust.GetProjectName(project) + " Files"; RootFolder = new LocalFolder(null, packet); LoadWorking(); }
public void AddFolder(LocalFolder folder) { ulong uid = folder.Info.UID; Debug.Assert(!Folders.SafeContainsKey(uid)); Folders.SafeAdd(uid, folder); }
private void RemoveHigherChanges(LocalFolder folder, ulong id) { folder.Files.LockReading(delegate() { foreach (LocalFile file in folder.Files.Values) { if (id == 0) file.HigherChanges.Clear(); else if (file.HigherChanges.ContainsKey(id)) file.HigherChanges.Remove(id); } }); folder.Folders.LockReading(delegate() { foreach (LocalFolder subfolder in folder.Folders.Values) { if (id == 0) subfolder.HigherChanges.Clear(); else if (subfolder.HigherChanges.ContainsKey(id)) subfolder.HigherChanges.Remove(id); RemoveHigherChanges(subfolder, id); } }); }
private LocalFolder CreateNewFolder(LocalFolder parent, string dirname ) { StorageFolder info = new StorageFolder(); LocalFolder folder = new LocalFolder(parent, info); info.UID = Utilities.StrongRandUInt64(Core.StrongRndGen); info.ParentUID = parent.Info.UID; info.Name = dirname; info.Date = Core.TimeNow.ToUniversalTime(); info.Revs = 5; folder.Archived.SafeAddFirst(info); return folder; }
private bool AutoIntegrate(LocalFolder folder, List<LockError> errors) { bool save = false; if (!folder.Info.IsFlagged(StorageFlags.Modified)) { StorageFolder latestFolder = folder.Info; // this will process will find higher has integrated my file // and highest has integrated his file, and return latest // from self to highest foreach (ulong id in InheritIDs) if (folder.HigherChanges.ContainsKey(id)) // higherChanges consists of files that are newer than local foreach (StorageFolder changeFolder in folder.HigherChanges[id]) if (changeFolder.Date >= latestFolder.Date && Storages.ItemDiff(latestFolder, changeFolder) == StorageActions.None) { latestFolder = (StorageFolder)folder.HigherChanges[id][0]; // first element is newest file break; } // if current file/folder is not our own (itemdiff) if (Storages.ItemDiff(latestFolder, folder.Info) != StorageActions.None) { ReplaceFolder(folder.GetPath(), latestFolder, false); save = true; } } string dir = folder.GetPath(); folder.Files.LockReading(delegate() { foreach (LocalFile file in folder.Files.Values) if (AutoIntegrate(file, dir, errors)) save = true; }); folder.Folders.LockReading(delegate() { foreach (LocalFolder subfolder in folder.Folders.Values) if (AutoIntegrate(subfolder, errors)) save = true; }); return save; }
public LocalFolder(LocalFolder parent, StorageFolder info) { Parent = parent; Info = info; }
public void WriteWorkingFile(CryptoStream stream, LocalFolder folder, bool commit) { // write files and all archives if tracked folder.Files.LockReading(delegate() { foreach (LocalFile file in folder.Files.Values) { // history int count = 0; file.Archived.LockReading(delegate() { foreach (StorageFile archive in file.Archived) { if (file.Info.HashID == 0 || file.Info.Hash == null) continue; // happens if file is still being hashed and auto-save is called if (commit) { archive.RemoveFlag(StorageFlags.Modified); if (count == file.Info.Revs) break; } Protocol.WriteToFile(archive, stream); count++; } }); // integrated file.Integrated.LockReading(delegate() { foreach (ulong who in file.Integrated.Keys) { StorageFile integrated = (StorageFile)file.Integrated[who]; if (commit) integrated.RemoveFlag(StorageFlags.Modified); integrated.IntegratedID = who; Protocol.WriteToFile(integrated, stream); } }); } }); // foreach tracked folder, recurse folder.Folders.LockReading(delegate() { foreach (LocalFolder sub in folder.Folders.Values) { // history int count = 0; sub.Archived.LockReading(delegate() { foreach (StorageFolder archive in sub.Archived) { if (commit) { archive.RemoveFlag(StorageFlags.Modified); if (count == sub.Info.Revs) break; } Protocol.WriteToFile(archive, stream); count++; } }); // integrated sub.Integrated.LockReading(delegate() { foreach (StorageFile change in sub.Integrated.Values) { if (commit) change.RemoveFlag(StorageFlags.Modified); Protocol.WriteToFile(change, stream); } }); WriteWorkingFile(stream, sub, commit); } }); }
public void TrackFolder(string path, StorageFolder track) { string parentPath = Utilities.StripOneLevel(path); LocalFolder folder = GetLocalFolder(path); if (folder != null) return; LocalFolder parent = GetLocalFolder(parentPath); if (parent == null) return; folder = new LocalFolder(parent, track); folder.Archived.SafeAddFirst(track); folder.Info.SetFlag(StorageFlags.Modified); parent.AddFolder(folder); if (Directory.Exists(RootPath + parentPath + Path.DirectorySeparatorChar + folder.Info.Name)) folder.Info.SetFlag(StorageFlags.Unlocked); Modified = true; PeriodicSave = true; Storages.CallFolderUpdate(ProjectID, parentPath, folder.Info.UID, WorkingChange.Created); }