static IBuffer GetContent(MasterFileTableEntry entry)
        {
            foreach (var attr in entry.Attributes)
            {
                if (attr.AttributeType == AttributeType.Data)
                {
                    return(attr.Content);
                }
            }

            return(null);
        }
        static long GetSize(MasterFileTableEntry entry)
        {
            foreach (var attr in entry.Attributes)
            {
                FileNameAttribute fna = attr as FileNameAttribute;
                if (fna != null)
                {
                    return(fna.RealSize);
                }
            }

            return(0);
        }
        static string GetPath(MasterFileTable mft, MasterFileTableEntry entry)
        {
            if (entry.SequenceNumber == MasterFileTable.RootDirectoryIndex)
            {
                return("<root>");
            }

            FileNameAttribute fna = null;

            foreach (var attr in entry.Attributes)
            {
                FileNameAttribute thisFna = attr as FileNameAttribute;
                if (thisFna != null)
                {
                    if (fna == null || thisFna.FileNameNamespace == NtfsNamespace.Win32 || thisFna.FileNameNamespace == NtfsNamespace.Win32AndDos)
                    {
                        fna = thisFna;
                    }
                }
            }

            if (fna == null)
            {
                return("<unknown>");
            }

            string parentPath = "<unknown>";
            MasterFileTableEntry parentEntry = mft[fna.ParentDirectory.RecordIndex];

            if (parentEntry != null)
            {
                if (parentEntry.SequenceNumber == fna.ParentDirectory.RecordSequenceNumber || parentEntry.SequenceNumber == fna.ParentDirectory.RecordSequenceNumber + 1)
                {
                    parentPath = GetPath(mft, parentEntry);
                }
            }

            return(parentPath + "\\" + fna.FileName);
        }
        protected override void DoRun()
        {
            VolumeManager volMgr = new VolumeManager();

            foreach (string disk in _diskFiles.Values)
            {
                volMgr.AddDisk(VirtualDisk.OpenDisk(disk, FileAccess.Read, UserName, Password));
            }


            VolumeInfo volInfo = null;

            if (!string.IsNullOrEmpty(VolumeId))
            {
                volInfo = volMgr.GetVolume(VolumeId);
            }
            else if (Partition >= 0)
            {
                volInfo = volMgr.GetPhysicalVolumes()[Partition];
            }
            else
            {
                volInfo = volMgr.GetLogicalVolumes()[0];
            }

            using (NtfsFileSystem fs = new NtfsFileSystem(volInfo.Open()))
            {
                MasterFileTable mft = fs.GetMasterFileTable();
                if (_recoverFile.IsPresent)
                {
                    MasterFileTableEntry entry = mft[long.Parse(_recoverFile.Value)];
                    IBuffer content            = GetContent(entry);
                    if (content == null)
                    {
                        Console.WriteLine("Sorry, unable to recover content");
                        Environment.Exit(1);
                    }

                    string outFile = _recoverFile.Value + "__recovered.bin";
                    if (File.Exists(outFile))
                    {
                        Console.WriteLine("Sorry, the file already exists: " + outFile);
                        Environment.Exit(1);
                    }

                    using (FileStream outFileStream = new FileStream(outFile, FileMode.CreateNew, FileAccess.Write))
                    {
                        Pump(content, outFileStream);
                    }

                    Console.WriteLine("Possible file contents saved as: " + outFile);
                    Console.WriteLine();
                    Console.WriteLine("Caution! It is rare for the file contents of deleted files to be intact - most");
                    Console.WriteLine("likely the contents recovered are corrupt as the space has been reused.");
                }
                else
                {
                    foreach (var entry in mft.GetEntries(EntryStates.NotInUse))
                    {
                        // Skip entries with no attributes, they've probably never been used.  We're certainly
                        // not going to manage to recover any useful data from them.
                        if (entry.Attributes.Count == 0)
                        {
                            continue;
                        }

                        // Skip directories - any useful files inside will be found separately
                        if ((entry.Flags & MasterFileTableEntryFlags.IsDirectory) != 0)
                        {
                            continue;
                        }

                        long   size = GetSize(entry);
                        string path = GetPath(mft, entry);

                        if (!_showMeta.IsPresent && path.StartsWith(@"<root>\$Extend"))
                        {
                            continue;
                        }

                        if (!_showZeroSize.IsPresent && size == 0)
                        {
                            continue;
                        }

                        Console.WriteLine("Index: {0,-4}   Size: {1,-8}   Path: {2}", entry.Index, Utilities.ApproximateDiskSize(size), path);
                    }
                }
            }
        }