Search code examples
c#dropboxwebclientunrarsharpcompress

Dropbox folder download issue (c#)


I'm automaticly downloading a whole folder from my Dropbox - storage(?), via the weblink eg:https://www.dropbox.com/sh/bunchOfLetters/somthnsomthn?dl=1 with just a basic webclient:

using (WebClient wc = new WebClient())
{
     wc.DownloadFile(new Uri(uri), _basePath + localPath);
}

The folder naturaly comes as a .rar file (due to Dropbox's download system), and if i try to open the file manualy (via Winrar) there is no problem at all. Now comes the problem.... if i try to use any kind of automated libary (like unrar or SharpCompress) it always gives my a 'Corupted Header' as if the download wouldnt have gotten everythng or the file just broke ..but still opening it with Winrar works just fine.

If anyone has an idea how and why; i would be greatfull to hear your thoughts.

Edit:

here is the function i use for SharpCompress:

public static bool ExtractToFolder(string extractionPackage, string outputPath)
        {
            if (extractionPackage == null) throw new ArgumentNullException(nameof(extractionPackage));
            if (outputPath == null) throw new ArgumentNullException(nameof(outputPath));
            if (string.IsNullOrEmpty(extractionPackage))
                throw new ArgumentException("Argument is null or empty", nameof(extractionPackage));
            if (string.IsNullOrEmpty(outputPath))
                throw new ArgumentException("Argument is null or empty", nameof(outputPath));
            if (!extractionPackage.EndsWith(".rar")) throw new InvalidDataException("not a .rar File");
            Directory.CreateDirectory(outputPath);

            try
            {
                using (Stream stream = File.OpenRead(extractionPackage))
                using (RarReader reader = RarReader.Open(stream))
                {
                    while (reader.MoveToNextEntry())
                    {
                        reader.WriteEntryToDirectory(outputPath, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
                    }
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

and if someone is interested in the unrar one: ..i know its not well done but it still works for normal files...just not Dropbox ones

namespace Cryptus.Rar
{
/// <summary>
/// just for compatibility purposes, use <see cref="SharpCompress"/>
/// </summary>
public class Unrar
{
    public enum RarOperations
    {
        OP_EXTRACT = 0,
        OP_TEST = 1,
        OP_LIST = 2
    }

    public const int ERAR_END_ARCHIVE = 10;
    public const int ERAR_NO_MEMORY = 11;
    public const int ERAR_BAD_DATA = 12;
    public const int ERAR_BAD_ARCHIVE = 13;
    public const int ERAR_UNKNOWN_FORMAT = 14;
    public const int ERAR_EOPEN = 15;
    public const int ERAR_ECREATE = 16;
    public const int ERAR_ECLOSE = 17;
    public const int ERAR_EREAD = 18;
    public const int ERAR_EWRITE = 19;
    public const int ERAR_SMALL_BUF = 20;

    public const int RAR_OM_LIST = 0;
    public const int RAR_OM_EXTRACT = 1;

    public const int RAR_SKIP = 0;
    public const int RAR_TEST = 1;
    public const int RAR_EXTRACT = 2;

    public const int RAR_VOL_ASK = 0;
    public const int RAR_VOL_NOTIFY = 1;

    [DllImport("unrar.dll")]
    public static extern IntPtr RAROpenArchive(ref RAROpenArchiveData ArchiveData);

    [DllImport("unrar.dll")]
    public static extern int RARCloseArchive(IntPtr hArcData);

    [DllImport("unrar.dll")]
    public static extern int RARReadHeader(IntPtr hArcData, ref RARHeaderData HeaderData);

    [DllImport("unrar.dll")]
    public static extern IntPtr RAROpenArchiveEx(ref RAROpenArchiveDataEx ArchiveData);

    [DllImport("unrar.dll")]
    public static extern int RARReadHeaderEx(IntPtr hArcData, ref RARHeaderDataEx HeaderData);

    [DllImport("unrar.dll")]
    public static extern int RARProcessFile(IntPtr hArcData, int Operation, string DestPath, string DestName);

    [DllImport("unrar.dll")]
    public static extern int RARGetDllVersion();

    [DllImport("user32.dll")]
    private static extern bool CharToOem(string lpszSrc, [Out] StringBuilder lpszDst);

    /// <summary>
    ///     opens an arcive and unloads its content to destDolder
    /// </summary>
    /// <param name="strFileName">input .rar File</param>
    /// <param name="destFolder">destination Folder</param>
    public void UnloadArchieve(string strFileName, string destFolder)
    {
        IntPtr lHandle;
        int iStatus;
        RAROpenArchiveData uRAR = new RAROpenArchiveData();
        RARHeaderData uHeader = new RARHeaderData();

        uRAR.ArcName = strFileName + char.MinValue;
        uRAR.OpenMode = RAR_OM_EXTRACT;
        uRAR.CmtBuf = null;

        string ExtractDir = Path.GetDirectoryName(strFileName);
        StringBuilder sbDir = new StringBuilder();
        CharToOem(destFolder, sbDir);

        lHandle = RAROpenArchive(ref uRAR);
        if (uRAR.OpenResult != 0)
            Console.Write("Unable to open the Archieve!!!");
        while (RARReadHeader(lHandle, ref uHeader) == 0)
        {
            int result = RARProcessFile(lHandle, 2, sbDir.ToString(), null);
            if (0 != result)
                Console.Write("Unable to open the Archieve!!!");
        }


        iStatus = RARCloseArchive(lHandle);
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RARHeaderData
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string ArcName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string FileName;
        public uint Flags;
        public uint PackSize;
        public uint UnpSize;
        public uint HostOS;
        public uint FileCRC;
        public uint FileTime;
        public uint UnpVer;
        public uint Method;
        public uint FileAttr;
        public string CmtBuf;
        public uint CmtBufSize;
        public uint CmtSize;
        public uint CmtState;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RAROpenArchiveData
    {
        public string ArcName;
        public uint OpenMode;
        public uint OpenResult;
        public string CmtBuf;
        public uint CmtBufSize;
        public uint CmtSize;
        public uint CmtState;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RAROpenArchiveDataEx
    {
        public string ArcName;
        public string ArcNameW;
        public uint OpenMode;
        public uint OpenResult;
        public string CmtBuf;
        public uint CmtBufSize;
        public uint CmtSize;
        public uint CmtState;
        public uint Flags;
        public uint Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RARHeaderDataEx
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string ArcName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string FileName;
        public string FileNameW;
        public uint Flags;
        public uint PackSize;
        public uint PackSizeHigh;
        public uint UnpSize;
        public uint UnpSizeHigh;
        public uint HostOS;
        public uint FileCRC;
        public uint FileTime;
        public uint UnpVer;
        public uint Method;
        public uint FileAttr;
        public string CmtBuf;
        public uint CmtBufSize;
        public uint CmtSize;
        public uint CmtState;
        public uint Reserved;
    }
}

Solution

  • Ok so it seems that @smarx was right with his comment! Its a bit strange, but Dropbox generates .rar files which contain not a rar, but a zip header. This is no problem for any form of automatic detection of the header format, but if you use a rar extraction method (which should be used for .rar files..) it wont work.