Thursday 22 October 2009

NTFS streams in .net

NTFS streams cannot be opened directly with regular .Net file IO classes, they throw a "System.NotSupportedException: The given path's format is not supported" exception. Here is a C# code sample demonstrating a work-around to the "cannot open NTFS streams in .net (using regular classes)" problem...
using System;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;

namespace NTFSStreams
{
    class Program
    {
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern SafeFileHandle CreateFile(
        string fileName,
        [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
        [MarshalAs(UnmanagedType.U4)] FileShare fileShare,
        IntPtr securityAttributes,
        [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
        [MarshalAs(UnmanagedType.U4)] FileAttributes flags,
        IntPtr template);



        static void Main(string[] args)
        {

            //Note the special file name construct used to specify the NTFS stream
            const string fileName = "test.txt:stream1";

            //Yes we are going to use CreateFile to bypass the awkward restrictions
            //imposed by the .net file IO classes
            SafeFileHandle handle = CreateFile(fileName
            , FileAccess.ReadWrite
            , FileShare.Read
            , IntPtr.Zero
            , FileMode.OpenOrCreate
            , FileAttributes.Normal
            , IntPtr.Zero);

            if (handle.IsInvalid)
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

            //Open a .net stream for writing.
            //We will close it here before reading for demonstration purposes
            using (FileStream stream = new FileStream(handle, FileAccess.ReadWrite))
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.Write("Hello world!");
                }
            }


            //Note: The file handle returned by the call to CreateFile is closed 
            //by the SafeFileHandle wrapper around it hence we need to reopen the
            //file here.
            //Alternatively you could have reset the file stream position and 
            //opened a StreamReader on the above FileStream itself.
            handle = CreateFile(fileName
            , FileAccess.Read
            , FileShare.Read
            , IntPtr.Zero
            , FileMode.Open
            , FileAttributes.Normal
            , IntPtr.Zero);

            using (FileStream stream = new FileStream(handle, FileAccess.Read))
            {
                using (StreamReader reader = new StreamReader(stream))
                {
                    while (!reader.EndOfStream)
                    {
                        Console.WriteLine(reader.ReadLine());
                    }
                }
            }
        }
    }
}



References

No comments:

Post a Comment