/// <summary> /// Set the desired file allocation, preferably without changing the end of file. /// </summary> /// <param name="length">the size to set, in bytes</param> /// <param name="useNT">if true, use the low-level undocumented NT API to allocate, without setting the length</param> private void SetAllocation(long length, bool useNT) { // using NT calls seems unreliable, beyond being undocumented, unsupported, and // likely platform dependant. // // Sometimes, it works perfectly. Other times, it generates roughly the same // number of fragments as not doing anything (but can vary). Other times, it // generates 10 times as many fragments as not doing anything. // // It does, at least, leave the file without extra allocated space at all times. #if !NT_ALLOCATE if (!useNT) { base.SetLength(length); } else { #endif //FILE_ALLOCATION_INFORMATION allocInfo = new FILE_ALLOCATION_INFORMATION(length); long allocInfo = length; IOUtil.Win32.IO_STATUS_BLOCK status = new IOUtil.Win32.IO_STATUS_BLOCK(); // = IO_STATUS_BLOCK.NullBlock; IOUtil.Win32.NtSetInformationFile( base.SafeFileHandle.DangerousGetHandle(), ref status, ref allocInfo, 8, //sizeof(FILE_ALLOCATION_INFORMATION), IOUtil.Win32.FILE_INFORMATION_CLASS.FileAllocationInformation); // FILE_INFORMATION_CLASS.FileEndOfFileInformation); #if !NT_ALLOCATE } #endif }
/// <summary> /// Get the named streams present in the given file. /// </summary> /// <param name="fileName">the file to inspect</param> /// <returns>the list of named streams available for the file, excluding the default stream</returns> /// <remarks> /// <p> /// An empty string array will be returned if there are any errors or if /// no named streams exist. /// </p> /// </remarks> public static string[] GetNamedStreams(string fileName) { IntPtr handle = IntPtr.Zero; try { handle = IOUtil.Win32.CreateFile( fileName, IOUtil.Win32.FileAccess.GENERIC_READ, IOUtil.Win32.FileShare.FILE_SHARE_READ | IOUtil.Win32.FileShare.FILE_SHARE_WRITE, IntPtr.Zero, IOUtil.Win32.CreationDisposition.OPEN_EXISTING, IOUtil.Win32.FileFlagsAndAttributes.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero); //if (handle == IntPtr.Zero) return new string[0]; if (handle.ToInt64() <= 0) return new string[0]; byte[] streamNames = new byte[32768 << 2]; IOUtil.Win32.IO_STATUS_BLOCK statusBlock = new IOUtil.Win32.IO_STATUS_BLOCK(); uint status = IOUtil.Win32.NtQueryInformationFile(handle, ref statusBlock, streamNames, (uint)streamNames.Length, IOUtil.Win32.FILE_INFORMATION_CLASS.FileStreamInformation); if (!IOUtil.Win32.NT_SUCCESS(status) || statusBlock.Information == 0) return new string[0]; ArrayList names = new ArrayList(); for (int pos = 0; pos < streamNames.Length; ) { try { int start = pos; // get next entry: int next = (int)BitConverter.ToUInt32(streamNames, pos); pos += 4; // get length: int len = (int)BitConverter.ToUInt32(streamNames, pos); pos += 4; // get size: long size = BitConverter.ToInt64(streamNames, pos); pos += 8; // get allocation size: long allocationSize = BitConverter.ToInt64(streamNames, pos); pos += 8; // get name: string name = Encoding.Unicode.GetString(streamNames, pos, len); if (name.Length != 0) { if (name[0] == ':' && name.EndsWith(":$DATA")) { name = name.Substring(1, name.Length - "::$DATA".Length); } if (name.Length != 0) { names.Add(name); } } if (next == 0) break; pos = start + next; // private struct FILE_STREAM_INFORMATION // { // ULONG NextEntry; // ULONG NameLength; // LARGE_INTEGER Size; // LARGE_INTEGER AllocationSize; // USHORT Name[1]; // } } catch { // ignore running off the end?? } } return (string[])names.ToArray(typeof(string)); } catch { return new string[0]; } finally { if (handle != IntPtr.Zero) { try { IOUtil.Win32.CloseHandle(handle); } catch { // ignore... } } } }
/// <summary> /// Set the desired file allocation, preferably without changing the end of file. /// </summary> /// <param name="length">the size to set, in bytes</param> /// <param name="useNT">if true, use the low-level undocumented NT API to allocate, without setting the length</param> private void SetAllocation(long length, bool useNT) { // using NT calls seems unreliable, beyond being undocumented, unsupported, and // likely platform dependant. // // Sometimes, it works perfectly. Other times, it generates roughly the same // number of fragments as not doing anything (but can vary). Other times, it // generates 10 times as many fragments as not doing anything. // // It does, at least, leave the file without extra allocated space at all times. #if !NT_ALLOCATE if (!useNT) { base.SetLength(length); } else { #endif //FILE_ALLOCATION_INFORMATION allocInfo = new FILE_ALLOCATION_INFORMATION(length); long allocInfo = length; IOUtil.Win32.IO_STATUS_BLOCK status = new IOUtil.Win32.IO_STATUS_BLOCK(); // = IO_STATUS_BLOCK.NullBlock; IOUtil.Win32.NtSetInformationFile( #if DOTNET2 base.SafeFileHandle.DangerousGetHandle(), #else base.Handle, #endif ref status, ref allocInfo, 8, //sizeof(FILE_ALLOCATION_INFORMATION), IOUtil.Win32.FILE_INFORMATION_CLASS.FileAllocationInformation); // FILE_INFORMATION_CLASS.FileEndOfFileInformation); #if !NT_ALLOCATE } #endif }