/// <summary>
		/// The constructor for a file contained as a hidden data stream.
		/// </summary>
		public FileNTFS(MFTRecord record, MFTAttribute attr, string path) {
			_record = record;
			_stream = new NTFSFileStream(_record.PartitionStream, _record, attr);
			FileSystem = record.FileSystem;
			Deleted = _record.Deleted;
			Name = PathUtils.MakeFileNameValid(record.FileName + "_" + attr.Name);
			Path = PathUtils.Combine(path, Name);
		}
		public NTFSFileStream(IDataStream partition, MFTRecord record, MFTAttribute attr) {
			if (attr != null) {
				_nonResident = attr.NonResident;
				if (_nonResident) {
					_runs = attr.Runs;
					_length = attr.DataSize;
				} else {
					_residentStream = attr.ResidentData;
					_length = attr.ResidentData.StreamLength;
				}
			}
			_record = record;
			_partitionStream = partition;
		}
		private void LoadExternalAttributeList(int startOffset, MFTAttribute attrList) {
			int offset = 0;
			while (true) {
				//Align to 8 byte boundary
				if (offset % 8 != 0) {
					offset = (offset / 8 + 1) * 8;
				}

				// Load the header for this external attribute reference.
				AttributeType type = (AttributeType)BitConverter.ToUInt32(_data, offset + startOffset + 0x0);
				// 0xFFFFFFFF marks end of attributes.
				if (offset == attrList.ValueLength || type == AttributeType.End) {
					break;
				}
				ushort length = BitConverter.ToUInt16(_data, offset + startOffset + 0x4);
				byte nameLength = _data[offset + startOffset + 0x6];
				ushort id = BitConverter.ToUInt16(_data, offset + startOffset + 0x18);
				ulong vcn = BitConverter.ToUInt64(_data, offset + startOffset + 0x8);
				ulong extensionRecordNumber = (BitConverter.ToUInt64(_data, offset + startOffset + 0x10) & 0x00000000FFFFFFFF);

				if (extensionRecordNumber != RecordNum && extensionRecordNumber != MFTRecordNumber) { // TODO: Are these ever different?
					// Load the MFT extension record, locate the attribute we want, and copy it over.
					MFTRecord extensionRecord = MFTRecord.Load(extensionRecordNumber, this.FileSystem);
					if (extensionRecord.Valid) {
						foreach (MFTAttribute externalAttribute in extensionRecord._attributes) {
							if (id == externalAttribute.Id) {
								if (externalAttribute.NonResident && externalAttribute.Type == AttributeType.Data) {
									// Find the corresponding data attribute on this record and merge the runlists
									bool merged = false;
									foreach (MFTAttribute attribute in _attributes) {
										if (attribute.Type == AttributeType.Data && externalAttribute.Name == attribute.Name) {
											MergeRunLists(ref attribute.Runs, externalAttribute.Runs);
											merged = true;
											break;
										}
									}
									if (!merged) {
										this._attributes.Add(externalAttribute);
									}
								} else {
									this._attributes.Add(externalAttribute);
								}
							}
						}
					}
				}

				offset += 0x1A + (nameLength * 2);
			}
		}
		private void LoadAttributes(int startOffset, MFTLoadDepth loadDepth) {
			_attributes = new List<MFTAttribute>();
			while (true) {
				//Align to 8 byte boundary
				if (startOffset % 8 != 0) {
					startOffset = (startOffset / 8 + 1) * 8;
				}

				// Read the attribute type and length and determine whether we care about this attribute.
				AttributeType type = (AttributeType)BitConverter.ToUInt32(_data, startOffset);
				if (type == AttributeType.End) {
					break;
				}
				int length = BitConverter.ToUInt16(_data, startOffset + 4);
				if (loadDepth == MFTLoadDepth.NameAttributeOnly && type != AttributeType.FileName) {
					// Skip this attribute if we're only loading the filename
					startOffset += length;
					continue;
				}

				MFTAttribute attribute = MFTAttribute.Load(_data, startOffset, this);
				if (!attribute.NonResident) {
					switch (attribute.Type) {
						case AttributeType.StandardInformation:
							LoadStandardAttribute(startOffset + attribute.ValueOffset);
							break;
						case AttributeType.FileName:
							LoadNameAttribute(startOffset + attribute.ValueOffset);
							break;
						case AttributeType.AttributeList:
							LoadExternalAttributeList(startOffset + attribute.ValueOffset, attribute);
							break;
						case AttributeType.VolumeLabel:
							LoadVolumeLabelAttribute(startOffset + attribute.ValueOffset, (int)attribute.ValueLength);
							break;
					}
				}
				if (attribute.Valid) {
					if (attribute.Type == AttributeType.Data) {
						if (attribute.Name == null) {
							if (_dataAttribute != null) {
								Console.Error.WriteLine("Warning: multiple unnamed data streams found on MFT record {0}.", RecordNum);
							}
							_dataAttribute = attribute;
						} else {
							_namedDataAttributes.Add(attribute);
						}
					}
					_attributes.Add(attribute);
				}

				startOffset += (int)attribute.Length;
			}
		}