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); + |