Search code examples
c#system.io.compression

Zip Windows 10 Documents folder without including reparse points using System.IO.Compression


I'm writing a simple desktop application to copy files from one PC to another. Having trouble with the Windows 10 reparse points, specifically My Music. I thought was going to get away with one simple line of code:

ZipFile.CreateFromDirectory(documentsFolder, docSavePath + @"\Documents.zip", CompressionLevel.Optimal, false);

But not so, it crashes on the My Music folder. I've also tried a bunch of different ways of doing this, all with the same result - access denied. Can copying and/or zipping the Documents folder really be this hard? I doubt it, I'm just missing something. I tried elevating privileges and that didn't work, either. Anyone have an example of how to do this?


Solution

  • I was able figure out how to check for the ReparsePoint attribute, which was relatively easy, but then had to piece together how to loop through all the files and add them to the ZipArchive. The credit for the RecurseDirectory goes to this answer.

    Then I added in what I learned about the reparse file attributes.

        private void documentBackup(string docSavePath)
        {
            if (File.Exists(docSavePath + @"\Documents.zip")) File.Delete(docSavePath + @"\Documents.zip");
            using (ZipArchive docZip = ZipFile.Open(docSavePath + "\\Documents.zip", ZipArchiveMode.Create))
            {
                foreach (FileInfo goodFile in RecurseDirectory(documentsFolder))
                {
                   var destination = Path.Combine(goodFile.DirectoryName, goodFile.Name).Substring(documentsFolder.ToString().Length + 1);
                   docZip.CreateEntryFromFile(Path.Combine(goodFile.Directory.ToString(), goodFile.Name), destination);                    
                }
            }
        }
    
    
        public IEnumerable<FileInfo> RecurseDirectory(string path, List<FileInfo> currentData = null)
        {
            if (currentData == null)
                currentData = new List<FileInfo>();
    
            var directory = new DirectoryInfo(path);
    
            foreach (var file in directory.GetFiles())
                currentData.Add(file);
    
            foreach (var d in directory.GetDirectories())
            {
                if ((d.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
                {
                    continue;
                }
                else
                {
                    RecurseDirectory(d.FullName, currentData);
                }
            }
    
            return currentData;
        }
    

    It takes longer than I'd like to run - but after looking at this dang problem for days I'm just happy it works!