IBM i Global

IBM i Global

Connect, learn, share, and engage with IBM Power.

 View Only

PASE for i on IBM i 7.5: fstatat, openat return -1 w/ errno == EINVAL

  • 1.  PASE for i on IBM i 7.5: fstatat, openat return -1 w/ errno == EINVAL

    Posted Wed February 07, 2024 10:40 AM

    I have a library that uses fstatat to open a directory, and then stat a path relative to that directory using code resembling the following:

    int fd = open("/some/directory", O_DIRECTORY);
    if (-1 == fd) {
       // handle error
       return;
    }
    
    struct stat st = {0};
    if (-1 == fstatat(fd, "./file_in_dir", &st, AT_SYMLINK_NOFOLLOW)) {
        // handle error
    }
    
    close(fd);

    I am able to enumerate the contents of the directory using fdopendir / readdir, so I know I have a valid directory file descriptor. Regardless, no matter what I try, I always get a -1 return value from fstatat (and openat) with errno == EINVAL (22).

    According to the IBM documentation, fstatat can result in EINVAL when the flags are invalid. Having discovered this, I grepped the system headers for AT_SYMLINK_NOFOLLOW and found the following:

    #if (_XOPEN_SOURCE >= 700) || defined(_KERNEL)
    #define AT_FDCWD                (-2)    /* Use the current working
                                             * directory to determine the
                                             * beginning of relative file
                                             * paths.                       */
    #define AT_EACCESS              1       /* Check access using effective
                                             * user and group ID.           */
    #define AT_SYMLINK_NOFOLLOW     1       /* Do not follow symbolic links */
    #define AT_SYMLINK_FOLLOW       2       /* Follow symbolic links        */
    #define AT_REMOVEDIR            1       /* Remove the directory entry
                                             * specified by fd and path as
                                             * a directory, not a normal
                                             * file.                        */
    #endif

    Now, I may be off-base, but doesn't this seem like no matter what value you pass for flags, it is invalid because AT_REMOVEDIR is the same value as AT_EACCESS and AT_SYMLINK_NOFOLLOW? Even if that isn't the case, I still haven't made it work.

    I have tried every permutation of flags, trailing slashes, no trailing slashes, dot-slash prefix, no dot-slash prefix, etc. This code works correctly on every single platform we've encountered to date, and that is not an insignificant number.

    I have been trying to figure this out for many hours now, so I am resorting to asking here. Anyone out there have a clue?



    ------------------------------
    Jeff Johnson
    ------------------------------