As I want to do porting to windows from Linux. I realized that Windows and Linux API both has stat.h but with kind of differences. The problem is that Windows stat.h does not have st_blksize variable but Linux does. I does not really understand what st_blksize can do also. Can anyone help me cope with this ? How to find the equivalent of st_blksize on Windows ?
-
1I always use a fixed-size multiple of 512 on Windows. You can probably get the disks actual block-size from the WIN32 API, but I would guess it will be kind of messy. – Some programmer dude Jan 06 '15 at 09:51
-
It depends on which block size you are interested in (logical or physical). You can query the logical block size using [IOCTL_DISK_GET_DRIVE_GEOMETRY](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365169.aspx), or the physical block size using [IOCTL_STORAGE_QUERY_PROPERTY](http://msdn.microsoft.com/en-us/library/ff560590.aspx) with a [STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR](http://msdn.microsoft.com/en-us/library/ff800831.aspx). – IInspectable Jan 06 '15 at 13:27
-
Extensive information can be found at [Advanced format (4K) disk compatibility update](http://msdn.microsoft.com/en-us/library/windows/desktop/hh848035.aspx). – IInspectable Jan 06 '15 at 13:28
-
@IInspectable It seems that Microsoft refers to blocks as "sectors"? I also think that wmi would be preferable to fsutil for retrieving information since it doesn't require administrator access. – Jonathan Mee Jan 06 '15 at 13:40
-
@Jon: The preferred solution in this scenario is [DeviceIoControl](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363216.aspx). WMI is more appropriate in scripting environments. fsutil is meant for humans, exclusively. You don't go parsing text output that can change over time, only to see your application stop working. – IInspectable Jan 06 '15 at 13:53
-
@IInspectable That makes sense, but I can't see how to get to a logical sector size from there. (Even though I'm pretty sure it's always 512 on Windows.) – Jonathan Mee Jan 06 '15 at 13:55
-
@Jon: Using `IOCTL_DISK_GET_DRIVE_GEOMETRY` will always return the logical (or emulated) sector size. It may have always been 512, but I cannot foresee the future. – IInspectable Jan 06 '15 at 13:58
-
@IInspectable It appears that what we should really be trying to retrieve is the [`DISK_GEOMETRY`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363972.aspx) struct's `BytesPerSector`. Though I'm uncertain how to retrieve that programmatically. If you know how, it might be worth posting an answer? – Jonathan Mee Jan 06 '15 at 14:04
2 Answers
For the Linux struct definition go here: http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysstat.h.html
The primary excerpts:
st_size
: File size in bytes (if file is a regular file)st_blksize
: A filesystem-specific preferred I/O block size for this object. In some filesystem types, this may vary from file to filest_blocks
: Number of blocks allocated for this object
It's pretty clear to see that st_size
should equal st_blksize * st_blocks
for regular files.
For your cross platform code you're going to want to #ifdef
anything that works with st_blksize
or st_blocks
. Or preferably you can just use st_size
everywhere in your code.
Further reading: https://groups.google.com/forum/#!topic/comp.unix.programmer/7saTJ9gRBEM
EDIT in response to IInspectable:
The block size on Windows should be 512, but if you need to validate, you can use the GetDriveGeometry
function from here to get a DISK_GEOMETRY*
.
DISK_GEOMETRY
's BytesPerSector
will give you the equivalent of st_blksize
.
Note the use of GetDriveGeometry
's use of CreateFileW
is unnecessary for most applications. So you can probably replace it with CreateFile
and adjust GetDriveGeometry
to just accept a good old ASCII path.
If you still need to get st_blocks
you can obtain this from the ceiling of st_size
over BytesPerSector
.
EDIT to update with respect to the Filesystem TS:
For the typical programming application all that is needed is the size of the file. The Filesystem TS now provides a cross platform way to obtain file size in the form of file_size
.
ofstream("foo.txt") << "lorem ipsum";
cout << experimental::filesystem::file_size("foo.txt") << endl; // Prints 11
Unfortunately experimental/filesystem
will not be included until GCC 5.3, however since the Filesystem TS "is directly based on boost.filesystem," experimentation in Boost may be an alternative: http://coliru.stacked-crooked.com/a/7b143609e6922774

- 1
- 1

- 37,899
- 23
- 129
- 288
-
@Davy I've edited to fill out the solution if this doesn't solve your problem let me know, otherwise please accept. – Jonathan Mee Jan 06 '15 at 15:38
-
There is no *good old ASCII* in the Windows API (with very few exceptions like [GetProcAddress](http://msdn.microsoft.com/en-us/library/windows/desktop/ms683212.aspx)). Windows NT has always been Unicode, and calling the ANSI version will internally convert to Unicode anyway. In addition, using `CreateFile` requires a `TCHAR`, or the use of the `_T`-macro, which is hardly an improvement. It's best to stick with explicit Unicode calls, i.e. `CreateFileW` with a Unicode string parameter. – IInspectable Jan 09 '15 at 20:54
-
@IInspectable I was saying this with respect to the call to [`CreateFile`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx) in `GetDriveGeometry`. My understanding was that `CreateFileA` was just a version that took a pointer to a regular old ASCII string, after looking at it however, the "A" there stands for ANSI. I am not greatly familiar with any of this so I'll deffer to your judgement. You thinkn it would be safer to stick to `CreateFileW`? – Jonathan Mee Jan 10 '15 at 04:04
-
`CreateFileA` roughly performs the following operations: It allocates a `wchar_t` buffer, converts the pathname argument to Unicode, and calls `CreateFileW`. This adds overhead and is needlessly complex. The ANSI versions are really just there to ease porting of old code that was written for Win9x. Today, calling the wide character version is always the right thing to do. It may not be safer, but could be more reliable: If at some point the pathname winds up with characters outside the ASCII range, the conversion performed by `CreateFileA` may appear to fail on some systems. – IInspectable Jan 10 '15 at 10:51
-
`It's pretty clear to see that st_size should equal st_blksize * st_blocks for regular files`=>Not true. `st_blksize` is not the size of blocks in `st_blocks`, it is something else (optimal block size for IO). On Linux+macOS, `st_blocks` is always in 512 byte units, `st_blksize` is often nowadays 4096. Also `st_size` can be massively bigger than `st_blocks*512` for sparse files. Closest Windows equivalent is actually `GetCompressedFileSize[AW]`, which gives actual file size on disk (despite name, works for sparse files, not just compressed). Divide that by 512 and round up to get `st_blocks` – Simon Kissane Jan 28 '23 at 03:17
I know that this question is quite old but nobody mentioned the FILE_STORAGE_INFO structure and its "PhysicalBytesPerSectorForAtomicity" and "PhysicalBytesPerSectorForPerformance" fields that could (maybe ? idk) be usefull and answer to the question.
I'm far from sure but since cppreference states that the "optimal block size" is st_blksize, I'm really wondering if this is not one of the closest WIN API equivalent.
(Of course tell me if I'm wrong, I do not have enough reputation to write this in just a comment but I still think this is the good place to write this)

- 3
- 3