OK, we have found something interesting. When we mount our filesystem with the MNT_LOCAL flag, the NSURLVolumeMaximumFileSizeKey starts reporting correctly.

Do you have any thoughts on why it works only with MNT_LOCAL? Using MNT_LOCAL might be a workaround for us, but I'm not sure of the implications of doing so as our filesystem is actually remote. How do AFP, NFS, SMB, etc. do it, as they don't have the local flag set?

Scott

On Mon, 10 Apr 2017, Jim Luther wrote:

How big is the file you are attempting to copy? Your hunch is probably correct. I think the Finder stops at 3.999... GB if the file system doesn't report NSURLVolumeMaximumFileSizeKey.

- Jim

On Apr 10, 2017, at 7:07 AM, Scott Talbert <s...@techie.net> wrote:

Still trying to sort this out, but not having any luck.

The real problem I'm trying to solve is this error message from Finder:

The item "<filename>" can't be copied because it is too large for the volume's 
format

Do you know under what conditions Finder will produce this error message? My 
hunch has been that it is related to the NSURL result, but strangely, we only 
see this Finder error consistently on one specific machine.

On Wed, 5 Apr 2017, Jim Luther wrote:

No. Immutable properties and capabilities like NSURLVolumeMaximumFileSizeKey 
are cached by coreservicesd on macos. The URL methods only remove cached values 
from the URL object.

On Apr 5, 2017, at 6:29 AM, Scott Talbert <s...@techie.net> wrote:

Do -[NSURL removeCachedResourceValueForKey:] and -[NSURL 
removeAllCachedResourceValues] clear the cached information in this case? It 
doesn't seem that they do.

Scott

On Mon, 3 Apr 2017, Scott Talbert wrote:

It sure sounds that way.  However, I haven't been able to spot a problem in the 
FUSE kext thus far.  It seems to be setting VOL_CAP_FMT_2TB_FILESIZE when it 
should be.

On Mon, 3 Apr 2017, Jim Luther wrote:


    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.co
                            m

                            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