public override bool IsEntryUpdated(SyncEntry childEntry, IAdapterItem adapterItem, out EntryUpdateResult result) { const long TicksPerMillisecond = 10000; // 2017/11/24: There appears to be a discrepency when reading ModifiedDateTimeUtc and CreationTimeUtc // from FileSystemInfo objects. The Ticks value is being rounded to the nearest 10000 ticks, causing // some directories to appear to be modified. For now, we will set the threshold for an item being // changed to 10ms const long Epsilon = TicksPerMillisecond * 10; FileSystemFolder fileSystemItem = adapterItem as FileSystemFolder; if (fileSystemItem == null) { throw new ArgumentException("The adapter item is not of the correct type.", nameof(adapterItem)); } result = new EntryUpdateResult(); if (Math.Abs(childEntry.ModifiedDateTimeUtc.Ticks - fileSystemItem.FileSystemInfo.LastWriteTimeUtc.Ticks) > Epsilon) { result.ChangeFlags |= SyncEntryChangedFlags.ModifiedTimestamp; result.ModifiedTime = fileSystemItem.FileSystemInfo.LastWriteTimeUtc; } if (Math.Abs(childEntry.CreationDateTimeUtc.Ticks - fileSystemItem.FileSystemInfo.CreationTimeUtc.Ticks) > Epsilon) { result.ChangeFlags |= SyncEntryChangedFlags.CreatedTimestamp; result.CreationTime = fileSystemItem.FileSystemInfo.CreationTimeUtc; } FileInfo fileInfo = fileSystemItem.FileSystemInfo as FileInfo; SyncEntryType fileType = SyncEntryType.Directory; if (fileInfo != null) { fileType = SyncEntryType.File; if (fileInfo.Length != childEntry.GetSize(this.Relationship, SyncEntryPropertyLocation.Source)) { result.ChangeFlags |= SyncEntryChangedFlags.FileSize; } } if (!string.Equals(fileSystemItem.Name, childEntry.Name, StringComparison.Ordinal)) { result.ChangeFlags |= SyncEntryChangedFlags.Renamed; } // It is possible that a directory was created over a file that previously existed (with the same name). To // handle this, we need to check if the type changed. if (childEntry.Type != fileType) { // TODO: Handle this throw new NotImplementedException(); } return(result.ChangeFlags != SyncEntryChangedFlags.None); }
public override byte[] GetItemHash(HashType hashType, IAdapterItem adapterItem) { if (hashType == HashType.SHA1) { return(adapterItem.Sha1Hash); } return(null); }
public override SyncEntry CreateSyncEntryForAdapterItem(IAdapterItem item, SyncEntry parentEntry) { GoogleDriveAdapterItem adapterItem = item as GoogleDriveAdapterItem; Pre.Assert(adapterItem != null, "adapterItem != null"); Pre.Assert(adapterItem.Item != null, "adapterItem.Item != null"); return(this.CreateEntry(adapterItem.Item, parentEntry)); }
public override byte[] GetItemHash(HashType hashType, IAdapterItem adapterItem) { if (hashType == HashType.MD5) { return(adapterItem.Md5Hash); } return(null); }
public override byte[] GetItemHash(HashType hashType, IAdapterItem adapterItem) { // SHA1 is the only hash supported by Blackblaze if (hashType == HashType.SHA1) { return(adapterItem.Sha1Hash); } return(null); }
public override SyncEntry CreateSyncEntryForAdapterItem(IAdapterItem item, SyncEntry parentEntry) { FileSystemFolder fileSystemItem = item as FileSystemFolder; if (fileSystemItem == null) { throw new InvalidOperationException("Item type is incorrect."); } return(this.CreateEntry(fileSystemItem.FileSystemInfo, parentEntry)); }
public override SyncEntry CreateSyncEntryForAdapterItem(IAdapterItem item, SyncEntry parentEntry) { OneDriveAdapterItem oneDriveAdapterItem = item as OneDriveAdapterItem; Pre.Assert(oneDriveAdapterItem != null, "oneDriveAdapterItem != null"); Pre.Assert(oneDriveAdapterItem.Item != null, "oneDriveAdapterItem.Item != null"); // Is this always true? Pre.Assert(parentEntry != null, "parentEntry != null"); return(this.CreateEntry(oneDriveAdapterItem.Item, parentEntry)); }
public override SyncEntry CreateSyncEntryForAdapterItem(IAdapterItem item, SyncEntry parentEntry) { AzureStorageAdapterItem adapterItem = (AzureStorageAdapterItem)item; SyncEntry entry = new SyncEntry { Name = item.Name, AdapterEntries = new List <SyncEntryAdapterData>(), CreationDateTimeUtc = adapterItem.CreationTimeUtc, ModifiedDateTimeUtc = adapterItem.ModifiedTimeUtc }; if (parentEntry != null) { entry.ParentEntry = parentEntry; entry.ParentId = parentEntry.Id; } entry.AdapterEntries.Add(new SyncEntryAdapterData() { AdapterId = this.Configuration.Id, SyncEntry = entry, AdapterEntryId = item.UniqueId }); if (adapterItem.ItemType == SyncAdapterItemType.File) { entry.Type = SyncEntryType.File; entry.SetSize(this.Relationship, SyncEntryPropertyLocation.Source, adapterItem.Size); // TODO Set MD5 hash? } else { entry.Type = SyncEntryType.Directory; } if (entry.Type == SyncEntryType.Undefined) { throw new Exception(string.Format("Unknown type for Item {0} ({1})", item.Name, item.UniqueId)); } // TODO: FIX THIS //if (this.Relationship.Configuration.SyncTimestamps) //{ // entry.CreationDateTimeUtc = info.CreationTimeUtc; // entry.ModifiedDateTimeUtc = info.LastWriteTimeUtc; //} entry.EntryLastUpdatedDateTimeUtc = DateTime.UtcNow; return(entry); }
protected virtual string GetPath() { IAdapterItem folder = this; List <string> resultList = new List <string>(); while (folder != null) { resultList.Add(folder.Name); folder = folder.Parent; } resultList.Reverse(); return(PathUtility.Join(this.Adapter.PathSeparator, resultList)); }
public GoogleDriveAdapterItem(Item item, IAdapterItem parent, AdapterBase adapter) : base( item.Name, parent, adapter, GetItemType(item), item.Id, item.Size, item.CreatedTime, item.ModifiedTime) { this.Item = item; }
public FolderViewModel(FolderBrowserViewModel browserViewModel, FolderViewModel parent, IAdapterItem folder) { this.browserViewModel = browserViewModel; this.Parent = parent; this.folder = folder; this.DisplayName = folder.Name; this.ErrorMessage = folder.ErrorMessage; if (string.IsNullOrWhiteSpace(this.ErrorMessage)) { this.SubFolders.Add(Placeholder); } this.IconSource = this.GetIconSource(false); }
public static FileSystemFolder Create(FileSystemInfo fileSystemInfo, IAdapterItem parent, AdapterBase adapter) { var itemType = fileSystemInfo.Attributes.HasFlag(FileAttributes.Directory) ? SyncAdapterItemType.Directory : SyncAdapterItemType.File; try { string uniqueId = GetUniqueIdForFileSystemInfo(fileSystemInfo); long size = 0; FileInfo fileInfo = fileSystemInfo as FileInfo; if (fileInfo != null) { size = fileInfo.Length; } return(new FileSystemFolder( fileSystemInfo.Name, parent, adapter, itemType, uniqueId, fileSystemInfo, size, fileSystemInfo.CreationTimeUtc, fileSystemInfo.LastWriteTimeUtc)); } catch (Exception exception) { Logger.Debug("Failed to generate FileSystemFolder for '{0}'. The error was: {1}", fileSystemInfo.Name, exception.Message); return(new FileSystemFolder( fileSystemInfo.Name, parent, adapter, itemType, null, fileSystemInfo, 0, DateTime.MinValue, DateTime.MinValue) { ErrorMessage = exception.Message }); } }
protected AdapterItem( string name, IAdapterItem parent, AdapterBase adapter, SyncAdapterItemType itemType, string uniqueId, long size, DateTime creationTimeUtc, DateTime modifiedTimeUtc) { this.Name = name; this.Parent = parent; this.Adapter = adapter; this.ItemType = itemType; this.UniqueId = uniqueId; this.Size = size; this.CreationTimeUtc = creationTimeUtc; this.ModifiedTimeUtc = modifiedTimeUtc; }
public BackblazeB2AdapterItem( string name, IAdapterItem parent, AdapterBase adapter, SyncAdapterItemType itemType, string uniqueId, long size, DateTime creationTimeUtc, DateTime modifiedTimeUtc) : base( name, parent, adapter, itemType, uniqueId, size, creationTimeUtc, modifiedTimeUtc) { }
public override IEnumerable <IAdapterItem> GetAdapterItems(IAdapterItem folder) { if (folder == null) { Item root = this.googleDriveClient.GetItemById("root").Result; return(new List <IAdapterItem>() { new GoogleDriveAdapterItem(root, null, this) }); } GoogleDriveAdapterItem adapterItem = folder as GoogleDriveAdapterItem; Pre.Assert(adapterItem != null, "adapterItem != null"); var items = this.googleDriveClient.GetChildItems(adapterItem).Result; IEnumerable <GoogleDriveAdapterItem> adapterItems = items.Select(i => new GoogleDriveAdapterItem(i, folder, this)); return(adapterItems); }
public override IEnumerable <IAdapterItem> GetAdapterItems(IAdapterItem folder) { if (folder == null) { Drive defaultDrive = this.oneDriveClient.GetDefaultDrive().Result; return(new List <OneDriveAdapterItem> { new OneDriveAdapterItem(defaultDrive, this) }); } OneDriveAdapterItem adapterItem = folder as OneDriveAdapterItem; Pre.Assert(adapterItem != null, "adapterItem != null"); IEnumerable <Item> items = this.oneDriveClient.GetChildItems(adapterItem).Result; IEnumerable <OneDriveAdapterItem> adapterItems = items.Select(i => new OneDriveAdapterItem(i, folder, this)); return(adapterItems); }
internal OneDriveAdapterItem(Item item, IAdapterItem parent, AdapterBase adapter) : base( item.Name, parent, adapter, GetItemType(item), item.Id, item.Size, item.CreatedDateTime.ToUniversalTime(), (item.LastModifiedDateTime ?? DateTime.MinValue).ToUniversalTime()) { this.Item = item; this.IsDeleted = item.Deleted != null; this.ParentUniqueId = item.ParentReference.Id; if (item.File?.Hashes?.Sha1Hash != null) { this.Sha1Hash = Convert.FromBase64String(item.File.Hashes.Sha1Hash); } }
public override byte[] GetItemHash(HashType hashType, IAdapterItem adapterItem) { if (hashType == HashType.SHA1) { if (adapterItem.Sha1Hash != null) { return(adapterItem.Sha1Hash); } FileSystemFolder item = (FileSystemFolder)adapterItem; string newPath = string.Join("\\", item.FullName.Split('\\').Skip(1)); string fullPath = Path.Combine(this.Config.RootDirectory, newPath); using (SHA1Cng sha1 = new SHA1Cng()) using (var fileStream = File.OpenRead(fullPath)) { return(sha1.ComputeHash(fileStream)); } } if (hashType == HashType.MD5) { if (adapterItem.Md5Hash != null) { return(adapterItem.Md5Hash); } FileSystemFolder item = (FileSystemFolder)adapterItem; string newPath = string.Join("\\", item.FullName.Split('\\').Skip(1)); string fullPath = Path.Combine(this.Config.RootDirectory, newPath); using (MD5Cng md5 = new MD5Cng()) using (var fileStream = File.OpenRead(fullPath)) { return(md5.ComputeHash(fileStream)); } } throw new NotImplementedException("Unknown hash type"); }
public override IEnumerable <IAdapterItem> GetAdapterItems(IAdapterItem folder) { BackblazeB2AdapterItem adapterItem = folder as BackblazeB2AdapterItem; Pre.Assert(adapterItem != null, "adapterItem != null"); string prefix = string.Empty; if (!adapterItem.IsBucket) { prefix = adapterItem.FullName + "/"; } ConfiguredTaskAwaitable <IList <File> > filesTask = this.backblazeClient.ListFileNamesAsync( this.TypedConfiguration.BucketId, prefix, "") .ConfigureAwait(false); IList <File> result = filesTask.GetAwaiter().GetResult(); List <BackblazeB2AdapterItem> childItems = new List <BackblazeB2AdapterItem>(); foreach (File file in result) { childItems.Add( new BackblazeB2AdapterItem( file.FullName.Split('/').Last(), folder, this, file.IsFileType ? SyncAdapterItemType.File : SyncAdapterItemType.Directory, file.FileId, file.ContentLength, file.UploadTimestamp, file.FileInfo?.LastModified ?? file.UploadTimestamp)); } return(childItems); }
/// <summary> /// Get the <see cref="FileSystemFolder"/> items that are children to the provided /// <see cref="FileSystemFolder"/>. /// </summary> /// <param name="folder">The parent folder</param> /// <returns>The list of child items under the parent folder.</returns> /// <remarks> /// An errors encountered when querying for the list of child should be thrown for the /// caller to handle. However, any errors related to querying the children themselves /// should be caught and returned as error information for that child (the original /// call should not fail in this case). /// </remarks> public override IEnumerable <IAdapterItem> GetAdapterItems(IAdapterItem folder) { // If folder is null, return the list of top-level folders on the computer (aka drives). if (folder == null) { DriveInfo[] allDrives = DriveInfo.GetDrives(); List <IAdapterItem> folders = new List <IAdapterItem>(); foreach (DriveInfo driveInfo in allDrives) { try { folders.Add(FileSystemFolder.Create(driveInfo.RootDirectory, this, true)); } catch (Exception exception) { Logger.Info( "Failed to enumerate drive {0} ({1}). The error was: {2}", driveInfo.Name, driveInfo.DriveType, exception.Message.Trim()); } } return(folders); } FileSystemFolder fileSystemFolder = folder as FileSystemFolder; if (fileSystemFolder == null) { throw new InvalidOperationException("folder item is not a FileSystemFolder"); } if (fileSystemFolder.ItemType != SyncAdapterItemType.Directory) { throw new InvalidOperationException("Invalid FileSystemFolder type"); } return(this.GetItemsFromDirectory((DirectoryInfo)fileSystemFolder.FileSystemInfo, folder)); }
private FileSystemFolder( string name, IAdapterItem parent, AdapterBase adapter, SyncAdapterItemType itemType, string uniqueId, FileSystemInfo fileSystemInfo, long size, DateTime creationTimeUtc, DateTime modifiedTimeUtc) : base( name, parent, adapter, itemType, uniqueId, size, creationTimeUtc, modifiedTimeUtc) { this.FileSystemInfo = fileSystemInfo; }
public override bool IsEntryUpdated(SyncEntry childEntry, IAdapterItem adapterItem, out EntryUpdateResult result) { const long TicksPerMillisecond = 10000; const long Epsilon = TicksPerMillisecond * 2; OneDriveAdapterItem item = adapterItem as OneDriveAdapterItem; if (item == null) { throw new ArgumentException("The adapter item is not of the correct type.", nameof(adapterItem)); } result = new EntryUpdateResult(); if (item.Item.LastModifiedDateTime != null && Math.Abs(childEntry.ModifiedDateTimeUtc.Ticks - item.Item.LastModifiedDateTime.Value.Ticks) > Epsilon) { result.ChangeFlags |= SyncEntryChangedFlags.ModifiedTimestamp; result.ModifiedTime = item.Item.LastModifiedDateTime.Value; } if (Math.Abs(childEntry.CreationDateTimeUtc.Ticks - item.Item.CreatedDateTime.Ticks) > Epsilon) { result.ChangeFlags |= SyncEntryChangedFlags.CreatedTimestamp; result.CreationTime = item.Item.CreatedDateTime; } SyncEntryType fileType = SyncEntryType.Directory; if (item.ItemType == SyncAdapterItemType.File) { fileType = SyncEntryType.File; if (item.Item.Size != childEntry.GetSize(this.Relationship, SyncEntryPropertyLocation.Source)) { // Before reporting the size of the item as changed, check the SHA1 hash. If the hash is unchanged, then the // file is the same as it was before. This is due to a bug in OneDrive where the reported size includes // thumbnails for the file. See https://github.com/OneDrive/onedrive-api-docs/issues/123 if (item.Item.File.Hashes != null) { byte[] sha1Hash = HexToBytes(item.Item.File.Hashes.Sha1Hash); if (!sha1Hash.SequenceEqual(childEntry.GetSha1Hash(this.Relationship, SyncEntryPropertyLocation.Source))) { result.ChangeFlags |= SyncEntryChangedFlags.FileSize; result.ChangeFlags |= SyncEntryChangedFlags.Sha1Hash; } } } } if (!string.Equals(item.Item.Name, childEntry.Name, StringComparison.Ordinal)) { result.ChangeFlags |= SyncEntryChangedFlags.Renamed; } // It is possible that a directory was created over a file that previously existed (with the same name). To // handle this, we need to check if the type changed. if (childEntry.Type != fileType) { // TODO: Handle this throw new NotImplementedException(); } return(result.ChangeFlags != SyncEntryChangedFlags.None); }
private IEnumerable <IAdapterItem> GetItemsFromDirectory(DirectoryInfo directory, IAdapterItem parent) { return (directory.GetFileSystemInfos() .Where(d => SuppressedDirectories.Contains(d.Name, StringComparer.OrdinalIgnoreCase) == false) .Select(info => FileSystemFolder.Create(info, parent, this))); }
public override byte[] GetItemHash(HashType hashType, IAdapterItem adapterItem) { throw new NotImplementedException(); }
public override SyncEntry CreateSyncEntryForAdapterItem(IAdapterItem item, SyncEntry parentEntry) { throw new NotImplementedException(); }
public override bool IsEntryUpdated(SyncEntry childEntry, IAdapterItem adapterItem, out EntryUpdateResult result) { throw new NotImplementedException(); }
public override IEnumerable <IAdapterItem> GetAdapterItems(IAdapterItem folder) { throw new NotImplementedException(); }
public override IEnumerable <IAdapterItem> GetAdapterItems(IAdapterItem folder) { // When querying items in the root of the container, folder will have a name of '{containerName}', and when // querying items in a folder other than the root, folder will have a have a name of // '{containerName}/{folder}'. We will need to reformat this in order to property query storage. string prefix = null; // Start by triming off the container name from the front of the folder name string relName = folder.FullName.Substring(this.TypedConfiguration.ContainerName.Length); // If the folder name is empty, then we are querying the container, so leave the prefix empty. if (!string.IsNullOrWhiteSpace(relName)) { prefix = relName; // Add a '/' character to the end of the folder name if needed if (!prefix.EndsWith(this.PathSeparator)) { prefix += this.PathSeparator; } // Ensure that the folder name does NOT start with a '/'. prefix = prefix.TrimStart('/'); } ConfiguredTaskAwaitable <IList <ContainerItem> > listBlobsTask = this.storageClient.ListBlobsAsync( this.TypedConfiguration.ContainerName, this.PathSeparator, prefix) .ConfigureAwait(false); IList <ContainerItem> result = listBlobsTask.GetAwaiter().GetResult(); foreach (ContainerItem item in result) { // The item name returned by storage has the prefix at the beginning of the name, which // we will need to trim off string itemName = prefix != null?item.Name.Substring(prefix.Length) : item.Name; string fullPath = string.Format("{0}/{1}", folder.FullName, itemName); string computedId = GetUniqueIdForFile(fullPath); BlobPrefix blobPrefix = item as BlobPrefix; if (blobPrefix != null) { // Azure returns the blob prefix with a '/' character on the end. We need to trim this off // prior to returning it to the caller. yield return(new AzureStorageAdapterItem( itemName.TrimEnd('/'), folder, this, SyncAdapterItemType.Directory, computedId, 0, DateTime.Now, DateTime.Now)); continue; } Blob blob = item as Blob; Pre.Assert(blob != null, "blob != null"); yield return(new AzureStorageAdapterItem( itemName, folder, this, SyncAdapterItemType.File, computedId, blob.Length, blob.Created, blob.LastModified)); } }