Ejemplo n.º 1
0
        public Response RemoveVolume(VolumeName request, string traceId)
        {
            if (!this.VolumeExists(request.Name))
            {
                string errorMessage = String.Format("Attempt to remove volume {0} that does not exist.", request.Name);
                TraceWriter.WriteErrorWithId(Constants.TraceSource, traceId, errorMessage);
                return(new Response(errorMessage));
            }

            this.volumeRWLock.EnterWriteLock();
            try
            {
                if (!volumeMappings.ContainsKey(request.Name))
                {
                    string errorMessage = String.Format("Mapping for volume {0} was not found.", request.Name);
                    TraceWriter.WriteErrorWithId(Constants.TraceSource, traceId, errorMessage);
                    return(new Response(errorMessage));
                }

                if (this.volumeMappings[request.Name].NumberOfMounts != 0)
                {
                    string errorMesg = String.Format("Cannot remove volume {0} since it is in use.", request.Name);
                    TraceWriter.WriteErrorWithId(Constants.TraceSource, traceId, errorMesg);
                    return(new Response(errorMesg));
                }

                // Remove the mountpoint.
                try
                {
                    string pathMountpoint = this.volumeMappings[request.Name].Mountpoint;
                    if (System.IO.Directory.Exists(pathMountpoint))
                    {
                        System.IO.Directory.Delete(pathMountpoint);
                    }

                    // Remove the metadata file
                    string metadataFilename = Path.Combine(this.serviceContext.CodePackageActivationContext.WorkDirectory, volumesMetadata, request.Name);
                    if (System.IO.File.Exists(metadataFilename))
                    {
                        System.IO.File.Delete(metadataFilename);
                    }
                }
                catch (Exception ex)
                {
                    TraceWriter.WriteWarningWithId(Constants.TraceSource, traceId, String.Format("{0}Unable to cleanup volume artifacts due to exception: {1}", traceId, ex.Message));
                }

                this.volumeMappings.Remove(request.Name);

                return(new Response());
            }
            finally
            {
                this.volumeRWLock.ExitWriteLock();
            }
        }
Ejemplo n.º 2
0
        public override int GetHashCode()
        {
            unchecked
            {
                int hashCode = VolumeName != null?VolumeName.ToUpper().GetHashCode() : 0;

                hashCode = (hashCode * 397) ^ (FilterQuery != null ? FilterQuery.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (SortOrder != null ? SortOrder.ToUpper().GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (Search != null ? Search.GetHashCode() : 0);

                return(hashCode);
            }
        }
Ejemplo n.º 3
0
        internal async Task <string> PrepForSnapshot(SnapSession session)
        {
            try
            {
                SnapShotPutBody body = new SnapShotPutBody();
                body.RunAsNames = session.RunAsName;
                VolumeMapping vm    = new VolumeMapping();
                VolumeName    vname = new VolumeName();
                vname.Name    = session.VolumeName;
                vm.VolumeName = vname;
                FootPrintObject fp = new FootPrintObject();
                fp.SVMName           = session.SvmName;
                fp.VolAndLunsMapping = new System.Collections.Generic.List <VolumeMapping>();
                fp.VolAndLunsMapping.Add(vm);
                body.FootPrint = new System.Collections.Generic.List <FootPrintObject>();
                body.FootPrint.Add(fp);
                PluginParams pluginParams = new PluginParams();
                pluginParams.Data = new System.Collections.Generic.List <PluginData>();
                PluginData port = new PluginData();
                port.Key   = "PORT";
                port.Value = "3306";
                pluginParams.Data.Add(port);
                PluginData ms = new PluginData();
                ms.Key   = "MASTER_SLAVE";
                ms.Value = "N";
                pluginParams.Data.Add(ms);
                PluginData host = new PluginData();
                host.Key   = "HOST";
                host.Value = session.CloneHostName;
                pluginParams.Data.Add(host);
                PluginData uid = new PluginData();
                uid.Key   = "CLONE_UID";
                uid.Value = SnapSession.BuildCloneName(session.DbName, session.AppName);
                pluginParams.Data.Add(uid);
                body.PluginParams = pluginParams;

                ClientResponse <SnapBackupResponse> response = await this.SendRequestAsync <SnapBackupResponse>(Method.PUT, $"api/3.0/plugins/{session.Plugin}/resources/{session.DbKey}", body, false);

                log.Info($"Payload PUT data Detail: {response.Payload}");

                return(response.Response.StatusCode.ToString());
            }
            catch (Exception ex)
            {
                this.log.Error($"Error executing PUT data for snapshot of clone with key {session.DbKey}: {ex}");
                throw;
            }
        }
Ejemplo n.º 4
0
        public Response GetVolumeMountPoint(VolumeName request)
        {
            this.rwLock.EnterReadLock();
            try
            {
                if (!knownVolumeMappings.ContainsKey(request.Name))
                {
                    return(new Response("volume not found"));
                }

                return(new VolumeMountResponse(this.knownVolumeMappings[request.Name].Mountpoint));
            }
            finally
            {
                this.rwLock.ExitReadLock();
            }
        }
Ejemplo n.º 5
0
        internal async Task <string> CreateResource(SnapSession session)
        {
            string answer = string.Empty;

            try
            {
                log.Info($"Token = {this.token}");
                ResourceBody body = new ResourceBody();
                body.ResourceName = session.DbName;
                body.ResourceType = "Database";
                body.HostName     = session.HostName;
                body.RunAsNames   = $"{session.DbName}_{session.Plugin}";
                body.MountPaths   = new System.Collections.Generic.List <MountInfo>();
                MountInfo mi = new MountInfo();
                mi.MountPath = session.MountPath;
                body.MountPaths.Add(mi);
                VolumeMapping vm    = new VolumeMapping();
                VolumeName    vname = new VolumeName();
                vname.Name    = session.VolumeName;
                vm.VolumeName = vname;
                FootPrintObject fp = new FootPrintObject();
                fp.SVMName           = session.SvmName;
                fp.VolAndLunsMapping = new System.Collections.Generic.List <VolumeMapping>();
                fp.VolAndLunsMapping.Add(vm);
                body.FootPrint = new System.Collections.Generic.List <FootPrintObject>();
                body.FootPrint.Add(fp);
                PluginParams pluginParams = new PluginParams();
                pluginParams.Data = new System.Collections.Generic.List <PluginData>();
                PluginData ms = new PluginData();
                ms.Key   = "MASTER_SLAVE";
                ms.Value = "N";
                pluginParams.Data.Add(ms);
                body.PluginParams = pluginParams;

                var response = await this.SendRequestAsync <dynamic>(Method.POST, $"api/3.0/plugins/MySQL/resources", body, false);

                log.Info($"Payload: {response.Payload}");
                string dbKey = string.Empty;
                answer = response.Response.Content.ToString();
            }
            catch (Exception ex)
            {
                this.log.Error($"Error while getting creating resource key: {ex}");
            }
            return(answer);
        }
Ejemplo n.º 6
0
        public NtfsFileSystem(string name) : base()
        {
            DirectoryRecordCount = 1;          // root folder
            FileRecordCount      = CurrentMftRecordNumber = 0;
            BytesPerFileRecord   = 64_000;     // 64 KB
            VolumeSize           = 20_000_000; // 20 MB
            BytesOccupied        = 0;

            CreateBoot();
            CreateRoot(name);

            VolName = new VolumeName();
            char[] arr = name.ToCharArray();
            Array.Reverse(arr);
            VolName.Name   = arr.ToString();
            BytesOccupied += (uint)VolName.Name.Length;

            //BytesRemaining = VolumeSize - BytesOccupied;
        }
Ejemplo n.º 7
0
        public Response GetVolumeMountPoint(VolumeName request, string traceId)
        {
            this.volumeRWLock.EnterReadLock();
            try
            {
                if (!volumeMappings.ContainsKey(request.Name))
                {
                    string errorMessage = String.Format("Mapping for volume {0} was not found.", request.Name);
                    TraceWriter.WriteErrorWithId(Constants.TraceSource, traceId, errorMessage);
                    return(new Response(errorMessage));
                }

                return(new VolumeMountResponse(this.volumeMappings[request.Name].Mountpoint));
            }
            finally
            {
                this.volumeRWLock.ExitReadLock();
            }
        }
Ejemplo n.º 8
0
        public Response GetVolume(VolumeName request)
        {
            this.rwLock.EnterReadLock();
            try
            {
                if (!knownVolumeMappings.ContainsKey(request.Name))
                {
                    return(new VolumeGetResponse("volume not found"));
                }

                return(new VolumeGetResponse(
                           new VolumeMountDescription()
                {
                    Name = request.Name,
                    Mountpoint = knownVolumeMappings[request.Name].Mountpoint
                }));
            }
            finally
            {
                this.rwLock.ExitReadLock();
            }
        }
Ejemplo n.º 9
0
        public FileRecord(byte[] rawBytes, int offset)
        {
            Offset = offset;
            var sig = BitConverter.ToInt32(rawBytes, 0);

            if ((sig != _fileSig) && (sig != _baadSig) && (sig != 0x0))
            {
                Logger.Fatal($"Invalid signature! 0x{sig:X}");
                return;
                //throw new Exception("Invalid signature!");
            }

            if (sig == _baadSig)
            {
                Logger.Warn($"Bad signature at offset 0x{offset:X}");
                return;
            }

            Attributes = new List <Attribute>();

            FixupOffset     = BitConverter.ToInt16(rawBytes, 2);
            FixupEntryCount = BitConverter.ToInt16(rawBytes, 4);

            LogSequenceNumber = BitConverter.ToInt64(rawBytes, 0x8);

            SequenceNumber = BitConverter.ToInt16(rawBytes, 0x10);

            ReferenceCount = BitConverter.ToInt16(rawBytes, 0x12);

            FirstAttributeOffset = BitConverter.ToInt16(rawBytes, 0x14);

            EntryFlags = (EntryFlag)BitConverter.ToInt16(rawBytes, 0x16);

            Logger.Trace($"Entry flags: {EntryFlags}");

            ActualRecordSize = BitConverter.ToInt32(rawBytes, 0x18);

            AllocatedRecordSize = BitConverter.ToInt32(rawBytes, 0x1c);

            var entryBytes = new byte[8];

            Buffer.BlockCopy(rawBytes, 0x20, entryBytes, 0, 8);

            MFTRecordToBaseRecord = new MftEntryInfo(entryBytes);

            FirstAvailableAttribueId = BitConverter.ToInt16(rawBytes, 0x28);

            EntryNumber = BitConverter.ToInt32(rawBytes, 0x2c);

            var fixupExpectedBytes = new byte[2];
            var fixupActual1       = new byte[2];
            var fixupActual2       = new byte[2];

            Buffer.BlockCopy(rawBytes, 0x30, fixupExpectedBytes, 0, 2);
            Buffer.BlockCopy(rawBytes, 0x32, fixupActual1, 0, 2);
            Buffer.BlockCopy(rawBytes, 0x34, fixupActual2, 0, 2);

            //verify this record looks ok based on fixup bytes
            //0x1FE and 0x3fe

            var expectedFixupVal = BitConverter.ToInt16(fixupExpectedBytes, 0);
            var x1FeValue        = BitConverter.ToInt16(rawBytes, 0x1FE);
            var x3FeValue        = BitConverter.ToInt16(rawBytes, 0x3FE);

            if ((x1FeValue != expectedFixupVal) &&
                ((EntryFlags & EntryFlag.FileRecordSegmentInUse) == EntryFlag.FileRecordSegmentInUse))
            {
                Logger.Warn(
                    $"FILE record at offset 0x{offset:X}! Fixup values do not match at 0x1FE. Expected: {expectedFixupVal}, actual: {x1FeValue}, EntryFlags: {EntryFlags}");
            }

            if ((x3FeValue != expectedFixupVal) &&
                ((EntryFlags & EntryFlag.FileRecordSegmentInUse) == EntryFlag.FileRecordSegmentInUse))
            {
                Logger.Warn(
                    $"FILE record at offset 0x{offset:X}! Fixup values do not match at 0x3FE. Expected: {expectedFixupVal}, actual: {x3FeValue}, EntryFlags: {EntryFlags}");
            }

            //header is done, replace fixup bytes with actual bytes
            //0x1fe and 0x3fe should contain fixup bytes

            Buffer.BlockCopy(fixupActual1, 0, rawBytes, 0x1fe, 2);
            Buffer.BlockCopy(fixupActual2, 0, rawBytes, 0x3fe, 2);

            //start attribute processing at FirstAttributeOffset

            var index = (int)FirstAttributeOffset;

            while (index < ActualRecordSize)
            {
                var attrType = BitConverter.ToInt32(rawBytes, index);

                var attrSize = BitConverter.ToInt32(rawBytes, index + 4);

//                Logger.Trace(
//                    $"ActualRecordSize: {ActualRecordSize} attrType: 0x{attrType:X}, size: {attrSize}, index: {index}, offset: 0x{offset:x}, i+o: 0x{index + offset:X}");

                if ((attrSize == 0) || (attrType == -1))
                {
                    index += 8;          //skip -1 type and 0 size

                    if (EntryFlags == 0) //this is a free record
                    {
                        break;
                    }

                    continue;
                }

                var rawAttr = new byte[attrSize];
                Buffer.BlockCopy(rawBytes, index, rawAttr, 0, attrSize);

                switch ((AttributeType)attrType)
                {
                case AttributeType.StandardInformation:
                    var si = new StandardInfo(rawAttr);
                    Attributes.Add(si);

                    SILastAccessedOn    = si.LastAccessedOn;
                    SICreatedOn         = si.CreatedOn;
                    SIRecordModifiedOn  = si.RecordModifiedOn;
                    SIContentModifiedOn = si.ContentModifiedOn;

                    break;

                case AttributeType.FileName:
                    var fi = new FileName(rawAttr);
                    Attributes.Add(fi);

                    if ((fi.FileInfo.NameType & NameTypes.Windows) == NameTypes.Windows)
                    {
                        FName = fi.FileInfo.FileName;
                    }

                    //if (fi.FileInfo.LastAccessedOn.UtcDateTime != SILastAccessedOn.UtcDateTime)
                    //{
                    FNLastAccessedOn = fi.FileInfo.LastAccessedOn;
                    //}

                    //if (fi.FileInfo.CreatedOn.UtcDateTime != SICreatedOn.UtcDateTime)
                    //{
                    FNCreatedOn = fi.FileInfo.CreatedOn;
                    //}

                    //if (fi.FileInfo.RecordModifiedOn.UtcDateTime != SIRecordModifiedOn.UtcDateTime)
                    //{
                    FNRecordModifiedOn = fi.FileInfo.RecordModifiedOn;
                    //}


                    //if (fi.FileInfo.ContentModifiedOn.UtcDateTime != SIContentModifiedOn.UtcDateTime)
                    //{
                    FNContentModifiedOn = fi.FileInfo.ContentModifiedOn;
                    //}


                    break;

                case AttributeType.Data:
                    var data = new Data(rawAttr);
                    Attributes.Add(data);
                    break;

                case AttributeType.IndexAllocation:
                    var ia = new IndexAllocation(rawAttr);
                    Attributes.Add(ia);
                    break;

                case AttributeType.IndexRoot:
                    var ir = new IndexRoot(rawAttr);
                    Attributes.Add(ir);
                    break;

                case AttributeType.Bitmap:
                    var bm = new Bitmap(rawAttr);
                    Attributes.Add(bm);
                    break;

                case AttributeType.VolumeVersionObjectId:
                    var oi = new ObjectId(rawAttr);
                    Attributes.Add(oi);
                    break;

                case AttributeType.SecurityDescriptor:
                    var sd = new SecurityDescriptor(rawAttr);
                    Attributes.Add(sd);

                    break;

                case AttributeType.VolumeName:
                    var vn = new VolumeName(rawAttr);
                    Attributes.Add(vn);
                    break;

                case AttributeType.VolumeInformation:
                    var vi = new VolumeInformation(rawAttr);
                    Attributes.Add(vi);
                    break;

                case AttributeType.LoggedUtilityStream:
                    var lus = new LoggedUtilityStream(rawAttr);
                    Attributes.Add(lus);
                    break;

                case AttributeType.ReparsePoint:
                    var rp = new ReparsePoint(rawAttr);
                    Attributes.Add(rp);
                    break;

                case AttributeType.AttributeList:
                    var al = new AttributeList(rawAttr);
                    Attributes.Add(al);
                    break;

                case AttributeType.Ea:
                    //TODO Finish this
                    var ea = new ExtendedAttribute(rawAttr);
                    Attributes.Add(ea);
                    break;

                case AttributeType.EaInformation:
                    var eai = new ExtendedAttributeInformation(rawAttr);
                    Attributes.Add(eai);
                    break;

                default:
                    Logger.Warn($"Unhandled attribute type! Add me: {(AttributeType) attrType}");
                    throw new Exception($"Add me: {(AttributeType) attrType}");
                    break;
                }

                index += attrSize;
            }

            SlackStartOffset = index;

            //rest is slack. handle here?
            Logger.Trace($"Slack starts at {index} i+o: 0x{index + offset:X}");
        }
Ejemplo n.º 10
0
        public Response RemoveVolume(VolumeName request)
        {
            if (!this.VolumeExists(request.Name))
            {
                return(new Response("volume not found"));
            }

            this.rwLock.EnterWriteLock();
            try
            {
                if (!knownVolumeMappings.ContainsKey(request.Name))
                {
                    return(new Response("volume not found"));
                }

                if (this.knownVolumeMappings[request.Name].MountIDs.Count != 0)
                {
                    return(new Response("volume in use"));
                }

                if (!this.DoUnmount(this.knownVolumeMappings[request.Name]))
                {
                    TraceWriter.WriteErrorWithId(
                        TraceType,
                        this.serviceContext.TraceId,
                        "unmount during remove failed");
                    return(new Response("unmount failed"));
                }

                string volumesMetadataFilename = Path.Combine(volumesMetadataPath, request.Name);
                if (System.IO.File.Exists(volumesMetadataFilename))
                {
                    System.IO.File.Delete(volumesMetadataFilename);
                }
                else
                {
                    TraceWriter.WriteWarningWithId(
                        TraceType,
                        this.serviceContext.TraceId,
                        $"Remove volume {request.Name} unexpected state: volumesMetadataFilename {volumesMetadataFilename} not exists");
                }

                string mountMetadataDirectoryPath = Path.Combine(mountMetadataPath, request.Name);
                if (System.IO.Directory.Exists(mountMetadataDirectoryPath))
                {
                    System.IO.Directory.Delete(mountMetadataDirectoryPath);
                }
                else
                {
                    TraceWriter.WriteWarningWithId(
                        TraceType,
                        this.serviceContext.TraceId,
                        $"Remove volume {request.Name} unexpected state: mountMetadataDirectoryPath {mountMetadataDirectoryPath} not exists");
                }

                this.knownVolumeMappings.Remove(request.Name);

                return(new Response());
            }
            catch (Exception e)
            {
                TraceWriter.WriteErrorWithId(
                    TraceType,
                    this.serviceContext.TraceId,
                    $"Remove volume {request.Name} failed with exception {e}.");

                return(new Response($"Remove volume {request.Name} failed with exception {e}."));
            }
            finally
            {
                this.rwLock.ExitWriteLock();
            }
        }
Ejemplo n.º 11
0
        public FileRecord(byte[] rawBytes, int offset)
        {
            Offset = offset;

            var sig = BitConverter.ToInt32(rawBytes, 0);

            switch (sig)
            {
            case FileSig:
                break;

            case BaadSig:
                _logger.Debug($"Bad signature at offset 0x{offset:X}");
                IsBad = true;
                return;

            default:
                //not initialized
                _logger.Debug($"Uninitialized entry (no signature) at offset 0x{offset:X}");
                IsUninitialized = true;
                return;
            }

            _logger.Debug($"Processing FILE record at offset 0x{offset:X}");

            Attributes = new List <Attribute>();

            FixupOffset     = BitConverter.ToInt16(rawBytes, 0x4);
            FixupEntryCount = BitConverter.ToInt16(rawBytes, 0x6);

            //to build fixup info, take FixupEntryCount x 2 bytes as each are 2 bytes long
            var fixupTotalLength = FixupEntryCount * 2;

            var fixupBuffer = new byte[fixupTotalLength];

            Buffer.BlockCopy(rawBytes, FixupOffset, fixupBuffer, 0, fixupTotalLength);

            //pull this early so we can check if its free in our fix up value messages
            EntryFlags = (EntryFlag)BitConverter.ToInt16(rawBytes, 0x16);

            FixupData = new FixupData(fixupBuffer);

            FixupOk = true;

            //fixup verification
            var counter = 512;

            foreach (var bytese in FixupData.FixupActual)
            {
                //adjust the offset to where we need to check
                var fixupOffset = counter - 2;

                var expected = BitConverter.ToInt16(rawBytes, fixupOffset);
                if (expected != FixupData.FixupExpected && EntryFlags != 0x0)
                {
                    FixupOk = false;
                    _logger.Warn(
                        $"Offset: 0x{Offset:X} Entry/seq: 0x{EntryNumber:X}/0x{SequenceNumber:X} Fixup values do not match at 0x{fixupOffset:X}. Expected: 0x{FixupData.FixupExpected:X2}, actual: 0x{expected:X2}");
                }

                //replace fixup expected with actual bytes. bytese has actual replacement values in it.
                Buffer.BlockCopy(bytese, 0, rawBytes, fixupOffset, 2);

                counter += 512;
            }

            LogSequenceNumber = BitConverter.ToInt64(rawBytes, 0x8);

            SequenceNumber = BitConverter.ToUInt16(rawBytes, 0x10);

            ReferenceCount = BitConverter.ToInt16(rawBytes, 0x12);

            FirstAttributeOffset = BitConverter.ToInt16(rawBytes, 0x14);

            ActualRecordSize = BitConverter.ToInt32(rawBytes, 0x18);

            AllocatedRecordSize = BitConverter.ToInt32(rawBytes, 0x1c);

            var entryBytes = new byte[8];

            Buffer.BlockCopy(rawBytes, 0x20, entryBytes, 0, 8);

            MftRecordToBaseRecord = new MftEntryInfo(entryBytes);

            FirstAvailablAttribueId = BitConverter.ToInt16(rawBytes, 0x28);

            EntryNumber = BitConverter.ToUInt32(rawBytes, 0x2c);

            //start attribute processing at FirstAttributeOffset

            var index = (int)FirstAttributeOffset;

            while (index < ActualRecordSize)
            {
                var attrType = (AttributeType)BitConverter.ToInt32(rawBytes, index);

                var attrSize = BitConverter.ToInt32(rawBytes, index + 4);

                if (attrSize == 0 || attrType == AttributeType.EndOfAttributes)
                {
                    index += 8; //skip -1 type and 0 size

                    if (index != ActualRecordSize)
                    {
                        _logger.Warn($"Slack space found in entry/seq: 0x{EntryNumber:X}/0x{SequenceNumber:X}");
                    }

                    //TODO process slack here?
                    break;
                }

                _logger.Debug(
                    $"Found Attribute Type {attrType.ToString()} at absolute offset: 0x{index + offset:X}");

                _logger.Trace(
                    $"ActualRecordSize: 0x{ActualRecordSize:X}, size: 0x{attrSize:X}, index: 0x{index:X}");

                var rawAttr = new byte[attrSize];
                Buffer.BlockCopy(rawBytes, index, rawAttr, 0, attrSize);

                switch (attrType)
                {
                case AttributeType.StandardInformation:
                    var si = new StandardInfo(rawAttr);
                    Attributes.Add(si);
                    break;

                case AttributeType.FileName:
                    var fi = new FileName(rawAttr);
                    Attributes.Add(fi);
                    break;

                case AttributeType.Data:
                    var d = new Data(rawAttr);
                    Attributes.Add(d);
                    break;

                case AttributeType.IndexAllocation:
                    var ia = new IndexAllocation(rawAttr);
                    Attributes.Add(ia);
                    break;

                case AttributeType.IndexRoot:
                    var ir = new IndexRoot(rawAttr);
                    Attributes.Add(ir);
                    break;

                case AttributeType.Bitmap:
                    var bm = new Bitmap(rawAttr);
                    Attributes.Add(bm);
                    break;

                case AttributeType.VolumeVersionObjectId:
                    var oi = new ObjectId_(rawAttr);
                    Attributes.Add(oi);
                    break;

                case AttributeType.SecurityDescriptor:
                    var sd = new SecurityDescriptor(rawAttr);
                    Attributes.Add(sd);
                    break;

                case AttributeType.VolumeName:
                    var vn = new VolumeName(rawAttr);
                    Attributes.Add(vn);
                    break;

                case AttributeType.VolumeInformation:
                    var vi = new VolumeInformation(rawAttr);
                    Attributes.Add(vi);
                    break;

                case AttributeType.LoggedUtilityStream:
                    var lus = new LoggedUtilityStream(rawAttr);
                    Attributes.Add(lus);
                    break;

                case AttributeType.ReparsePoint:
                    try
                    {
                        var rp = new ReparsePoint(rawAttr);
                        Attributes.Add(rp);
                    }
                    catch (Exception)
                    {
                        var l = LogManager.GetLogger("ReparsePoint");

                        l.Error(
                            $"There was an error parsing a ReparsePoint in FILE record at offset 0x{Offset:X}. Please extract via --dd and --do and send to [email protected]");
                    }

                    break;

                case AttributeType.AttributeList:
                    var al = new AttributeList(rawAttr);
                    Attributes.Add(al);
                    break;

                case AttributeType.Ea:
                    var ea = new ExtendedAttribute(rawAttr);
                    Attributes.Add(ea);
                    break;

                case AttributeType.EaInformation:
                    var eai = new ExtendedAttributeInformation(rawAttr);
                    Attributes.Add(eai);
                    break;

                default:
                    throw new Exception($"Add me: {attrType} (0x{attrType:X})");
                }

                index += attrSize;
            }

            //rest is slack. handle here?
            _logger.Trace($"Slack starts at 0x{index:X} Absolute offset: 0x{index + offset:X}");
        }