public static IList <Win32StreamInfo> ListStreams(string filePath) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath"); } if (-1 != filePath.IndexOfAny(Path.GetInvalidPathChars())) { throw new ArgumentException(Resources.Error_InvalidFileChars, "filePath"); } var result = new List <Win32StreamInfo>(); using ( var hFile = SafeCreateFile(filePath, NativeFileAccess.GenericRead, FileShare.Read, IntPtr.Zero, FileMode.Open, NativeFileAttributesAndFlags.BackupSemantics, IntPtr.Zero)) { using (var hName = new StreamName()) { if (!hFile.IsInvalid) { var streamId = new Win32StreamId(); var dwStreamHeaderSize = Marshal.SizeOf(streamId); var finished = false; var context = IntPtr.Zero; int bytesRead; string name; try { while (!finished) { // Read the next stream header: if (!Kernel32.BackupRead(hFile, ref streamId, dwStreamHeaderSize, out bytesRead, false, false, ref context)) { finished = true; } else if (dwStreamHeaderSize != bytesRead) { finished = true; } else { // Read the stream name: if (0 >= streamId.StreamNameSize) { name = null; } else { hName.EnsureCapacity(streamId.StreamNameSize); if (!Kernel32.BackupRead(hFile, hName.MemoryBlock, streamId.StreamNameSize, out bytesRead, false, false, ref context)) { name = null; finished = true; } else { // Unicode chars are 2 bytes: name = hName.ReadStreamName(bytesRead >> 1); } } // Add the stream info to the result: if (!string.IsNullOrEmpty(name)) { result.Add(new Win32StreamInfo { StreamType = (FileStreamType)streamId.StreamId, StreamAttributes = (FileStreamAttributes)streamId.StreamAttributes, StreamSize = streamId.Size, StreamName = name }); } // Skip the contents of the stream: int bytesSeekedLow, bytesSeekedHigh; if (!finished && !Kernel32.BackupSeek(hFile, (int)(streamId.Size & 0xffffffff), (int)(streamId.Size >> 32), out bytesSeekedLow, out bytesSeekedHigh, ref context)) { finished = true; } } } } finally { // Abort the backup: Kernel32.BackupRead(hFile, hName.MemoryBlock, 0, out bytesRead, true, false, ref context); } } } } return(result); }
public override IEnumerable <ContentInfo> GetContentInfos(string path) { long length; var contentInfos = new List <ContentInfo>(); try { length = new FileInfo(path).Length; } catch (FileNotFoundException) { yield break; } yield return(new ContentInfo(this.DefaultContentName, length)); var hFile = Kernel32.CreateFileW(path, (int)FileAccess.Read, (int)FileShare.ReadWrite, IntPtr.Zero, (int)FileMode.Open, (int)Kernel32.FileFlags.BackupSemantics, IntPtr.Zero); if (hFile.ToInt32() == Kernel32.INVALID_HANDLE_VALUE) { yield break; } try { var sid = new Kernel32.WIN32_STREAM_ID(); var dwStreamHeaderSize = Marshal.SizeOf(sid); var context = new IntPtr(); var shouldContinue = true; while (shouldContinue) { var lRead = 0; shouldContinue = Kernel32.BackupRead(hFile, ref sid, dwStreamHeaderSize, ref lRead, false, false, ref context); if (shouldContinue && lRead == dwStreamHeaderSize) { if (sid.dwStreamNameSize > 0) { var pName = Marshal.AllocHGlobal(sid.dwStreamNameSize); lRead = 0; try { shouldContinue = Kernel32.BackupRead(hFile, pName, sid.dwStreamNameSize, ref lRead, false, false, ref context); var bName = new char[sid.dwStreamNameSize]; Marshal.Copy(pName, bName, 0, sid.dwStreamNameSize); // Name Format ":NAME:$DATA\0" var streamName = new string(bName); var i = streamName.IndexOf(Kernel32.STREAM_SEPERATOR, 1, StringComparison.Ordinal); if (i > -1) { streamName = streamName.Substring(1, i - 1); } else { i = streamName.IndexOf('\0'); if (i > -1) { streamName = streamName.Substring(1, i - 1); } } contentInfos.Add(new ContentInfo(streamName, sid.Size.ToInt64())); } finally { Marshal.FreeHGlobal(pName); } } // Skip the stream contents var l = 0; var h = 0; shouldContinue = Kernel32.BackupSeek(hFile, sid.Size.Low, sid.Size.High, ref l, ref h, ref context); } else { break; } } } finally { Kernel32.CloseHandle(hFile); } foreach (var contentInfo in contentInfos) { yield return(contentInfo); } }