diff options
Diffstat (limited to 'api/src/glfs-fops.c')
| -rw-r--r-- | api/src/glfs-fops.c | 137 | 
1 files changed, 136 insertions, 1 deletions
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index 0e5b206b98c..1bb958fc1b7 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -2792,7 +2792,7 @@ glfd_entry_next (struct glfs_fd *glfd, int plus)  } -static struct dirent * +struct dirent *  glfs_readdirbuf_get (struct glfs_fd *glfd)  {          struct dirent *buf = NULL; @@ -4608,3 +4608,138 @@ out:  invalid_fs:          return ret;  } + +/* + * Given glfd of a directory, this function does readdirp and returns + * xstat along with dirents. + */ +int +pub_glfs_xreaddirplus_r (struct glfs_fd *glfd, uint32_t flags, +                         struct glfs_xreaddirp_stat **xstat_p, +                         struct dirent *ext, +                         struct dirent **res) +{ +        int              ret = -1; +        gf_dirent_t     *entry = NULL; +        struct dirent   *buf = NULL; +        struct glfs_xreaddirp_stat *xstat = NULL; + +        DECLARE_OLD_THIS; +        __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs); + +        GF_REF_GET (glfd); + +        GF_VALIDATE_OR_GOTO (THIS->name, xstat_p, out); +        GF_VALIDATE_OR_GOTO (THIS->name, res, out); + +        errno = 0; + +        if (ext) +                buf = ext; +        else +                buf = glfs_readdirbuf_get (glfd); + +        if (!buf) +                goto out; + +        xstat = GF_CALLOC(1, sizeof(struct glfs_xreaddirp_stat), +                          glfs_mt_xreaddirp_stat_t); + +        if (!xstat) +                goto out; + +        /* this is readdirplus operation */ +        entry = glfd_entry_next (glfd, 1); + +        /* XXX: Ideally when we reach EOD, errno should have been +         * set to ENOENT. But that doesn't seem to be the case. +         * +         * The only way to confirm if its EOD at this point is that +         * errno == 0 and entry == NULL +         */ +        if (errno) +                goto out; + +        if (!entry) { +                /* reached EOD, ret = 0  */ +                ret = 0; +                *res = NULL; +                goto out; +        } + +        *res = buf; +        gf_dirent_to_dirent (entry, buf); + +        if (flags & GFAPI_XREADDIRP_STAT) { +                glfs_iatt_to_stat (glfd->fs, &entry->d_stat, &xstat->st); +                xstat->flags_handled |= GFAPI_XREADDIRP_STAT; +        } + +        if ((flags & GFAPI_XREADDIRP_HANDLE) && +                /* skip . and .. */ +                strcmp(buf->d_name, ".") +                     && strcmp(buf->d_name, "..")) { + +                /* Now create object. +                 * We can use "glfs_h_find_handle" as well as inodes would have +                 * already got linked as part of 'gf_link_inodes_from_dirent' */ +                xstat->object = glfs_h_create_from_handle (glfd->fs, +                                                        entry->d_stat.ia_gfid, +                                                        GFAPI_HANDLE_LENGTH, +                                                        NULL); + +                if (xstat->object) { /* success */ +                        /* note: xstat->object->inode->ref is taken +                         * This shall be unref'ed when application does +                         * glfs_free(xstat) */ +                        xstat->flags_handled |= GFAPI_XREADDIRP_HANDLE; +                } +        } + +        ret = xstat->flags_handled; +        *xstat_p = xstat; + +out: +        gf_msg_debug (THIS->name, 0, +                      "xreaddirp- requested_flags (%x) , processed_flags (%x)", +                      flags, xstat->flags_handled); + +        GF_REF_PUT (glfd); + +        if (ret < 0) { +                gf_msg (THIS->name, GF_LOG_WARNING, errno, +                        API_MSG_XREADDIRP_R_FAILED, +                        "glfs_x_readdirp_r failed - reason (%s)", +                        strerror(errno)); + +                if (xstat) +                        glfs_free (xstat); +        } + +        __GLFS_EXIT_FS; + +        return ret; + +invalid_fs: +        return -1; +} +GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_xreaddirplus_r, 3.11.0); + +struct stat* +pub_glfs_xreaddirplus_get_stat (struct glfs_xreaddirp_stat *xstat) +{ +        GF_VALIDATE_OR_GOTO ("glfs_xreaddirplus_get_stat", xstat, out); + +        if (!xstat->flags_handled & GFAPI_XREADDIRP_STAT) +                gf_msg (THIS->name, GF_LOG_ERROR, errno, +                        LG_MSG_INVALID_ARG, +                        "GFAPI_XREADDIRP_STAT is not set. Flags" +                        "handled for xstat(%p) are (%x)", +                        xstat, xstat->flags_handled); +        return &xstat->st; + +out: +        return NULL; +} +GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_xreaddirplus_get_stat, 3.11.0); +  | 
