statfs() in 64 bit trickery

This makes no sense to me:

When building for 32 bit, I can pass an object of type MemoryBlock to a function parameter of type “Ptr” and it works as expected: The function receives the address of where the Memoryblock’s content begins.

But when I compile the same for 64 bit, the function appears to get an address that lies 16 byte PAST of where the content starts.

Here’s a real life example, which I need to enquire the number of files+folders on a Mac volume:

[code] declare function statfs lib “System.framework” (path as CString, dataOut as Ptr) as Integer

dim d as new MemoryBlock (2168)
if statfs (dir.POSIXPath, d) = 0 then
dim files, ffree as UInt64

#if Target64Bit
  const fix = 16
  files = d.UInt64Value(32+fix)
  ffree = d.UInt64Value(40+fix)
  files = d.UInt32Value(24)
  ffree = d.UInt32Value(28)

nodes = files - ffree
return true

end if

I have verified the data offsets with a similar test project in Xcode: offsetof(struct statfs, f_files) is 32 indeed. But I have to add 16 to it in Xojo to get the right value. Viewing the MemoryBlock in the debugger also shows that there are 16 bytes in front of the structure that are not filled by the statfs() function. All values are offset by 16 byte.

What’s going on?

I’ve tried this with Xojo 2017r2 as well as with 2018r1.

Nevermind - it’s something else. Later offsets do move out even more, e.g. by 24 or 32 byte. Somehow, when I compile with Xojo for 64 bit, the statfs structure has a different layout than with Xcode building for 64 bit.

I still can’t make any sense of it, though.

Solved it: Apparently, there are many different versions of statfs (not just one each for 32 and 64 bit). The one I end up calling expects the “old” structure with the additional “f_otype” and “f_oflags” fields at the start, but the “long” type fields are all 64 bit long. In this case, that’s controlled by the appearance of the macro “__DARWIN_INODE64” in the function declaration of the C header.

So, for anyone else converting declares to 64 bit that use BSD (System.framework) level functions, consider the possibility that the structure layout in Xcode may not match the one you get in Xojo.

I was curious about this. I found that the stat man page 2 gives some information about the DARVIN INODE macros. See “man -s2 stat”.

Good find - I’d have to call statfs64() in order to use the statfs64 struct.

This is why I mask all of these multi-platform POSIX-y functions in wrappers. My s_statfs() contains tests for the endian-ness and the stat struct size, and then maps the resulting values into my version of the stat struct. I learned this back when we were still dealing with 8bit, Motorola and Zilog processors. By doing things this way, we were able to move our core code from 8 to 16 to 32 to 64 and even 128bit for a custom super computer OS from the 90s.

This is also why I diodn’t have to worry about the Y2K debacle.