public void Dump(TextWriter writer, string indent)
        {
            writer.WriteLine(indent + "SECURITY DESCRIPTORS");

            using (Stream s = _file.OpenStream(AttributeType.Data, "$SDS", FileAccess.Read))
            {
                byte[] buffer = Utilities.ReadFully(s, (int)s.Length);

                foreach (var entry in _idIndex.Entries)
                {
                    int pos = (int)entry.Value.SdsOffset;

                    SecurityDescriptorRecord rec = new SecurityDescriptorRecord();
                    if (!rec.Read(buffer, pos))
                    {
                        break;
                    }

                    string secDescStr = "--unknown--";
                    if (rec.SecurityDescriptor[0] != 0)
                    {
                        RawSecurityDescriptor sd = new RawSecurityDescriptor(rec.SecurityDescriptor, 0);
                        secDescStr = sd.GetSddlForm(AccessControlSections.All);
                    }

                    writer.WriteLine(indent + "  SECURITY DESCRIPTOR RECORD");
                    writer.WriteLine(indent + "           Hash: " + rec.Hash);
                    writer.WriteLine(indent + "             Id: " + rec.Id);
                    writer.WriteLine(indent + "    File Offset: " + rec.OffsetInFile);
                    writer.WriteLine(indent + "           Size: " + rec.EntrySize);
                    writer.WriteLine(indent + "          Value: " + secDescStr);
                }
            }
        }
        private SecurityDescriptor ReadDescriptor(IndexData data)
        {
            using (Stream s = _file.OpenStream(AttributeType.Data, "$SDS", FileAccess.Read))
            {
                s.Position = data.SdsOffset;
                byte[] buffer = Utilities.ReadFully(s, data.SdsLength);

                SecurityDescriptorRecord record = new SecurityDescriptorRecord();
                record.Read(buffer, 0);

                return(new SecurityDescriptor(new RawSecurityDescriptor(record.SecurityDescriptor, 0)));
            }
        }
        public uint AddDescriptor(RawSecurityDescriptor newDescriptor)
        {
            // Search to see if this is a known descriptor
            SecurityDescriptor newDescObj = new SecurityDescriptor(newDescriptor);
            uint newHash = newDescObj.CalcHash();

            byte[] newByteForm = new byte[newDescObj.Size];
            newDescObj.WriteTo(newByteForm, 0);

            foreach (var entry in _hashIndex.FindAll(new HashFinder(newHash)))
            {
                SecurityDescriptor stored = ReadDescriptor(entry.Value);

                byte[] storedByteForm = new byte[stored.Size];
                stored.WriteTo(storedByteForm, 0);

                if (Utilities.AreEqual(newByteForm, storedByteForm))
                {
                    return(entry.Value.Id);
                }
            }

            long offset = _nextSpace;

            // Write the new descriptor to the end of the existing descriptors
            SecurityDescriptorRecord record = new SecurityDescriptorRecord();

            record.SecurityDescriptor = newByteForm;
            record.Hash = newHash;
            record.Id   = _nextId;

            // If we'd overflow into our duplicate block, skip over it to the
            // start of the next block
            if (((offset + record.Size) / BlockSize) % 2 == 1)
            {
                _nextSpace = Utilities.RoundUp(offset, BlockSize * 2);
                offset     = _nextSpace;
            }

            record.OffsetInFile = offset;

            byte[] buffer = new byte[record.Size];
            record.WriteTo(buffer, 0);

            using (Stream s = _file.OpenStream(AttributeType.Data, "$SDS", FileAccess.ReadWrite))
            {
                s.Position = _nextSpace;
                s.Write(buffer, 0, buffer.Length);
                s.Position = BlockSize + _nextSpace;
                s.Write(buffer, 0, buffer.Length);
            }

            // Make the next descriptor land at the end of this one
            _nextSpace = Utilities.RoundUp(_nextSpace + buffer.Length, 16);
            _nextId++;

            // Update the indexes
            HashIndexData hashIndexData = new HashIndexData();

            hashIndexData.Hash      = record.Hash;
            hashIndexData.Id        = record.Id;
            hashIndexData.SdsOffset = record.OffsetInFile;
            hashIndexData.SdsLength = (int)record.EntrySize;

            HashIndexKey hashIndexKey = new HashIndexKey();

            hashIndexKey.Hash = record.Hash;
            hashIndexKey.Id   = record.Id;

            _hashIndex[hashIndexKey] = hashIndexData;

            IdIndexData idIndexData = new IdIndexData();

            idIndexData.Hash      = record.Hash;
            idIndexData.Id        = record.Id;
            idIndexData.SdsOffset = record.OffsetInFile;
            idIndexData.SdsLength = (int)record.EntrySize;

            IdIndexKey idIndexKey = new IdIndexKey();

            idIndexKey.Id = record.Id;

            _idIndex[idIndexKey] = idIndexData;

            _file.UpdateRecordInMft();

            return(record.Id);
        }