【问题标题】:c# - How can I extract a FAT Disk Image?c# - 如何提取 FAT 磁盘映像?
【发布时间】:2012-05-18 20:39:03
【问题描述】:

我实际上是在尝试使用 DiskUtils 提取胖磁盘映像,但我没有得到正确的文件名...

我得到 "\TURNER~3\TOPPER~1.P~1" 代替 "\TURNEROVER\TOPPERSHEATH.PPTX"

FatFileSystem FatImg = new FatFileSystem(MS); //MS = Fat Image MemoryStream
foreach(DiscDirectoryInfo Di in FatImg.Root.GetDirectories())
{
    foreach(DiscFileInfo Fi in Di.GetFiles())
    {
        Stream St = Fi.OpenRead(); // Correct Stream
        string FName = Fi.Name; //Wrong Name
    }
}

这是因为 DiscUtils 不支持 LFN [长文件名]...

所以我正在寻找一个完美的库来提取这些文件,然后我尝试自己制作一个......

有什么方法可以在没有文件名错误的情况下提取它 [也许通过 DiscUtils]...

【问题讨论】:

  • 你在某个地方有一个现有的 FAT 映像文件,我们可以玩吗?

标签: c# fat diskimage


【解决方案1】:

这里有一些修改可以添加到DiscUtils 以支持FAT LFNs:

首先,对Fat\Directory.cs文件进行这些更改,像这样(你需要添加_lfns变量,GetLfnChunk函数,并修改现有的LoadEntries函数以添加标有@987654327的行@下面):

internal Dictionary<string, string> _lfns = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

private static string GetLfnChunk(byte[] buffer)
{
    // see http://home.teleport.com/~brainy/lfn.htm
    // NOTE: we assume ordinals are ok here.
    char[] chars = new char[13];
    chars[0] = (char)(256 * buffer[2] + buffer[1]);
    chars[1] = (char)(256 * buffer[4] + buffer[3]);
    chars[2] = (char)(256 * buffer[6] + buffer[5]);
    chars[3] = (char)(256 * buffer[8] + buffer[7]);
    chars[4] = (char)(256 * buffer[10] + buffer[9]);

    chars[5] = (char)(256 * buffer[15] + buffer[14]);
    chars[6] = (char)(256 * buffer[17] + buffer[16]);
    chars[7] = (char)(256 * buffer[19] + buffer[18]);
    chars[8] = (char)(256 * buffer[21] + buffer[20]);
    chars[9] = (char)(256 * buffer[23] + buffer[22]);
    chars[10] = (char)(256 * buffer[25] + buffer[24]);

    chars[11] = (char)(256 * buffer[29] + buffer[28]);
    chars[12] = (char)(256 * buffer[31] + buffer[30]);
    string chunk = new string(chars);
    int zero = chunk.IndexOf('\0');
    return zero >= 0 ? chunk.Substring(0, zero) : chunk;
}

private void LoadEntries()
{
    _entries = new Dictionary<long, DirectoryEntry>();
    _freeEntries = new List<long>();

    _selfEntryLocation = -1;
    _parentEntryLocation = -1;

    string lfn = null;  //+++
    while (_dirStream.Position < _dirStream.Length)
    {
        long streamPos = _dirStream.Position;
        DirectoryEntry entry = new DirectoryEntry(_fileSystem.FatOptions, _dirStream);

        if (entry.Attributes == (FatAttributes.ReadOnly | FatAttributes.Hidden | FatAttributes.System | FatAttributes.VolumeId))
        {
            // Long File Name entry
            _dirStream.Position = streamPos;  //+++
            lfn = GetLfnChunk(Utilities.ReadFully(_dirStream, 32)) + lfn;  //+++
        }
        else if (entry.Name.IsDeleted())
        {
            // E5 = Free Entry
            _freeEntries.Add(streamPos);
            lfn = null; //+++
        }
        else if (entry.Name == FileName.SelfEntryName)
        {
            _selfEntry = entry;
            _selfEntryLocation = streamPos;
            lfn = null; //+++
        }
        else if (entry.Name == FileName.ParentEntryName)
        {
            _parentEntry = entry;
            _parentEntryLocation = streamPos;
            lfn = null; //+++
        }
        else if (entry.Name == FileName.Null)
        {
            // Free Entry, no more entries available
            _endOfEntries = streamPos;
            lfn = null; //+++
            break;
        }
        else
        {
            if (lfn != null) //+++
            { //+++
                _lfns.Add(entry.Name.GetDisplayName(_fileSystem.FatOptions.FileNameEncoding), lfn); //+++
            } //+++
            _entries.Add(streamPos, entry);
            lfn = null; //+++
        }
    }
}

其次,将这两个公共函数添加到Fat\FatFileSystem.cs 文件中。它们将成为查询 LFN 的新 API:

/// <summary>
/// Gets the long name of a given file.
/// </summary>
/// <param name="shortFullPath">The short full path to the file. Input path segments must be short names.</param>
/// <returns>The corresponding long file name.</returns>
public string GetLongFileName(string shortFullPath)
{
    if (shortFullPath == null)
        throw new ArgumentNullException("shortFullPath");

    string dirPath = Path.GetDirectoryName(shortFullPath);
    string fileName = Path.GetFileName(shortFullPath);
    Directory dir = GetDirectory(dirPath);
    if (dir == null)
        return fileName;

    string lfn;
    if (dir._lfns.TryGetValue(Path.GetFileName(shortFullPath), out lfn))
        return lfn;

    return fileName;
}

/// <summary>
/// Gets the long path to a given file.
/// </summary>
/// <param name="shortFullPath">The short full path to the file. Input path segments must be short names.</param>
/// <returns>The corresponding long file path to the file or null if not found.</returns>
public string GetLongFilePath(string shortFullPath)
{
    if (shortFullPath == null)
        throw new ArgumentNullException("shortFullPath");

    string path = null;
    string current = null;
    foreach (string segment in shortFullPath.Split(Path.DirectorySeparatorChar))
    {
        if (current == null)
        {
            current = segment;
            path = GetLongFileName(current);
        }
        else
        {
            current = Path.Combine(current, segment);
            path = Path.Combine(path, GetLongFileName(current));
        }
    }
    return path;
}

就是这样。现在,您可以像这样递归地转储整个 FAT 磁盘,例如:

static void Main(string[] args)
{
    using (FileStream fs = File.Open("fat.ima", FileMode.Open))
    {
        using (FatFileSystem floppy = new FatFileSystem(fs))
        {
            Dump(floppy.Root);
        }
    }
}

static void Dump(DiscDirectoryInfo di)
{
    foreach (DiscDirectoryInfo subdi in di.GetDirectories())
    {
        Dump(subdi);
    }
    foreach (DiscFileInfo fi in di.GetFiles())
    {
        Console.WriteLine(fi.FullName);
        // get LFN name
        Console.WriteLine(" " + ((FatFileSystem)di.FileSystem).GetLongFileName(fi.FullName));


        // get LFN-ed full path
        Console.WriteLine(" " + ((FatFileSystem)di.FileSystem).GetLongFilePath(fi.FullName));
    }
}

使用风险自负! :)

【讨论】:

  • 你在做这个吗?我已经决定在赏金结束后编辑DiscUtils 文件!总之谢谢!赏金结束后立即 +60 [赏金 + 10(+1)]!
  • @WritwickDas - 不,但我发现挑战很有趣,而且我是赏金猎人 :-)
  • 赏金转到Bounty Hunter!!
【解决方案2】:

7-Zip 可以提取 FAT 图像。 http://sevenzipsharp.codeplex.com 有一个 C# 包装库,可以读取文件名并提取到流中。

【讨论】:

  • 你确定它可以提取任何类型的脂肪吗?说 Fat16 或 Fat12 ......我有一个 FAT16 文件,我试图用 Gui 打开它,但它报告了 Invalid Archive 的错误......但我会尝试...... [我以前知道 SevenZipSharp,但作为 7- zip本身无法打开文件我没试过]
  • 我已经将它与软盘映像一起使用,并且它支持 vhd 硬盘映像,所以我希望它可以提取任何类型的 FAT。
  • 确切的错误是 “无法将 'FileName' 作为存档打开!” 刚刚检查过! Winimage 可以正确编辑我的 Fat!
  • 这确实表明并非如此。不幸的是,我没有可供测试的 FAT16 映像。恐怕您必须找到其他解决方案。
  • 没关系!谢谢你的建议!:)
【解决方案3】:

DiscUtils 中似乎没有对 FAT 的长名称文件支持。 Check out this post. 我相信你已经知道了,因为看起来你提出了这个问题。

【讨论】:

  • 你说得对,我在那里问了这个问题......所以我在这里问我缺少的任何替代方案......
【解决方案4】:

使用命令行的最佳方法是使用这个:

7z“x”+源+“-o”+路径+“*-r”

  • “x” = 提取;重现文件夹结构
  • source = 磁盘映像的路径
  • " -o [path]" = 提取目标
  • “*”=所有文件
  • “-r”=递归

在C#中,你可以使用我做的这个方法(我将7z.exe复制到我的应用程序的Debug文件夹中)

public void ExtractDiskImage(string pathToDiskImage, string extractPath, bool WaitForFinish)
{
    ProcessStartInfo UnzipDiskImage = new ProcessStartInfo("7z.exe");
    StringBuilder str = new StringBuilder();
    str.Append("x ");
    str.Append(pathToDiskImage);
    str.Append(" -o");
    str.Append(extractPath);
    str.Append(" * -r");
    UnzipDiskImage.Arguments = str.ToString();
    UnzipDiskImage.WindowStyle = ProcessWindowStyle.Hidden;
    Process process = Process.Start(UnzipDiskImage);
    if(WaitForFinish == true)
    {
        process.WaitForExit(); //My app had to wait for the extract to finish
    }
}

【讨论】:

    【解决方案5】:

    带有 /X 开关的 DOS DIR 命令显示长名称和短名称。

    否则有一个保存 LFN 的实用程序:DOSLFNBk.exe,这将有助于创建映射表。

    我不知道您正在寻找的答案,但没有先手动创建表,因此您可以在没有 DiskUtil 的情况下进行映射,我想不出一个实用程序或方法来实现您的目标 - 但正如您提到的,在这里在 SO 有人可能知道另一种选择。

    来自 DiskUtils 的 Kevin 确实提到,如果他包含对 LFN 的支持,他将侵犯 Mirosoft 专利,我也不建议您侵权(绝对不是商业项目),但如果这只是个人的,或者如果您能找到像 7-Zip 这样的库有许可证...

    您的屏幕截图显示 VNext.. 与 RTM 版本相同的错误?

    【讨论】:

    • “您的屏幕截图显示 VNext.. 与 RTM 版本相同的错误是什么意思?” 我没有得到这句话...我该如何运行DOS DIR 命令与 Fat Disc Image 上的 /X 开关?...而且 AFAIK,DOS LFN Backup 不是免费的[我之前发现过这个实用程序,但不知道[没有使用它,因为它不是免费的] 并且不能在光盘映像上使用..无论如何感谢您的建议..
    • 现在检查 DOSLFNBK 有一个免费的 1.6 版本,但该版本不支持 FAT32...Fat32 介于 2.0 和 2.3 之间
    • vNext == VS 2011,抱歉下次我会投入更多研究
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-15
    • 2021-12-28
    • 1970-01-01
    • 2016-02-25
    • 2015-07-21
    • 2011-02-13
    相关资源
    最近更新 更多