You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The issue is that the compiler wants to make sure that the values within these structures are always aligned on the proper boundary. Four-byte values should be at addresses divisible by 4, 8-byte values should be at boundaries divisible by 8, and so on. Now imagine what would happen if you were to create an array of Win32StreamID structures. All of the fields in the first instance of the array would be properly aligned. For example, since the Size field follows two 32-bit integers, it would be 8 bytes from the start of the array, perfect for an 8-byte value. However, if the structure were 20-bytes in size, the second instance in the array would not have all of its members properly aligned. The integer values would all be fine, but the long value would be 28 bytes from the start of the array, a value not evenly divisible by 8. To fix this, the compiler pads the structure to a size of 24, such that all of the fields will always be properly aligned (assuming the array itself is). If the compiler's doing the right thing, you might be wondering why I'm concerned about this. You'll see why if you look at the code in Figure 2. In order to get around the first marshaling issue I described, I do in fact leave the cStreamName out of the Win32StreamID structure. I use BackupRead to read in enough bytes to fill my Win32StreamID structure, and then I examine the structure's dwStreamNameSize field. Now that I know how long the name is, I can use BackupRead again to read in the string's value from the file. That's all well and dandy, but if Marshal.SizeOf returns 24 for my Win32StreamID structure instead of 20, I'll be attempting to read too much data. To avoid this, I need to make sure that the size of Win32StreamID is in fact 20 and not 24. This can be accomplished in two different ways using fields on the StructLayoutAttribute that adorns the structure. The first is to use the Size field, which dictates to the runtime exactly how big the structure should be:
[StructLayout(LayoutKind.Sequential, Size = 20)]
The second option is to use the Pack field. Pack indicates the packing size that should be used when the LayoutKind.Sequential value is specified and controls the alignment of the fields within the structure. The default packing size for a managed structure is 8. If I change that to 4, I get the 20-byte structure I'm looking for (and as I'm not actually using this in an array, I don't lose efficiency or stability that might result from such a packing change):
[StructLayout(LayoutKind.Sequential, Pack = 4)]
Expected behavior
structure must be declared as:
[StructLayout (LayoutKind.Sequential, Pack = 4)]
public struct WIN32_STREAM_ID
{
public Kernel32.BACKUP_STREAM_ID dwStreamId;
public Kernel32.BACKUP_STREAM_ATTR dwStreamAttributes;
public long Size;
public uint dwStreamNameSize;
// WCHAR cStreamName[1];
}
or
[StructLayout (LayoutKind.Sequential, Size = 20)]
public struct WIN32_STREAM_ID
{
public Kernel32.BACKUP_STREAM_ID dwStreamId;
public Kernel32.BACKUP_STREAM_ATTR dwStreamAttributes;
public long Size;
public uint dwStreamNameSize;
// WCHAR cStreamName[1];
}
The text was updated successfully, but these errors were encountered:
I'm not sure I agree. Using the C++ compiler, both 32 and 64-bit versions of the structure are 24 bytes with an 8 byte alignment. The actual structure only consumes 22 bytes. If size is set to 20, then the cStreamName will never be carried. This deserves more investigation and testing.
I would use it as follows (not tested as I don't have a tape drive):
usingvarhFile=CreateFile(...);usingSafeHGlobalMemoryHandlemem=new(4096);// use appropriate size hereboolret=BackupRead(hFile,mem,mem.Size,outvarbytesRead,false,false,outvarctx);WIN32_STREAM_IDid=mem.ToStructure<WIN32_STREAM_ID>();
Describe the bug and how to reproduce
currently declared WIN32_STREAM_ID has size = 24 byte, which makes it impossible to use it in Kernel32.BackupRead to read NTFS file streams.
Correct size must be 20 bytes.
Problem is well described in https://stackoverflow.com/questions/604960/how-to-read-and-modify-ntfs-alternate-data-streams-using-net
Expected behavior
structure must be declared as:
or
The text was updated successfully, but these errors were encountered: