tags:

views:

1069

answers:

5

How would I create/ delete/ read/ write/ NTFS alternate data streams from .NET?

If there is no native .NET support, which Win32 API's would I use? Also, how would I use them, as I don't think this is documented?

+1  A: 

Not in .NET:

http://support.microsoft.com/kb/105763

#include <windows.h>
   #include <stdio.h>

   void main( )
   {
      HANDLE hFile, hStream;
      DWORD dwRet;

      hFile = CreateFile( "testfile",
                       GENERIC_WRITE,
                    FILE_SHARE_WRITE,
                                NULL,
                         OPEN_ALWAYS,
                                   0,
                                NULL );
      if( hFile == INVALID_HANDLE_VALUE )
         printf( "Cannot open testfile\n" );
      else
          WriteFile( hFile, "This is testfile", 16, &dwRet, NULL );

      hStream = CreateFile( "testfile:stream",
                                GENERIC_WRITE,
                             FILE_SHARE_WRITE,
                                         NULL,
                                  OPEN_ALWAYS,
                                            0,
                                         NULL );
      if( hStream == INVALID_HANDLE_VALUE )
         printf( "Cannot open testfile:stream\n" );
      else
         WriteFile(hStream, "This is testfile:stream", 23, &dwRet, NULL);
   }
Otávio Décio
Two missing CloseHandle calls... OS will clean up, but would be a problem in a real application.
Richard
@Richard - just copied from MS's support site...
Otávio Décio
+3  A: 

Here is a version for C#

class Program
{
    static void Main(string[] args)
    {
        var mainStream = NativeMethods.CreateFileW(
            "testfile",
            NativeConstants.GENERIC_WRITE,
            NativeConstants.FILE_SHARE_WRITE,
            IntPtr.Zero,
            NativeConstants.OPEN_ALWAYS,
            0,
            IntPtr.Zero);

        var stream = NativeMethods.CreateFileW(
            "testfile:stream",
            NativeConstants.GENERIC_WRITE,
            NativeConstants.FILE_SHARE_WRITE,
            IntPtr.Zero,
            NativeConstants.OPEN_ALWAYS,
            0,
            IntPtr.Zero);
    }
}

public partial class NativeMethods
{

    /// Return Type: HANDLE->void*
    ///lpFileName: LPCWSTR->WCHAR*
    ///dwDesiredAccess: DWORD->unsigned int
    ///dwShareMode: DWORD->unsigned int
    ///lpSecurityAttributes: LPSECURITY_ATTRIBUTES->_SECURITY_ATTRIBUTES*
    ///dwCreationDisposition: DWORD->unsigned int
    ///dwFlagsAndAttributes: DWORD->unsigned int
    ///hTemplateFile: HANDLE->void*
    [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "CreateFileW")]
    public static extern System.IntPtr CreateFileW([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string lpFileName, uint dwDesiredAccess, uint dwShareMode, [System.Runtime.InteropServices.InAttribute()] System.IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, [System.Runtime.InteropServices.InAttribute()] System.IntPtr hTemplateFile);

}


public partial class NativeConstants
{

    /// GENERIC_WRITE -> (0x40000000L)
    public const int GENERIC_WRITE = 1073741824;

    /// FILE_SHARE_DELETE -> 0x00000004
    public const int FILE_SHARE_DELETE = 4;

    /// FILE_SHARE_WRITE -> 0x00000002
    public const int FILE_SHARE_WRITE = 2;

    /// FILE_SHARE_READ -> 0x00000001
    public const int FILE_SHARE_READ = 1;

    /// OPEN_ALWAYS -> 4
    public const int OPEN_ALWAYS = 4;
}
JaredPar
Should be using a type derived from SafeHandle here, to ensure you clean up those file handles.
Richard
+3  A: 

There is no native .NET support for them. You have to use P/Invoke to call the native Win32 methods.

To create them, call CreateFile with a path like filename.txt:streamname. If you use the interop call that returns a SafeFileHandle, you can use that to construct a FileStream that you can then read & write to.

To list the streams that exist on a file, use FindFirstStreamW and FindNextStreamW (which exist only on Server 2003 and later - not XP).

I don't believe you can delete a stream, except by copying the rest of the file and leaving off one of the streams. Setting the length to 0 may also work, but I haven't tried it.

You can also have alternate data streams on a directory. You access them the same as with files - C:\some\directory:streamname.

Streams can have compression, encryption and sparseness set on them independent of the default stream.

Zack Elan
+1  A: 

You have ready to use library here on codeproject

SeeR
A: 

BTW, if you want to copy file(s) with standard file-copying progress dialog, you can't use ::SHFileOperation() - it does not work with AltDataStreams at all (checked on Windows 7). As for ::CopyFileEx(), it works in some cases (e.g. it can copy a file into AltDataStream while calling the progress callback), but it don't work in others.

Nishi