From 144db7f39f35a51c24558c81faea3f49c237312f Mon Sep 17 00:00:00 2001 From: Anand Avati Date: Wed, 19 Sep 2012 16:37:34 -0700 Subject: gfapi: added more API calls - stat - lstat - access - readlink - mknod - mkdir - rmdir - symlink - rename - link - opendir - closedir - seekdir - telldir - readdir_r - statvfs - chmod - fchmod - chown - lchown - fchown - utimens - lutimens - futimens - getxattr - lgetxattr - fgetxattr - setxattr - lsetxattr - fsetxattr - listxattr - llistxattr - flistxattr - removexattr - lremovexattr - fremovexattr Change-Id: Ic2467293ddfbcefaa9b41c82cec61a5602636833 BUG: 839950 Signed-off-by: Anand Avati Reviewed-on: http://review.gluster.org/4022 Tested-by: Gluster Build System Reviewed-by: Amar Tumballi --- api/src/glfs-fops.c | 1331 +++++++++++++++++++++++++++++++++++++++++++++++ api/src/glfs-internal.h | 6 +- api/src/glfs.h | 81 +++ 3 files changed, 1416 insertions(+), 2 deletions(-) (limited to 'api') diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c index a6e2f1744e5..c9897243e52 100644 --- a/api/src/glfs-fops.c +++ b/api/src/glfs-fops.c @@ -119,6 +119,34 @@ out: } +int +glfs_stat (struct glfs *fs, const char *path, struct stat *stat) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + + if (ret == 0 && stat) + iatt_to_stat (&iatt, stat); +out: + loc_wipe (&loc); + + return ret; +} + + int glfs_fstat (struct glfs_fd *glfd, struct stat *stat) { @@ -183,6 +211,11 @@ glfs_creat (struct glfs *fs, const char *path, int flags, mode_t mode) if (!glfd) goto out; + /* This must be glfs_resolve() and NOT glfs_lresolve(). + That is because open("name", O_CREAT) where "name" + is a danging symlink must create the dangling + destinataion. + */ ret = glfs_resolve (fs, subvol, path, &loc, &iatt); if (ret == -1 && errno != ENOENT) /* Any other type of error is fatal */ @@ -825,3 +858,1301 @@ glfs_ftruncate_async (struct glfs_fd *glfd, off_t offset, return ret; } + +int +glfs_access (struct glfs *fs, const char *path, int mode) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + ret = syncop_access (subvol, &loc, mode); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_symlink (struct glfs *fs, const char *data, const char *path) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + + if (loc.inode) { + errno = EEXIST; + ret = -1; + goto out; + } + + if (ret == -1 && errno != ENOENT) + /* Any other type of error is fatal */ + goto out; + + if (ret == -1 && errno == ENOENT && !loc.parent) + /* The parent directory or an ancestor even + higher does not exist + */ + goto out; + + /* ret == -1 && errno == ENOENT */ + loc.inode = inode_new (loc.parent->table); + if (!loc.inode) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_symlink (subvol, &loc, data, xattr_req); +out: + loc_wipe (&loc); + + if (xattr_req) + dict_destroy (xattr_req); + + return ret; +} + + +int +glfs_readlink (struct glfs *fs, const char *path, char *buf, size_t bufsiz) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + if (iatt.ia_type != IA_IFLNK) { + ret = -1; + errno = EINVAL; + goto out; + } + + ret = syncop_readlink (subvol, &loc, &buf, bufsiz); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_mknod (struct glfs *fs, const char *path, mode_t mode, dev_t dev) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + + if (loc.inode) { + errno = EEXIST; + ret = -1; + goto out; + } + + if (ret == -1 && errno != ENOENT) + /* Any other type of error is fatal */ + goto out; + + if (ret == -1 && errno == ENOENT && !loc.parent) + /* The parent directory or an ancestor even + higher does not exist + */ + goto out; + + /* ret == -1 && errno == ENOENT */ + loc.inode = inode_new (loc.parent->table); + if (!loc.inode) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_mknod (subvol, &loc, mode, dev, xattr_req); +out: + loc_wipe (&loc); + + if (xattr_req) + dict_destroy (xattr_req); + + return ret; +} + + +int +glfs_mkdir (struct glfs *fs, const char *path, mode_t mode) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + uuid_t gfid; + dict_t *xattr_req = NULL; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + xattr_req = dict_new (); + if (!xattr_req) { + ret = -1; + errno = ENOMEM; + goto out; + } + + uuid_generate (gfid); + ret = dict_set_static_bin (xattr_req, "gfid-req", gfid, 16); + if (ret) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + + if (loc.inode) { + errno = EEXIST; + ret = -1; + goto out; + } + + if (ret == -1 && errno != ENOENT) + /* Any other type of error is fatal */ + goto out; + + if (ret == -1 && errno == ENOENT && !loc.parent) + /* The parent directory or an ancestor even + higher does not exist + */ + goto out; + + /* ret == -1 && errno == ENOENT */ + loc.inode = inode_new (loc.parent->table); + if (!loc.inode) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_mkdir (subvol, &loc, mode, xattr_req); +out: + loc_wipe (&loc); + + if (xattr_req) + dict_destroy (xattr_req); + + return ret; +} + + +int +glfs_unlink (struct glfs *fs, const char *path) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + if (iatt.ia_type == IA_IFDIR) { + ret = -1; + errno = EISDIR; + goto out; + } + + ret = syncop_unlink (subvol, &loc); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_rmdir (struct glfs *fs, const char *path) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + if (iatt.ia_type != IA_IFDIR) { + ret = -1; + errno = ENOTDIR; + goto out; + } + + ret = syncop_rmdir (subvol, &loc); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_rename (struct glfs *fs, const char *oldpath, const char *newpath) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t oldloc = {0, }; + loc_t newloc = {0, }; + struct iatt oldiatt = {0, }; + struct iatt newiatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_lresolve (fs, subvol, oldpath, &oldloc, &oldiatt); + if (ret) + goto out; + + ret = glfs_lresolve (fs, subvol, newpath, &newloc, &newiatt); + if (ret && errno != ENOENT && newloc.parent) + goto out; + + if ((oldiatt.ia_type == IA_IFDIR) != (newiatt.ia_type == IA_IFDIR)) { + /* Either both old and new must be dirs, or both must be + non-dirs. Else, fail. + */ + ret = -1; + errno = EISDIR; + goto out; + } + + /* TODO: check if new or old is a prefix of the other, and fail EINVAL */ + + ret = syncop_rename (subvol, &oldloc, &newloc); +out: + loc_wipe (&oldloc); + loc_wipe (&newloc); + + return ret; +} + + +int +glfs_link (struct glfs *fs, const char *oldpath, const char *newpath) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t oldloc = {0, }; + loc_t newloc = {0, }; + struct iatt oldiatt = {0, }; + struct iatt newiatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_lresolve (fs, subvol, oldpath, &oldloc, &oldiatt); + if (ret) + goto out; + + ret = glfs_lresolve (fs, subvol, newpath, &newloc, &newiatt); + if (ret == 0) { + ret = -1; + errno = EEXIST; + goto out; + } + + if (oldiatt.ia_type == IA_IFDIR) { + ret = -1; + errno = EISDIR; + goto out; + } + + ret = syncop_link (subvol, &oldloc, &newloc); +out: + loc_wipe (&oldloc); + loc_wipe (&newloc); + + return ret; +} + + +struct glfs_fd * +glfs_opendir (struct glfs *fs, const char *path) +{ + int ret = -1; + struct glfs_fd *glfd = NULL; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + glfd = GF_CALLOC (1, sizeof (*glfd), glfs_mt_glfs_fd_t); + if (!glfd) + goto out; + INIT_LIST_HEAD (&glfd->entries); + + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + if (!IA_ISDIR (iatt.ia_type)) { + ret = -1; + errno = ENOTDIR; + goto out; + } + + glfd->fd = fd_create (loc.inode, getpid()); + if (!glfd->fd) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_opendir (subvol, &loc, glfd->fd); +out: + loc_wipe (&loc); + + if (ret && glfd) { + glfs_fd_destroy (glfd); + glfd = NULL; + } + + return glfd; +} + + +int +glfs_closedir (struct glfs_fd *glfd) +{ + __glfs_entry_fd (glfd); + + gf_dirent_free (list_entry (&glfd->entries, gf_dirent_t, list)); + + glfs_fd_destroy (glfd); + + return 0; +} + + +long +glfs_telldir (struct glfs_fd *fd) +{ + return fd->offset; +} + + +void +glfs_seekdir (struct glfs_fd *fd, long offset) +{ + gf_dirent_t *entry = NULL; + gf_dirent_t *tmp = NULL; + + if (fd->offset == offset) + return; + + fd->offset = offset; + fd->next = NULL; + + list_for_each_entry_safe (entry, tmp, &fd->entries, list) { + if (entry->d_off != offset) + continue; + + if (&tmp->list != &fd->entries) { + /* found! */ + fd->next = tmp; + return; + } + } + /* could not find entry at requested offset in the cache. + next readdir_r() will result in glfd_entry_refresh() + */ +} + + +void +gf_dirent_to_dirent (gf_dirent_t *gf_dirent, struct dirent *dirent) +{ + dirent->d_ino = gf_dirent->d_ino; + +#ifdef _DIRENT_HAVE_D_OFF + dirent->d_off = gf_dirent->d_off; +#endif + +#ifdef _DIRENT_HAVE_D_TYPE + dirent->d_type = gf_dirent->d_type; +#endif + +#ifdef _DIRENT_HAVE_D_NAMLEN + dirent->d_namlen = strlen (gf_dirent->d_name); +#endif + + strncpy (dirent->d_name, gf_dirent->d_name, 256); +} + + +int +glfd_entry_refresh (struct glfs_fd *glfd) +{ + xlator_t *subvol = NULL; + gf_dirent_t entries; + gf_dirent_t old; + int ret = -1; + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + errno = EIO; + return -1; + } + + INIT_LIST_HEAD (&entries.list); + INIT_LIST_HEAD (&old.list); + + ret = syncop_readdir (subvol, glfd->fd, 131072, glfd->offset, + &entries); + if (ret >= 0) { + /* spurious errno is dangerous for glfd_entry_next() */ + errno = 0; + + list_splice_init (&glfd->entries, &old.list); + list_splice_init (&entries.list, &glfd->entries); + } + + if (ret > 0) + glfd->next = list_entry (glfd->entries.next, gf_dirent_t, list); + + gf_dirent_free (&old); + + return ret; +} + + +gf_dirent_t * +glfd_entry_next (struct glfs_fd *glfd) +{ + gf_dirent_t *entry = NULL; + int ret = -1; + + if (!glfd->offset || !glfd->next) { + ret = glfd_entry_refresh (glfd); + if (ret < 0) + return NULL; + } + + entry = glfd->next; + if (!entry) + return NULL; + + if (&entry->next->list == &glfd->entries) + glfd->next = NULL; + else + glfd->next = entry->next; + + glfd->offset = entry->d_off; + + return entry; +} + + +int +glfs_readdir_r (struct glfs_fd *glfd, struct dirent *buf, struct dirent **res) +{ + int ret = 0; + gf_dirent_t *entry = NULL; + + __glfs_entry_fd (glfd); + + if (glfd->fd->inode->ia_type != IA_IFDIR) { + ret = -1; + errno = EBADF; + goto out; + } + + errno = 0; + entry = glfd_entry_next (glfd); + if (errno) + ret = -1; + + if (res) { + if (entry) + *res = buf; + else + *res = NULL; + } + + if (entry) + gf_dirent_to_dirent (entry, buf); +out: + return ret; +} + + +int +glfs_statvfs (struct glfs *fs, const char *path, struct statvfs *buf) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + ret = syncop_statfs (subvol, &loc, buf); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_setattr (struct glfs *fs, const char *path, struct iatt *iatt, + int valid, int follow) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt riatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + if (follow) + ret = glfs_resolve (fs, subvol, path, &loc, &riatt); + else + ret = glfs_lresolve (fs, subvol, path, &loc, &riatt); + + if (ret) + goto out; + + ret = syncop_setattr (subvol, &loc, iatt, valid, 0, 0); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_fsetattr (struct glfs_fd *glfd, struct iatt *iatt, int valid) +{ + int ret = -1; + xlator_t *subvol = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_fsetattr (subvol, glfd->fd, iatt, valid, 0, 0); +out: + return ret; +} + + +int +glfs_chmod (struct glfs *fs, const char *path, mode_t mode) +{ + int ret = -1; + struct iatt iatt = {0, }; + int valid = 0; + + iatt.ia_prot = ia_prot_from_st_mode (mode); + valid = GF_SET_ATTR_MODE; + + ret = glfs_setattr (fs, path, &iatt, valid, 1); + + return ret; +} + + +int +glfs_fchmod (struct glfs_fd *glfd, mode_t mode) +{ + int ret = -1; + struct iatt iatt = {0, }; + int valid = 0; + + iatt.ia_prot = ia_prot_from_st_mode (mode); + valid = GF_SET_ATTR_MODE; + + ret = glfs_fsetattr (glfd, &iatt, valid); + + return ret; +} + + +int +glfs_chown (struct glfs *fs, const char *path, uid_t uid, gid_t gid) +{ + int ret = -1; + int valid = 0; + struct iatt iatt = {0, }; + + iatt.ia_uid = uid; + iatt.ia_gid = gid; + valid = GF_SET_ATTR_UID|GF_SET_ATTR_GID; + + ret = glfs_setattr (fs, path, &iatt, valid, 1); + + return ret; +} + + +int +glfs_lchown (struct glfs *fs, const char *path, uid_t uid, gid_t gid) +{ + int ret = -1; + int valid = 0; + struct iatt iatt = {0, }; + + iatt.ia_uid = uid; + iatt.ia_gid = gid; + valid = GF_SET_ATTR_UID|GF_SET_ATTR_GID; + + ret = glfs_setattr (fs, path, &iatt, valid, 0); + + return ret; +} + + +int +glfs_fchown (struct glfs_fd *glfd, uid_t uid, gid_t gid) +{ + int ret = -1; + int valid = 0; + struct iatt iatt = {0, }; + + iatt.ia_uid = uid; + iatt.ia_gid = gid; + valid = GF_SET_ATTR_UID|GF_SET_ATTR_GID; + + ret = glfs_fsetattr (glfd, &iatt, valid); + + return ret; +} + + +int +glfs_utimens (struct glfs *fs, const char *path, struct timespec times[2]) +{ + int ret = -1; + int valid = 0; + struct iatt iatt = {0, }; + + iatt.ia_atime = times[0].tv_sec; + iatt.ia_atime_nsec = times[0].tv_nsec; + iatt.ia_mtime = times[1].tv_sec; + iatt.ia_mtime_nsec = times[1].tv_nsec; + + valid = GF_SET_ATTR_ATIME|GF_SET_ATTR_MTIME; + + ret = glfs_setattr (fs, path, &iatt, valid, 1); + + return ret; +} + + +int +glfs_lutimens (struct glfs *fs, const char *path, struct timespec times[2]) +{ + int ret = -1; + int valid = 0; + struct iatt iatt = {0, }; + + iatt.ia_atime = times[0].tv_sec; + iatt.ia_atime_nsec = times[0].tv_nsec; + iatt.ia_mtime = times[1].tv_sec; + iatt.ia_mtime_nsec = times[1].tv_nsec; + + valid = GF_SET_ATTR_ATIME|GF_SET_ATTR_MTIME; + + ret = glfs_setattr (fs, path, &iatt, valid, 0); + + return ret; +} + + +int +glfs_futimens (struct glfs_fd *glfd, struct timespec times[2]) +{ + int ret = -1; + int valid = 0; + struct iatt iatt = {0, }; + + iatt.ia_atime = times[0].tv_sec; + iatt.ia_atime_nsec = times[0].tv_nsec; + iatt.ia_mtime = times[1].tv_sec; + iatt.ia_mtime_nsec = times[1].tv_nsec; + + valid = GF_SET_ATTR_ATIME|GF_SET_ATTR_MTIME; + + ret = glfs_fsetattr (glfd, &iatt, valid); + + return ret; +} + + +int +glfs_getxattr_process (void *value, size_t size, dict_t *xattr, + const char *name) +{ + data_t *data = NULL; + int ret = -1; + + data = dict_get (xattr, (char *)name); + if (!data) { + errno = ENODATA; + ret = -1; + goto out; + } + + ret = data->len; + if (!value || !size) + goto out; + + if (size < ret) { + ret = -1; + errno = ERANGE; + goto out; + } + + memcpy (value, data->data, ret); +out: + if (xattr) + dict_unref (xattr); + return ret; +} + + +ssize_t +glfs_getxattr_common (struct glfs *fs, const char *path, const char *name, + void *value, size_t size, int follow) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + dict_t *xattr = NULL; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + if (follow) + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + else + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + ret = syncop_getxattr (subvol, &loc, &xattr, name); + if (ret) + goto out; + + ret = glfs_getxattr_process (value, size, xattr, name); +out: + loc_wipe (&loc); + + return ret; +} + + +ssize_t +glfs_getxattr (struct glfs *fs, const char *path, const char *name, + void *value, size_t size) +{ + return glfs_getxattr_common (fs, path, name, value, size, 1); +} + + +ssize_t +glfs_lgetxattr (struct glfs *fs, const char *path, const char *name, + void *value, size_t size) +{ + return glfs_getxattr_common (fs, path, name, value, size, 0); +} + + +ssize_t +glfs_fgetxattr (struct glfs_fd *glfd, const char *name, void *value, + size_t size) +{ + int ret = -1; + xlator_t *subvol = NULL; + dict_t *xattr = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_fgetxattr (subvol, glfd->fd, &xattr, name); + if (ret) + goto out; + + ret = glfs_getxattr_process (value, size, xattr, name); +out: + return ret; +} + + +static int +dict_keys_join (void *value, int size, dict_t *dict) +{ + int len = 0; + + int add_key_len (dict_t *d, char *k, data_t *v, void *o) + { + if (value && size > len) + strncpy (value + len, k, size - len); + + len += (strlen (k) + 1); + + return 0; + } + + dict_foreach (dict, add_key_len, 0); + + return len; +} + +int +glfs_listxattr_process (void *value, size_t size, dict_t *xattr) +{ + int ret = -1; + + ret = dict_keys_join (NULL, 0, xattr); + + if (!value || !size) + goto out; + + if (size < ret) { + ret = -1; + errno = ERANGE; + goto out; + } + + dict_keys_join (value, size, xattr); +out: + if (xattr) + dict_unref (xattr); + return ret; +} + + +ssize_t +glfs_listxattr_common (struct glfs *fs, const char *path, void *value, + size_t size, int follow) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + dict_t *xattr = NULL; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + if (follow) + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + else + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + ret = syncop_getxattr (subvol, &loc, &xattr, NULL); + if (ret) + goto out; + + ret = glfs_listxattr_process (value, size, xattr); +out: + loc_wipe (&loc); + + return ret; +} + + +ssize_t +glfs_listxattr (struct glfs *fs, const char *path, void *value, size_t size) +{ + return glfs_listxattr_common (fs, path, value, size, 1); +} + + +ssize_t +glfs_llistxattr (struct glfs *fs, const char *path, void *value, size_t size) +{ + return glfs_listxattr_common (fs, path, value, size, 0); +} + + +ssize_t +glfs_flistxattr (struct glfs_fd *glfd, void *value, size_t size) +{ + int ret = -1; + xlator_t *subvol = NULL; + dict_t *xattr = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_fgetxattr (subvol, glfd->fd, &xattr, NULL); + if (ret) + goto out; + + ret = glfs_listxattr_process (value, size, xattr); +out: + return ret; +} + + +dict_t * +dict_for_key_value (const char *name, const char *value, size_t size) +{ + dict_t *xattr = NULL; + int ret = 0; + + xattr = dict_new (); + if (!xattr) + return NULL; + + ret = dict_set_static_bin (xattr, (char *)name, (void *)value, size); + if (ret) { + dict_destroy (xattr); + xattr = NULL; + } + + return xattr; +} + + +int +glfs_setxattr_common (struct glfs *fs, const char *path, const char *name, + const void *value, size_t size, int flags, int follow) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + dict_t *xattr = NULL; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + if (follow) + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + else + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + xattr = dict_for_key_value (name, value, size); + if (!xattr) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_setxattr (subvol, &loc, xattr, flags); +out: + loc_wipe (&loc); + if (xattr) + dict_unref (xattr); + + return ret; +} + + +int +glfs_setxattr (struct glfs *fs, const char *path, const char *name, + const void *value, size_t size, int flags) +{ + return glfs_setxattr_common (fs, path, name, value, size, flags, 1); +} + + +int +glfs_lsetxattr (struct glfs *fs, const char *path, const char *name, + const void *value, size_t size, int flags) +{ + return glfs_setxattr_common (fs, path, name, value, size, flags, 0); +} + + +int +glfs_fsetxattr (struct glfs_fd *glfd, const char *name, const void *value, + size_t size, int flags) +{ + int ret = -1; + xlator_t *subvol = NULL; + dict_t *xattr = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + xattr = dict_for_key_value (name, value, size); + if (!xattr) { + ret = -1; + errno = ENOMEM; + goto out; + } + + ret = syncop_fsetxattr (subvol, glfd->fd, xattr, flags); +out: + if (xattr) + dict_unref (xattr); + + return ret; +} + + +int +glfs_removexattr_common (struct glfs *fs, const char *path, const char *name, + int follow) +{ + int ret = -1; + xlator_t *subvol = NULL; + loc_t loc = {0, }; + struct iatt iatt = {0, }; + + __glfs_entry_fs (fs); + + subvol = glfs_active_subvol (fs); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + if (follow) + ret = glfs_resolve (fs, subvol, path, &loc, &iatt); + else + ret = glfs_lresolve (fs, subvol, path, &loc, &iatt); + if (ret) + goto out; + + ret = syncop_removexattr (subvol, &loc, name); +out: + loc_wipe (&loc); + + return ret; +} + + +int +glfs_removexattr (struct glfs *fs, const char *path, const char *name) +{ + return glfs_removexattr_common (fs, path, name, 1); +} + + +int +glfs_lremovexattr (struct glfs *fs, const char *path, const char *name) +{ + return glfs_removexattr_common (fs, path, name, 0); +} + + +int +glfs_fremovexattr (struct glfs_fd *glfd, const char *name) +{ + int ret = -1; + xlator_t *subvol = NULL; + + __glfs_entry_fd (glfd); + + subvol = glfs_fd_subvol (glfd); + if (!subvol) { + ret = -1; + errno = EIO; + goto out; + } + + ret = syncop_fremovexattr (subvol, glfd->fd, name); +out: + return ret; +} diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index 8c9e356f9c3..c2fc0ecc1ea 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -39,8 +39,10 @@ struct glfs { }; struct glfs_fd { - off_t offset; - fd_t *fd; + off_t offset; + fd_t *fd; + struct list_head entries; + gf_dirent_t *next; }; #define DEFAULT_EVENT_POOL_SIZE 16384 diff --git a/api/src/glfs.h b/api/src/glfs.h index 14d41356a02..ded42febab5 100644 --- a/api/src/glfs.h +++ b/api/src/glfs.h @@ -39,6 +39,8 @@ #include #include #include +#include +#include __BEGIN_DECLS @@ -353,6 +355,7 @@ int glfs_ftruncate_async (glfs_fd_t *fd, off_t length, glfs_io_cbk fn, void *data); int glfs_lstat (glfs_t *fs, const char *path, struct stat *buf); +int glfs_stat (glfs_t *fs, const char *path, struct stat *buf); int glfs_fstat (glfs_fd_t *fd, struct stat *buf); int glfs_fsync (glfs_fd_t *fd); @@ -361,6 +364,84 @@ int glfs_fsync_async (glfs_fd_t *fd, glfs_io_cbk fn, void *data); int glfs_fdatasync (glfs_fd_t *fd); int glfs_fdatasync_async (glfs_fd_t *fd, glfs_io_cbk fn, void *data); +int glfs_access (glfs_t *fs, const char *path, int mode); + +int glfs_symlink (glfs_t *fs, const char *oldpath, const char *newpath); + +int glfs_readlink (glfs_t *fs, const char *path, char *buf, size_t bufsiz); + +int glfs_mknod (glfs_t *fs, const char *path, mode_t mode, dev_t dev); + +int glfs_mkdir (glfs_t *fs, const char *path, mode_t mode); + +int glfs_unlink (glfs_t *fs, const char *path); + +int glfs_rmdir (glfs_t *fs, const char *path); + +int glfs_rename (glfs_t *fs, const char *oldpath, const char *newpath); + +int glfs_link (glfs_t *fs, const char *oldpath, const char *newpath); + +glfs_fd_t *glfs_opendir (glfs_t *fs, const char *path); + +int glfs_readdir_r (glfs_fd_t *fd, struct dirent *dirent, + struct dirent **result); + +long glfs_telldir (glfs_fd_t *fd); + +void glfs_seekdir (glfs_fd_t *fd, long offset); + +int glfs_closedir (glfs_fd_t *fd); + +int glfs_statvfs (glfs_t *fs, const char *path, struct statvfs *buf); + +int glfs_chmod (glfs_t *fs, const char *path, mode_t mode); + +int glfs_fchmod (glfs_fd_t *fd, mode_t mode); + +int glfs_chown (glfs_t *fs, const char *path, uid_t uid, gid_t gid); + +int glfs_lchown (glfs_t *fs, const char *path, uid_t uid, gid_t gid); + +int glfs_fchown (glfs_fd_t *fd, uid_t uid, gid_t gid); + +int glfs_utimens (glfs_t *fs, const char *path, struct timespec times[2]); + +int glfs_lutimens (glfs_t *fs, const char *path, struct timespec times[2]); + +int glfs_futimens (glfs_fd_t *fd, struct timespec times[2]); + +ssize_t glfs_getxattr (glfs_t *fs, const char *path, const char *name, + void *value, size_t size); + +ssize_t glfs_lgetxattr (glfs_t *fs, const char *path, const char *name, + void *value, size_t size); + +ssize_t glfs_fgetxattr (glfs_fd_t *fd, const char *name, + void *value, size_t size); + +ssize_t glfs_listxattr (glfs_t *fs, const char *path, void *value, size_t size); + +ssize_t glfs_llistxattr (glfs_t *fs, const char *path, void *value, + size_t size); + +ssize_t glfs_flistxattr (glfs_fd_t *fd, void *value, size_t size); + +int glfs_setxattr (glfs_t *fs, const char *path, const char *name, + const void *value, size_t size, int flags); + +int glfs_lsetxattr (glfs_t *fs, const char *path, const char *name, + const void *value, size_t size, int flags); + +int glfs_fsetxattr (glfs_fd_t *fd, const char *name, + const void *value, size_t size, int flags); + +int glfs_removexattr (glfs_t *fs, const char *path, const char *name); + +int glfs_lremovexattr (glfs_t *fs, const char *path, const char *name); + +int glfs_fremovexattr (glfs_fd_t *fd, const char *name); + __END_DECLS #endif /* !_GLFS_H */ -- cgit