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 <s...@techie.net> 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      (Filesystem-dev@lists.apple.com)
>> Help/Unsubscribe/Update your Subscription:
>> https://lists.apple.com/mailman/options/filesystem-dev/luther.j%40apple.com
>>
>> This email sent to luthe...@apple.com
>
>


 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Filesystem-dev mailing list      (Filesystem-dev@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/filesystem-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to