How to read and modify NTFS Alternate Data Streams using .NET
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);
}
Working C# Example: Writing & Reading NTFS Alternate Data Stream Under Win7 64 bit
I've had success on Windows 7 x64 using this library:
https://github.com/hubkey/Trinet.Core.IO.Ntfs
I can't find my old code, and the documentation page I have bookmarked is down at the moment, so I'll try to post some code when it's back up if you're still having problems.
Edit:
Apparently it's as simple as:
using Trinet.Core.IO.Ntfs;
var fileInfo = new FileInfo(@"C:\path\to\file.dat");
if (AlternateDataStreamExists("MyStreamName"))
{
var alternateStream = fileInfo.GetAlternateDataStream("MyStreamName").OpenRead();
}
else
{
var alternateStream = fileInfo.GetAlternateDataStream("MyStreamName").OpenWrite();
}
Accessing alternate data streams in files
Unfortunately no, there is still no access via a managed .Net Framework API.
Update
Here's a library\source for an ADS access wrapper:
http://www.codeproject.com/KB/cs/ntfsstreams.aspx
How do I read Windows NTFS's Alternate Data Stream using Java's IO?
I was able to read the ADS of a file simply by opening the the file with the syntax "file_name:stream_name". So if you've done this:
C:>echo Hidden text > test.txt:hidden
Then you should be able to do this:
package net.snortum.play;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class AdsPlay {
public static void main(String[] args) {
new AdsPlay().start();
}
private void start() {
File file = new File("test.txt:hidden");
try (BufferedReader bf = new BufferedReader( new FileReader(file))) {
String hidden = bf.readLine();
System.out.println(hidden);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you want to get the ADS data from the dir /r
command, I think you just need to execute a shell and capture the output:
package net.snortum.play;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ExecPlay {
public static void main(String[] args) {
new ExecPlay().start();
}
private void start() {
String fileName = "not found";
String ads = "not found";
final String command = "cmd.exe /c dir /r"; // listing of current directory
final Pattern pattern = Pattern.compile(
"\\s*" // any amount of whitespace
+ "[0123456789,]+\\s*" // digits (with possible comma), whitespace
+ "([^:]+):" // group 1 = file name, then colon
+ "([^:]+):" // group 2 = ADS, then colon
+ ".+"); // everything else
try {
Process process = Runtime.getRuntime().exec(command);
process.waitFor();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
fileName = matcher.group(1);
ads = matcher.group(2);
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(fileName + ", " + ads);
}
}
Now you can use the first code listing to print the ADS data.
How to add a custom property in a file in .Net?
You could consider using ADS (alternate data streams) which is an NTFS feature. ADS allow you to attach content to files on NTFS file systems. From the point-of-view of the user, there is a single file, but this file may have additional streams attached to it which will not be visible from Explorer for example. When the file is copied directly between NTFS file systems, the streams get copied too.
Alternate data streams are used by the OS to tag files with information such as what zone a file arrived from (e.g. the internet) and this drives security warning dialogs in such cases.
An example of using streams from C# can be found here:
NTFS Alternate Data Streams - .NET
Pros:
- No loose files containing your extra meta-data.
- When files are copied on NTFS file systems, streams are automatically copied.
Cons:
- Only works on NTFS e.g. not FAT32.
- If a file is copied onto another file system format, streams are lost.
- If a file is packaged via some other fornat (e.g. as an email attachment) the streams may be lost.
reading alternative streams results into NullReferenceException
CreateFileW
does not return a pointer to some memory location, it returns a handle. To work with that, you need FileStream
, not UnmanagedMemoryStream
:
using (var stream = new FileStream(mainStream, FileAccess.Read))
Though this overload of the constructor is obsolete, you should use SafeFileHandle
instead of IntPtr
(and make sure to Dispose
it):
[CLSCompliant(false)]
[DllImport("kernel32.dll", EntryPoint = "CreateFileW")]
public static extern SafeFileHandle CreateFileW(
[In] [MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
[In] IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
[In] IntPtr hTemplateFile
);
Also, I don't know anything about Zone.Identifier
, but for me the stream doesn't contain a single character, like you seem to be expecting, it contains:
[ZoneTransfer]
ZoneId=3
To get to that, you can wrap the FileStream
in a StreamReader
. So, the whole code to get the above string is:
using (var streamHandle = NativeMethods.CreateFileW(
@"<path to batch file directory>any.bat:Zone.Identifier",
NativeConstants.GENERIC_READ, NativeConstants.FILE_SHARE_READ,
IntPtr.Zero, NativeConstants.OPEN_EXISTING, 0, IntPtr.Zero))
using (var stream = new FileStream(streamHandle, FileAccess.Read))
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
Related Topics
What Is the Use of "Ref" for Reference-Type Variables in C#
What's the Point of the Var Keyword
Catch Exception That Is Thrown in Different Thread
At the End of an Async Method, Should I Return or Await
Difference Between Events and Delegates and Its Respective Applications
How to Set Session Timeout in Web.Config
Transparent Background Image for Form - Smooth Edge Shape for the Form
Using Global Keyboard Hook (Wh_Keyboard_Ll) in Wpf/C#
Is It Bad to Not Unregister Event Handlers
Executenonquery: Connection Property Has Not Been Initialized
Programmatically Determine a Duration of a Locked Workstation
How to Assign by "Reference" to a Class Field in C#
How Do Arrays in C# Partially Implement Ilist<T>
What Operations Are Atomic in C#
Type or Namespace Name Does Not Exist
Concurrent Hashset<T> in .Net Framework
Should I Use Public Properties and Private Fields or Public Fields for Data