Example #1
0
        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);
        }
Example #2
0
        public override byte[] GetItemHash(HashType hashType, IAdapterItem adapterItem)
        {
            if (hashType == HashType.SHA1)
            {
                return(adapterItem.Sha1Hash);
            }

            return(null);
        }
Example #3
0
        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));
        }
Example #4
0
        public override byte[] GetItemHash(HashType hashType, IAdapterItem adapterItem)
        {
            if (hashType == HashType.MD5)
            {
                return(adapterItem.Md5Hash);
            }

            return(null);
        }
Example #5
0
        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);
        }
Example #6
0
        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));
        }
Example #7
0
        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));
        }
Example #8
0
        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);
        }
Example #9
0
        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));
        }
Example #10
0
 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;
 }
Example #11
0
        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);
        }
Example #12
0
        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
                });
            }
        }
Example #13
0
 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;
 }
Example #14
0
 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)
 {
 }
Example #15
0
        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);
        }
Example #16
0
        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);
        }
Example #17
0
        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);
            }
        }
Example #18
0
        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");
        }
Example #19
0
        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);
        }
Example #20
0
        /// <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));
        }
Example #21
0
 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;
 }
Example #22
0
        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);
        }
Example #23
0
 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();
 }
Example #28
0
        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));
            }
        }