On Mar 31, 2017, at 5:10 PM, Scott Talbert <email@hidden> wrote:
Thanks for the information. Unfortunately, that leaves me even more
confused as, using that code, I get the correct answer:
#include <sys/attr.h>
#include <sys/param.h>
#include <sys/mount.h>
#import <Foundation/Foundation.h>
int getMaxFileSize(const char *path, int64_t *maxFileSize)
{
int result;
struct statfs statfsBuf;
// get the file system's mount point path for the input path
result = statfs(path, &statfsBuf);
if ( result == 0 ) {
long fileSizeBits = pathconf(statfsBuf.f_mntonname,
_PC_FILESIZEBITS);
if (fileSizeBits == -1) {
// if _PC_FILESIZEBITS isn't supported, check for
VOL_CAP_FMT_2TB_FILESIZE
bool fileSystemSupports2TBFileSize = false;
// get the supported capabilities
struct attrlist attrList;
struct volCapabilitiesBuf {
u_int32_t length;
vol_capabilities_attr_t capabilities;
} __attribute__((aligned(4), packed));
struct volCapabilitiesBuf volCaps;
memset(&attrList, 0, sizeof(attrList));
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
result = getattrlist(statfsBuf.f_mntonname, &attrList,
&volCaps, sizeof(volCaps), 0);
if ( result == 0 ) {
fileSystemSupports2TBFileSize =
((volCaps.capabilities.capabilities[VOL_CAPABILITIES_FORMAT]
& VOL_CAP_FMT_2TB_FILESIZE) &&
(volCaps.capabilities.valid[VOL_CAPABILITIES_FORMAT] &
VOL_CAP_FMT_2TB_FILESIZE));
}
if ( fileSystemSupports2TBFileSize ) {
// use Supports2TBFileSize
*maxFileSize = LONG_LONG_MAX;
}
else {
// otherwise, we don't know
*maxFileSize = -1LL;
}
}
else if ( fileSizeBits > 64 ) {
// off_t is signed long long, so it cannot be more than
LONG_LONG_MAX
*maxFileSize = LONG_LONG_MAX;
}
else if ( fileSizeBits < 32 ) {
// POSIX spec says 'Minimum Acceptable Value: 32' for
FILESIZEBITS
*maxFileSize = INT_MAX;
}
else {
// 32...64 bits: shift off the bits we don't need
*maxFileSize = (int64_t)((u_int64_t)0xffffffffffffffffLL >>
(u_int64_t)(65 - fileSizeBits));
}
}
return result;
}
int main()
{
const char *mount = "/Volumes/Filesystem";
int64_t maxFileSize;
int ret1 = getMaxFileSize(mount, &maxFileSize);
NSLog(@"getMaxFileSize %d %lld", ret1, maxFileSize);
NSString *path = [NSString stringWithUTF8String:mount];
NSURL *url = [NSURL fileURLWithPath:path];
NSNumber *maxfilesize;
NSError *error;
BOOL ret = [url getResourceValue:&maxfilesize
forKey:NSURLVolumeMaximumFileSizeKey error:&error];
NSLog(@"NSURLVolumeMaximumFileSize: %d %@ %@", ret, maxfilesize, error);
}
$ ./blahm
2017-03-31 20:04:34.358 blahm[45735:2028260] getMaxFileSize 0
9223372036854775807
2017-03-31 20:04:34.365 blahm[45735:2028260] NSURLVolumeMaximumFileSize: 1
(null) (null)
As -[NSURL getResourceValue:forKey:error:] is documented, "If this method
returns YES and the value is populated with nil, it means that the
resource property is not available for the specified resource, and that no
errors occurred when determining that the resource property was
unavailable." So YES and nil is a valid response.
The NSURLVolumeMaximumFileSizeKey property value comes from two sources:
pathconf() with _PC_FILESIZEBITS, or from getattrlist() from the
ATTR_VOL_CAPABILITIES attribute and the VOL_CAP_FMT_2TB_FILESIZE
capability.
Here's code (not the real code but the exact same algorithm) that shows
how the value is calculated:
int getMaxFileSize(const char *path, int64_t *maxFileSize)
{
int result;
struct statfs statfsBuf;
// get the file system's mount point path for the input path
result = statfs(path, &statfsBuf);
if ( result == 0 ) {
long fileSizeBits = pathconf(statfsBuf.f_mntonname,
_PC_FILESIZEBITS);
if (fileSizeBits == -1) {
// if _PC_FILESIZEBITS isn't supported, check for
VOL_CAP_FMT_2TB_FILESIZE
bool fileSystemSupports2TBFileSize = false;
// get the supported capabilities
struct attrlist attrList;
struct volCapabilitiesBuf {
u_int32_t length;
vol_capabilities_attr_t capabilities;
} __attribute__((aligned(4), packed));
struct volCapabilitiesBuf volCaps;
memset(&attrList, 0, sizeof(attrList));
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
result = getattrlist(statfsBuf.f_mntonname, &attrList,
&volCaps, sizeof(volCaps), 0);
if ( result == 0 ) {
fileSystemSupports2TBFileSize =
((volCaps.capabilities.capabilities[VOL_CAPABILITIES_FORMAT]
& VOL_CAP_FMT_2TB_FILESIZE) &&
(volCaps.capabilities.valid[VOL_CAPABILITIES_FORMAT] &
VOL_CAP_FMT_2TB_FILESIZE));
}
if ( fileSystemSupports2TBFileSize ) {
// use Supports2TBFileSize
*maxFileSize = LONG_LONG_MAX;
}
else {
// otherwise, we don't know
*maxFileSize = -1LL;
}
}
else if ( fileSizeBits > 64 ) {
// off_t is signed long long, so it cannot be more than
LONG_LONG_MAX
*maxFileSize = LONG_LONG_MAX;
}
else if ( fileSizeBits < 32 ) {
// POSIX spec says 'Minimum Acceptable Value: 32' for
FILESIZEBITS
*maxFileSize = INT_MAX;
}
else {
// 32...64 bits: shift off the bits we don't need
*maxFileSize = (int64_t)((u_int64_t)0xffffffffffffffffLL >>
(u_int64_t)(65 - fileSizeBits));
}
}
return result;
}
if NSURLVolumeMaximumFileSizeKey is returning nil with no errors,
maxFileSize is -1LL, and the only way maxFileSize will be -1LL is if
pathconf() returned an error, and the file system is saying
VOL_CAP_FMT_2TB_FILESIZE is not valid and set (capabilities).
Hope that helpsâ?¢
- Jim
On Mar 31, 2017, at 2:33 PM, Scott Talbert <email@hidden> wrote:
Hello,
Can anyone tell me why calling NSURL -getResourceValue:forKey:error:
with key NSURLVolumeMaximumFileSizeKey would return a nil resource value
for a given volume? The function returns YES and error is nil also.
I can see from running dtruss that it in turn calls getattrlist(). If I
call getattrlist() myself on the same volume, I can see the bits I would
think it is looking at are set correctly - VOL_CAP_FMT_2TB_FILESIZE.
Thanks,
Scott
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Filesystem-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden