예제 #1
0
        private void SetTotalsTexts()
        {
            ArchiveSizeText = Properties.Resources.TotalArchiveSizeText +
                              LongToSizeString.ConvertToString((double)this._archiveSize) + ", ";

            this.TotalFilesToArchiveText = this._archiveInfo.Count +
                                           (this._archiveInfo.Count == 1 ? " file. " : " files. ");

            if (_excludedFiles.Count > 0)
            {
                this.TotalFilesToArchiveText = this.TotalFilesToArchiveText.Replace('.', ',');
                this.TotalFilesToExcludeText = this._excludedFiles.Count +
                                               (this._excludedFiles.Count == 1 ? " file" : " files") +
                                               " will not be uploaded.";
            }
        }
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double size = System.Convert.ToDouble(value);

            return(LongToSizeString.ConvertToString(size));
        }
예제 #3
0
        /// <summary>
        /// Prepare the ArchiveFileInfo list needed for this archive. This method scans for all files
        /// to be included in the archive and prepares their keynames, file paths and base prefixes.
        /// If the user selection doesn't include any files or if the user selection has a total size
        /// more than the remaining free Deepfreeze Storage, this method throws an exception.
        /// </summary>
        /// <param name="paths"></param>
        /// <returns></returns>
        private async Task PrepareArchivePathsAndSizeAsync(IEnumerable <string> paths, SelectionMode selectionMode)
        {
            // Clear list with archive files info.
            this._archiveInfo.Clear();
            // Clear errors
            ErrorSelectingFiles = null;

            IsReset         = false;
            IsBusy          = true;
            BusyMessageText = Properties.Resources.CalculatingTotalArchiveSizeText;

            try
            {
                long size = 0;

                // split paths to files and folders.
                var  files       = new List <string>();
                var  directories = new List <string>();
                bool isDirectoryRestricted;

                foreach (var p in paths)
                {
                    FileAttributes attr = File.GetAttributes(p);

                    // if the selected folder is indeed a directory and not a junction point
                    // add it for archiving.
                    if ((attr & FileAttributes.Directory) == FileAttributes.Directory &&
                        (attr & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint)
                    {
                        isDirectoryRestricted = CheckIfDirectoryIsRestricted(p);

                        if (!isDirectoryRestricted)
                        {
                            if (directories.Contains(p))
                            {
                                continue;
                            }

                            directories.Add(p);
                        }
                        else
                        {
                            this._excludedFiles.Add(p, Enumerations.FileCategory.RestrictedDirectory);
                        }
                    }

                    else
                    {
                        if (files.Contains(p))
                        {
                            continue;
                        }

                        files.Add(p);
                    }
                }

                // If the initial selection includes just one folder,
                // then set the archive's title to its name. (step 1)
                if (directories.Count == 1 && files.Count == 0)
                {
                    this.ArchiveTitle = new DirectoryInfo(directories.First()).Name;
                }

                // The directories list may contain subdirectories of some of its elements.
                // We need to remove them because we need to add them later on in the subDirectories dictionary
                // so we can get the correct grandparent value.
                var dirsToRemove = new List <string>();
                foreach (var dir in directories)
                {
                    var dirInfo = new DirectoryInfo(dir);
                    var subDirs = dirInfo.GetDirectories().Select(x => x.FullName);

                    foreach (var sub in subDirs)
                    {
                        if (directories.Contains(sub) && !dirsToRemove.Contains(sub))
                        {
                            dirsToRemove.Add(sub);
                        }
                    }

                    dirInfo = null;
                    subDirs = null;
                }

                foreach (var dirToRemove in dirsToRemove)
                {
                    directories.Remove(dirToRemove);
                }

                dirsToRemove.Clear();
                dirsToRemove = null;

                var subDirectories = new Dictionary <string, string>();
                // Okay now find all the subdirectories to include respecting restrictions.
                foreach (var dir in directories)
                {
                    var subsWithoutJunctions = await IgnoreJunctionsUnderPath(dir);

                    foreach (var sub in subsWithoutJunctions.OrderBy(x => x))
                    {
                        if (subDirectories.Keys.Contains(sub))
                        {
                            continue;
                        }

                        // for each subdirectory to include we create a key with the dir's parent as a value.
                        // we will need this to find the prefix to remove for the key names.
                        subDirectories.Add(sub, Directory.GetParent(dir).FullName + "\\");
                    }

                    subsWithoutJunctions.Clear();
                    subsWithoutJunctions = null;
                }

                // add all found subdirectories in the directories list
                // which will be scanned for files at the top level for each directory.
                if (subDirectories.Count > 0)
                {
                    foreach (var sub in subDirectories.Keys)
                    {
                        if (directories.Contains(sub))
                        {
                            continue;
                        }

                        directories.Add(sub);
                    }
                }

                // REMARK
                // We want to handle directories first. The main reason behind this is that in search results
                // one file may be contained more than one time. If a descendant directory of this file is contained
                // in the results, then we want the file to be included with a key name indicating this hierarchy.
                // The "clean" selection of the file from the search results, will have to be ignored.
                //
                // Example: C:\test\test.txt
                // Searching for 'test' will return two results, the test folder and the test.txt file.
                // Selecting both, will add the same path two times. But the folder result will get included
                // first in the _archiveInfo list, and when the code tries to add the 'clean
                // for all directories selected for archiving, add all files in _archiveFileInfo.

                foreach (var dir in directories)
                {
                    // Fetch all files in directory, only those on the top level.
                    var dirFiles = Directory.GetFiles(dir, "*", SearchOption.TopDirectoryOnly);

                    if (dirFiles.Count() > 0)
                    {
                        await Task.Run(() =>
                        {
                            foreach (var f in dirFiles)
                            {
                                if (this._archiveInfo.Select(x => x.FilePath).Contains(f))
                                {
                                    continue;
                                }

                                var fileCategory = Utilities.CheckFileApiRestrictions(f);

                                if (fileCategory != Enumerations.FileCategory.Normal)
                                {
                                    this.HasInvalidFiles = true;
                                    this._excludedFiles.Add(f, fileCategory);
                                    continue;
                                }

                                var info = new FileInfo(f);

                                // Check that the archive size does not exceed the maximum allowed file size.
                                // S3 supports multipart uploads with up to 10000 parts and 5 TB max size.
                                // Since DF supports part size of 5 MB, archive size must not exceed 5 MB * 10000
                                if (info.Length > MAX_ALLOWED_FILE_SIZE)
                                {
                                    throw new Exception("The file " + f + " exceeds the maximum allowed archive size of " +
                                                        LongToSizeString.ConvertToString((double)MAX_ALLOWED_FILE_SIZE) + ".");
                                }

                                var baseToRemove = (!subDirectories.Keys.Contains(dir))
                                    ? Directory.GetParent(dir).FullName + "\\"
                                    : subDirectories[dir];

                                var archiveFileInfo = new ArchiveFileInfo()
                                {
                                    FileName     = info.Name,
                                    KeyName      = f.Replace(baseToRemove, "").Replace('\\', '/'),
                                    FilePath     = f,
                                    Size         = info.Length,
                                    LastModified = info.LastWriteTimeUtc,
                                    MD5          = Utilities.GetMD5Hash(f),
                                    IsUploaded   = false
                                };

                                this._archiveInfo.Add(archiveFileInfo);

                                size += archiveFileInfo.Size;
                            }
                        }
                                       );
                    }
                }

                // Remove the subdirectories from the directories list, so only the initially selected
                // directory(ies) is left. We need to keep clean the directories list, so the code below
                // suggesting an upload name gets the corrent amount of initially selected directories.
                foreach (string subDir in subDirectories.Values)
                {
                    directories.Remove(subDir);
                }

                subDirectories.Clear();
                subDirectories = null;

                // do the same for each individually selected files.
                foreach (var f in files)
                {
                    if (this._archiveInfo.Select(x => x.FilePath).Contains(f))
                    {
                        continue;
                    }

                    var fileCategory = Utilities.CheckFileApiRestrictions(f);

                    if (fileCategory != Enumerations.FileCategory.Normal)
                    {
                        this.HasInvalidFiles = true;
                        this._excludedFiles.Add(f, fileCategory);
                        continue;
                    }

                    var info = new FileInfo(f);

                    // Check that the archive size does not exceed the maximum allowed file size.
                    // S3 supports multipart uploads with up to 10000 parts and 5 TB max size.
                    // Since DF supports part size of 5 MB, archive size must not exceed 5 MB * 10000
                    if (info.Length > MAX_ALLOWED_FILE_SIZE)
                    {
                        throw new Exception("The file " + info + " exceeds the maximum allowed archive size of " +
                                            LongToSizeString.ConvertToString((double)MAX_ALLOWED_FILE_SIZE) + ".");
                    }

                    var archiveFileInfo = new ArchiveFileInfo()
                    {
                        FileName     = info.Name,
                        KeyName      = info.Name,
                        FilePath     = f,
                        Size         = info.Length,
                        LastModified = info.LastWriteTimeUtc,
                        MD5          = Utilities.GetMD5Hash(f),
                        IsUploaded   = false
                    };

                    this._archiveInfo.Add(archiveFileInfo);

                    size += archiveFileInfo.Size;
                }

                var result = await ShowRestrictedWarningMessage();

                // if the user clicked cancel in the warning message box because of a restricted folder
                // then cancel the new archive archive creation and reset the ViewModel.
                if (result == MessageBoxResult.Cancel)
                {
                    this._isUserCancel = true;
                    throw new Exception("User cancelled because of a restricted folder");
                }

                if (this._archiveInfo.Count == 0)
                {
                    throw new Exception("Your selection doesn't contain any files. Nothing to upload.");
                }

                // check that the archive size fits in user's DF storage.
                if (size > (this._deepfreezeClient.Settings.ActiveUser.Quota.Size - this._deepfreezeClient.Settings.ActiveUser.Quota.Used))
                {
                    // get the userviewmodel to refresh stats.
                    // we could use the messaging service, but we actually need to wait until the stats are refreshed
                    // before checking the sizes again. Sending a message is a fire and forget style, so that couldn't work here.
                    var userVM = IoC.Get <IUserViewModel>() as UserViewModel;
                    await userVM.RefreshUser();

                    if (size > (this._deepfreezeClient.Settings.ActiveUser.Quota.Size - this._deepfreezeClient.Settings.ActiveUser.Quota.Used))
                    {
                        throw new Exception(Properties.Resources.ErrorNotEnoughSpaceGenericText);
                    }
                }

                // suggest an archive title step 2
                // if the title wasn't set in the previous step, suggest one.
                if (String.IsNullOrEmpty(this.ArchiveTitle))
                {
                    if (this._archiveInfo.Count == 1)
                    {
                        this.ArchiveTitle = this._archiveInfo.First().FileName;
                    }
                    else
                    {
                        this.ArchiveTitle = "upload-" + String.Format("{0:yyyy-MM-dd}", DateTime.Now);
                    }
                }

                this._archiveSize = size;

                this.SetTotalsTexts();

                this.HasChosenFiles = true;

                return;
            }
            catch (Exception e)
            {
                _log.Error(Utilities.GetCallerName() + " threw " + e.GetType().ToString() + " with message \"" + e.Message + "\"", e);

                if (!this._isUserCancel)
                {
                    this.ErrorSelectingFiles = Properties.Resources.ErrorAddingFilesGenericText;
                }

                if (e is UnauthorizedAccessException ||
                    e is DirectoryNotFoundException ||
                    e is FileNotFoundException)
                {
                    this.ErrorSelectingFiles += " " + e.Message;
                }
                else
                {
                    if (e.Message == Properties.Resources.ErrorNotEnoughSpaceGenericText)
                    {
                        this.ErrorSelectingFiles = e.Message;
                    }

                    // if the selection includes no files and a restricted folder WASN'T in the selection
                    // then show the no files to upload error message.
                    if (this._archiveInfo.Count == 0 && !this._isUserCancel)
                    {
                        this.ErrorSelectingFiles = e.Message;
                    }
                }

                this.IsReset = true;

                if (this._isUserCancel)
                {
                    this.Reset();
                }
            }
            finally
            {
                IsBusy = false;
            }
        }