> On Apr 3, 2017, at 8:56 AM, Scott Talbert <s...@techie.net> wrote:
> 
> It's getting a value from the getattrlist path.
> 
> The fact that the data is cached at mount time is an interesting clue. It 
> suggest that perhaps there may be some window just shortly after mount that 
> the incorrect data is getting reported and cached.
> 
> It's a FUSE filesystem.  However, some of the more commonly-used FUSE 
> filesystems (e.g., sshfs) seem to behave the same way.

That sounds like a bug in FUSE. Once a file system is mounted, the kernel sends 
out a VQ_MOUNT kernel event and that's what causes the kNotifyVFSMount BSD 
notification to be sent. At that time, file systems must be ready to respond to 
requests correctly. If they don't, they have a bug.

- Jim

> On Sat, 1 Apr 2017, Jim Luther wrote:
> 
>> Scott, if you walk through that code, do you see which path it's getting a 
>> value from -- pathconf or getattrlist?
>> 
>> The code in our frameworks that gets that value runs when a file system is 
>> first mounted. We have code listening for kNotifyVFSMount BSD notifications. 
>> When a notification comes in, we look to see what new volume(s) are 
>> available, and then collect and cache the volume's immutable properties 
>> (like this capability).
>> 
>> Knowing more about the file system (what file system type, how it's 
>> connected, etc) where you are seeing the problem might help diagnose things.
>> 
>> - Jim
>> 
>>> On Mar 31, 2017, at 5:10 PM, Scott Talbert <s...@techie.net> 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 <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