diff options
Diffstat (limited to 'xlators/storage/posix/src/posix-handle.c')
| -rw-r--r-- | xlators/storage/posix/src/posix-handle.c | 1436 |
1 files changed, 856 insertions, 580 deletions
diff --git a/xlators/storage/posix/src/posix-handle.c b/xlators/storage/posix/src/posix-handle.c index 219a582c9f7..410b38da8cb 100644 --- a/xlators/storage/posix/src/posix-handle.c +++ b/xlators/storage/posix/src/posix-handle.c @@ -7,11 +7,6 @@ later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - #include <errno.h> #include <sys/types.h> #include <sys/stat.h> @@ -23,135 +18,376 @@ #include "posix-handle.h" #include "posix.h" -#include "xlator.h" -#include "syscall.h" +#include <glusterfs/syscall.h> +#include "posix-messages.h" +#include "posix-metadata.h" +#include <glusterfs/compat-errno.h> -#define HANDLE_PFX ".glusterfs" -#define TRASH_DIR "landfill" +int +posix_handle_mkdir_hashes(xlator_t *this, int dfd, uuid_t gfid); -#define UUID0_STR "00000000-0000-0000-0000-000000000000" -#define SLEN(str) (sizeof(str) - 1) +inode_t * +posix_resolve(xlator_t *this, inode_table_t *itable, inode_t *parent, + char *bname, struct iatt *iabuf) +{ + inode_t *inode = NULL; + int ret = -1; + + ret = posix_istat(this, NULL, parent->gfid, bname, iabuf); + if (ret < 0) { + gf_log(this->name, GF_LOG_WARNING, + "gfid: %s, bname: %s " + "failed", + uuid_utoa(parent->gfid), bname); + goto out; + } + + if (__is_root_gfid(iabuf->ia_gfid) && !strcmp(bname, "/")) { + inode = itable->root; + } else { + inode = inode_find(itable, iabuf->ia_gfid); + if (inode == NULL) { + inode = inode_new(itable); + gf_uuid_copy(inode->gfid, iabuf->ia_gfid); + } + } + + /* posix_istat wouldn't have fetched posix_mdata_t i.e., + * time attributes as inode is passed as NULL, hence get + * here once you got the inode + */ + ret = posix_get_mdata_xattr(this, NULL, -1, inode, iabuf); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_GETMDATA_FAILED, + "posix get mdata failed on gfid:%s", uuid_utoa(inode->gfid)); + goto out; + } + + /* Linking an inode here, can cause a race in posix_acl. + Parent inode gets linked here, but before + it reaches posix_acl_readdirp_cbk, create/lookup can + come on a leaf-inode, as parent-inode-ctx not yet updated + in posix_acl_readdirp_cbk, create and lookup can fail + with EACCESS. So do the inode linking in the quota xlator + + if (__is_root_gfid (iabuf->ia_gfid) && !strcmp (bname, "/")) + linked_inode = itable->root; + else + linked_inode = inode_link (inode, parent, bname, iabuf); + + inode_unref (inode);*/ +out: + return inode; +} int -posix_handle_relpath (xlator_t *this, uuid_t gfid, const char *basename, - char *buf, size_t buflen) +posix_make_ancestral_node(const char *priv_base_path, char *path, int pathsize, + gf_dirent_t *head, char *dir_name, struct iatt *iabuf, + inode_t *inode, int type, dict_t *xdata) { - char *uuid_str = NULL; - int len = 0; - - len = SLEN("../") - + SLEN("../") - + SLEN("00/") - + SLEN("00/") - + SLEN(UUID0_STR) - + 1 /* '\0' */ - ; - - if (basename) { - len += (strlen (basename) + 1); - } - - if (buflen < len || !buf) - return len; + gf_dirent_t *entry = NULL; + char real_path[PATH_MAX + 1] = + { + 0, + }, + len = 0; + loc_t loc = { + 0, + }; + int ret = -1; + + len = strlen(path) + strlen(dir_name) + 1; + if (len > pathsize) { + goto out; + } + + strcat(path, dir_name); + if (*dir_name != '/') + strcat(path, "/"); + + if (type & POSIX_ANCESTRY_DENTRY) { + entry = gf_dirent_for_name(dir_name); + if (!entry) + goto out; + + entry->d_stat = *iabuf; + entry->inode = inode_ref(inode); + + list_add_tail(&entry->list, &head->list); + snprintf(real_path, sizeof(real_path), "%s/%s", priv_base_path, path); + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + + entry->dict = posix_xattr_fill(THIS, real_path, &loc, NULL, -1, xdata, + iabuf); + loc_wipe(&loc); + } + + ret = 0; - uuid_str = uuid_utoa (gfid); +out: + return ret; +} - if (basename) { - len = snprintf (buf, buflen, "../../%02x/%02x/%s/%s", - gfid[0], gfid[1], uuid_str, basename); +int +posix_make_ancestryfromgfid(xlator_t *this, char *path, int pathsize, + gf_dirent_t *head, int type, uuid_t gfid, + const size_t handle_size, + const char *priv_base_path, inode_table_t *itable, + inode_t **parent, dict_t *xdata, int32_t *op_errno) +{ + char *linkname = NULL; /* "../../<gfid[0]>/<gfid[1]/" + "<gfidstr>/<NAME_MAX>" */ + char *dir_handle = NULL; + char *pgfidstr = NULL; + char *saveptr = NULL; + ssize_t len = 0; + inode_t *inode = NULL; + struct iatt iabuf = { + 0, + }; + int ret = -1; + uuid_t tmp_gfid = { + 0, + }; + char *dir_stack[PATH_MAX / 2 + 1]; /* Since PATH_MAX/2 also gives + an upper bound on depth of + directories tree */ + uuid_t gfid_stack[PATH_MAX / 2 + 1]; + + char *dir_name = NULL; + char *saved_dir = NULL; + int top = -1; + + if (!path || !parent || !priv_base_path || gf_uuid_is_null(gfid)) { + *op_errno = EINVAL; + goto out; + } + + dir_handle = alloca(handle_size); + linkname = alloca(PATH_MAX); + gf_uuid_copy(tmp_gfid, gfid); + + while (top < PATH_MAX / 2) { + gf_uuid_copy(gfid_stack[++top], tmp_gfid); + if (__is_root_gfid(tmp_gfid)) { + *parent = inode_ref(itable->root); + + saved_dir = alloca(sizeof("/")); + strcpy(saved_dir, "/"); + dir_stack[top] = saved_dir; + break; } else { - len = snprintf (buf, buflen, "../../%02x/%02x/%s", - gfid[0], gfid[1], uuid_str); + snprintf(dir_handle, handle_size, "%s/%s/%02x/%02x/%s", + priv_base_path, GF_HIDDEN_PATH, tmp_gfid[0], tmp_gfid[1], + uuid_utoa(tmp_gfid)); + + len = sys_readlink(dir_handle, linkname, PATH_MAX); + if (len < 0) { + *op_errno = errno; + gf_msg(this->name, + (errno == ENOENT || errno == ESTALE) ? GF_LOG_DEBUG + : GF_LOG_ERROR, + errno, P_MSG_READLINK_FAILED, + "could not read" + " the link from the gfid handle %s ", + dir_handle); + ret = -1; + goto out; + } + + linkname[len] = '\0'; + + pgfidstr = strtok_r(linkname + SLEN("../../00/00/"), "/", &saveptr); + dir_name = strtok_r(NULL, "/", &saveptr); + saved_dir = alloca(strlen(dir_name) + 1); + gf_uuid_parse(pgfidstr, tmp_gfid); + strcpy(saved_dir, dir_name); + dir_stack[top] = saved_dir; + } + } + if (top == PATH_MAX / 2) { + gf_msg(this->name, GF_LOG_ERROR, P_MSG_ANCESTORY_FAILED, 0, + "build ancestry failed due to " + "deep directory hierarchy, depth: %d.", + top); + *op_errno = EINVAL; + ret = -1; + goto out; + } + + while (top >= 0) { + if (!*parent) { + /* There's no real "root" cause for how we end up here, + * so for now let's log this and bail out to prevent + * crashes. + */ + gf_msg(this->name, GF_LOG_WARNING, P_MSG_INODE_RESOLVE_FAILED, 0, + "OOPS: *parent is null (path: %s), bailing!", path); + goto out; + } + + memset(&iabuf, 0, sizeof(iabuf)); + inode = posix_resolve(this, itable, *parent, dir_stack[top], &iabuf); + if (inode == NULL) { + gf_msg(this->name, GF_LOG_ERROR, P_MSG_INODE_RESOLVE_FAILED, 0, + "posix resolve on the inode %s failed", + uuid_utoa(gfid_stack[top])); + *op_errno = ESTALE; + ret = -1; + goto out; + } + + ret = posix_make_ancestral_node(priv_base_path, path, pathsize, head, + dir_stack[top], &iabuf, inode, type, + xdata); + if (ret < 0) { + *op_errno = ENOMEM; + goto out; } - return len; + inode_unref(*parent); + *parent = inode; + top--; + } +out: + return ret; } - -/* - TODO: explain how this pump fixes ELOOP -*/ int -posix_handle_pump (xlator_t *this, char *buf, int len, int maxlen, - char *base_str, int base_len, int pfx_len) +posix_handle_relpath(xlator_t *this, uuid_t gfid, const char *basename, + char *buf, size_t buflen) { - char linkname[512] = {0,}; /* "../../<gfid>/<NAME_MAX>" */ - int ret = 0; - int blen = 0; - int link_len = 0; - - /* is a directory's symlink-handle */ - ret = readlink (base_str, linkname, 512); - if (ret == -1) { - gf_log (this->name, GF_LOG_ERROR, - "internal readlink failed on %s (%s)", - base_str, strerror (errno)); - goto err; - } + char *uuid_str = NULL; + int len = 0; - if (ret < 512) - linkname[ret] = 0; + len = POSIX_GFID_HANDLE_RELSIZE; - link_len = ret; + if (basename) { + len += (strlen(basename) + 1); + } - if ((ret == 8) && memcmp (linkname, "../../..", 8) == 0) { - if (strcmp (base_str, buf) == 0) { - strcpy (buf + pfx_len, ".."); - } - goto out; - } + if (buflen < len || !buf) + return len; - if (ret < 50 || ret >= 512) { - gf_log (this->name, GF_LOG_ERROR, - "malformed internal link %s for %s", - linkname, base_str); - goto err; - } + uuid_str = uuid_utoa(gfid); - if (memcmp (linkname, "../../", 6) != 0) { - gf_log (this->name, GF_LOG_ERROR, - "malformed internal link %s for %s", - linkname, base_str); - goto err; - } + if (basename) { + len = snprintf(buf, buflen, "../../%02x/%02x/%s/%s", gfid[0], gfid[1], + uuid_str, basename); + } else { + len = snprintf(buf, buflen, "../../%02x/%02x/%s", gfid[0], gfid[1], + uuid_str); + } - if ((linkname[2] != '/') || - (linkname[5] != '/') || - (linkname[8] != '/') || - (linkname[11] != '/') || - (linkname[48] != '/')) { - gf_log (this->name, GF_LOG_ERROR, - "malformed internal link %s for %s", - linkname, base_str); - goto err; - } + return len; +} - if ((linkname[20] != '-') || - (linkname[25] != '-') || - (linkname[30] != '-') || - (linkname[35] != '-')) { - gf_log (this->name, GF_LOG_ERROR, - "malformed internal link %s for %s", - linkname, base_str); - goto err; - } +/* + TODO: explain how this pump fixes ELOOP +*/ +gf_boolean_t +posix_is_malformed_link(xlator_t *this, char *base_str, char *linkname, + size_t len) +{ + if ((len == 8) && strcmp(linkname, "../../..")) /*for root*/ + goto err; - blen = link_len - 48; - memmove (buf + base_len + blen, buf + base_len, - (strlen (buf) - base_len) + 1); + if (len < 50 || len >= 512) + goto err; - strncpy (base_str + pfx_len, linkname + 6, 42); + if (memcmp(linkname, "../../", 6) != 0) + goto err; + + if ((linkname[2] != '/') || (linkname[5] != '/') || (linkname[8] != '/') || + (linkname[11] != '/') || (linkname[48] != '/')) { + goto err; + } + + if ((linkname[20] != '-') || (linkname[25] != '-') || + (linkname[30] != '-') || (linkname[35] != '-')) { + goto err; + } + + return _gf_false; - if (len + blen < maxlen) - strncpy (buf + pfx_len, linkname + 6, link_len - 6); -out: - return len + blen; err: - return -1; + gf_log_callingfn(this->name, GF_LOG_ERROR, + "malformed internal link " + "%s for %s", + linkname, base_str); + return _gf_true; } +int +posix_handle_pump(xlator_t *this, char *buf, int len, int maxlen, + char *base_str, int base_len, int pfx_len) +{ + char linkname[512] = { + 0, + }; /* "../../<gfid>/<NAME_MAX>" */ + int ret = 0; + int blen = 0; + int link_len = 0; + char tmpstr[POSIX_GFID_HASH2_LEN] = { + 0, + }; + char d2[3] = { + 0, + }; + int index = 0; + int dirfd = 0; + struct posix_private *priv = this->private; + + strncpy(tmpstr, (base_str + pfx_len + 3), 40); + strncpy(d2, (base_str + pfx_len), 2); + index = strtoul(d2, NULL, 16); + dirfd = priv->arrdfd[index]; + + /* is a directory's symlink-handle */ + ret = readlinkat(dirfd, tmpstr, linkname, 512); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_READLINK_FAILED, + "internal readlink failed on %s ", base_str); + goto err; + } + + if (ret < 512) + linkname[ret] = 0; + + link_len = ret; + + if ((ret == 8) && memcmp(linkname, "../../..", 8) == 0) { + if (strcmp(base_str, buf) == 0) { + strcpy(buf + pfx_len, ".."); + } + goto out; + } + + if (posix_is_malformed_link(this, base_str, linkname, ret)) + goto err; + + blen = link_len - 48; + + if (len + blen >= maxlen) { + gf_msg(this->name, GF_LOG_ERROR, 0, P_MSG_HANDLEPATH_FAILED, + "Unable to form handle path for %s (maxlen = %d)", buf, maxlen); + goto err; + } + + memmove(buf + base_len + blen, buf + base_len, + (strlen(buf) - base_len) + 1); + + strncpy(base_str + pfx_len, linkname + 6, 42); + + strncpy(buf + pfx_len, linkname + 6, link_len - 6); +out: + return len + blen; +err: + return -1; +} /* posix_handle_path differs from posix_handle_gfid_path in the way that the @@ -163,582 +399,622 @@ err: */ int -posix_handle_path (xlator_t *this, uuid_t gfid, const char *basename, - char *ubuf, size_t size) +posix_handle_path(xlator_t *this, uuid_t gfid, const char *basename, char *ubuf, + size_t size) { - struct posix_private *priv = NULL; - char *uuid_str = NULL; - int len = 0; - int ret = -1; - struct stat stat; - char *base_str = NULL; - int base_len = 0; - int pfx_len; - int maxlen; - char *buf; - - priv = this->private; - - uuid_str = uuid_utoa (gfid); - - if (ubuf) { - buf = ubuf; - maxlen = size; - } else { - maxlen = PATH_MAX; - buf = alloca (maxlen); - } - - base_len = (priv->base_path_length + SLEN(HANDLE_PFX) + 45); - base_str = alloca (base_len + 1); - base_len = snprintf (base_str, base_len + 1, "%s/%s/%02x/%02x/%s", - priv->base_path, HANDLE_PFX, gfid[0], gfid[1], - uuid_str); - - pfx_len = priv->base_path_length + 1 + SLEN(HANDLE_PFX) + 1; - - if (basename) { - len = snprintf (buf, maxlen, "%s/%s", base_str, basename); - } else { - len = snprintf (buf, maxlen, "%s", base_str); - } - - ret = lstat (base_str, &stat); - - if (!(ret == 0 && S_ISLNK(stat.st_mode) && stat.st_nlink == 1)) - goto out; - - do { - errno = 0; - ret = posix_handle_pump (this, buf, len, maxlen, - base_str, base_len, pfx_len); - if (ret == -1) - break; - - len = ret; - - ret = lstat (buf, &stat); - } while ((ret == -1) && errno == ELOOP); + struct posix_private *priv = NULL; + char *uuid_str = NULL; + int len = 0; + int ret = -1; + struct stat stat; + char *base_str = NULL; + int base_len = 0; + int pfx_len; + int maxlen; + char *buf; + int index = 0; + int dfd = 0; + char newstr[POSIX_GFID_HASH2_LEN] = { + 0, + }; + + priv = this->private; + + uuid_str = uuid_utoa(gfid); + + if (ubuf) { + buf = ubuf; + maxlen = size; + } else { + maxlen = PATH_MAX; + buf = alloca(maxlen); + } + + index = gfid[0]; + dfd = priv->arrdfd[index]; + + base_len = (priv->base_path_length + SLEN(GF_HIDDEN_PATH) + 45); + base_str = alloca(base_len + 1); + base_len = snprintf(base_str, base_len + 1, "%s/%s/%02x/%02x/%s", + priv->base_path, GF_HIDDEN_PATH, gfid[0], gfid[1], + uuid_str); + pfx_len = priv->base_path_length + 1 + SLEN(GF_HIDDEN_PATH) + 1; + + if (basename) { + len = snprintf(buf, maxlen, "%s/%s", base_str, basename); + } else { + len = snprintf(buf, maxlen, "%s", base_str); + } + + snprintf(newstr, sizeof(newstr), "%02x/%s", gfid[1], uuid_str); + ret = sys_fstatat(dfd, newstr, &stat, AT_SYMLINK_NOFOLLOW); + + if (!(ret == 0 && S_ISLNK(stat.st_mode) && stat.st_nlink == 1)) + goto out; + + do { + errno = 0; + ret = posix_handle_pump(this, buf, len, maxlen, base_str, base_len, + pfx_len); + len = ret; + + if (ret == -1) + break; + ret = sys_lstat(buf, &stat); + } while ((ret == -1) && errno == ELOOP); out: - return len + 1; + return len + 1; } - int -posix_handle_gfid_path (xlator_t *this, uuid_t gfid, const char *basename, - char *buf, size_t buflen) +posix_handle_gfid_path(xlator_t *this, uuid_t gfid, char *buf, size_t buflen) { - struct posix_private *priv = NULL; - char *uuid_str = NULL; - int len = 0; - - priv = this->private; - - len = priv->base_path_length /* option directory "/export" */ - + SLEN("/") - + SLEN(HANDLE_PFX) - + SLEN("/") - + SLEN("00/") - + SLEN("00/") - + SLEN(UUID0_STR) - + 1 /* '\0' */ - ; - - if (basename) { - len += (strlen (basename) + 1); - } else { - len += 256; /* worst-case for directory's symlink-handle expansion */ - } + struct posix_private *priv = NULL; + char *uuid_str = NULL; + int len = 0; - if ((buflen < len) || !buf) - return len; + priv = this->private; - uuid_str = uuid_utoa (gfid); + len = POSIX_GFID_HANDLE_SIZE(priv->base_path_length); - if (__is_root_gfid (gfid)) { - if (basename) { - len = snprintf (buf, buflen, "%s/%s", priv->base_path, - basename); - } else { - strncpy (buf, priv->base_path, buflen); - } - goto out; - } + len += 256; /* worst-case for directory's symlink-handle expansion */ - if (basename) { - len = snprintf (buf, buflen, "%s/%s/%02x/%02x/%s/%s", priv->base_path, - HANDLE_PFX, gfid[0], gfid[1], uuid_str, basename); - } else { - len = snprintf (buf, buflen, "%s/%s/%02x/%02x/%s", priv->base_path, - HANDLE_PFX, gfid[0], gfid[1], uuid_str); - } -out: + if ((buflen < len) || !buf) return len; -} + uuid_str = uuid_utoa(gfid); + + if (__is_root_gfid(gfid)) { + len = snprintf(buf, buflen, "%s", priv->base_path); + } else { + len = snprintf(buf, buflen, "%s/%s/%02x/%02x/%s", priv->base_path, + GF_HIDDEN_PATH, gfid[0], gfid[1], uuid_str); + } + + return len; +} int -posix_handle_init (xlator_t *this) +posix_handle_init(xlator_t *this) { - struct posix_private *priv = NULL; - char *handle_pfx = NULL; - int ret = 0; - int len = 0; - struct stat stbuf; - struct stat rootbuf; - struct stat exportbuf; - char *rootstr = NULL; - uuid_t gfid = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; - - priv = this->private; - - ret = stat (priv->base_path, &exportbuf); - if (ret || !S_ISDIR (exportbuf.st_mode)) { - gf_log (this->name, GF_LOG_ERROR, - "Not a directory: %s", priv->base_path); - return -1; - } + struct posix_private *priv = NULL; + char *handle_pfx = NULL; + int ret = 0; + struct stat stbuf; + struct stat rootbuf; + struct stat exportbuf; + char *rootstr = NULL; + static uuid_t gfid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + int dfd = 0; + + priv = this->private; + + ret = sys_stat(priv->base_path, &exportbuf); + if (ret || !S_ISDIR(exportbuf.st_mode)) { + gf_msg(this->name, GF_LOG_ERROR, 0, P_MSG_HANDLE_CREATE, + "Not a directory: %s", priv->base_path); + return -1; + } - handle_pfx = alloca (priv->base_path_length + 1 + strlen (HANDLE_PFX) - + 1); + handle_pfx = alloca(priv->base_path_length + 1 + SLEN(GF_HIDDEN_PATH) + 1); - sprintf (handle_pfx, "%s/%s", priv->base_path, HANDLE_PFX); + sprintf(handle_pfx, "%s/%s", priv->base_path, GF_HIDDEN_PATH); - ret = stat (handle_pfx, &stbuf); - switch (ret) { + ret = sys_stat(handle_pfx, &stbuf); + switch (ret) { case -1: - if (errno == ENOENT) { - ret = mkdir (handle_pfx, 0600); - if (ret != 0) { - gf_log (this->name, GF_LOG_ERROR, - "Creating directory %s failed: %s", - handle_pfx, strerror (errno)); - return -1; - } - } else { - gf_log (this->name, GF_LOG_ERROR, - "Checking for %s failed: %s", - handle_pfx, strerror (errno)); - return -1; + if (errno == ENOENT) { + ret = sys_mkdir(handle_pfx, 0600); + if (ret != 0) { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_HANDLE_CREATE, + "Creating directory %s failed", handle_pfx); + return -1; } - break; + } else { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_HANDLE_CREATE, + "Checking for %s failed", handle_pfx); + return -1; + } + break; case 0: - if (!S_ISDIR (stbuf.st_mode)) { - gf_log (this->name, GF_LOG_ERROR, - "Not a directory: %s", - handle_pfx); - return -1; - } - break; + if (!S_ISDIR(stbuf.st_mode)) { + gf_msg(this->name, GF_LOG_ERROR, 0, P_MSG_HANDLE_CREATE, + "Not a directory: %s", handle_pfx); + return -1; + } + break; default: - break; - } + break; + } - stat (handle_pfx, &priv->handledir); + ret = sys_stat(handle_pfx, &priv->handledir); - len = posix_handle_path (this, gfid, NULL, NULL, 0); - rootstr = alloca (len); - posix_handle_path (this, gfid, NULL, rootstr, len); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_HANDLE_CREATE, + "stat for %s failed", handle_pfx); + return -1; + } - ret = stat (rootstr, &rootbuf); - switch (ret) { + MAKE_HANDLE_ABSPATH_FD(rootstr, this, gfid, dfd); + ret = sys_fstatat(dfd, rootstr, &rootbuf, 0); + switch (ret) { case -1: - if (errno != ENOENT) { - gf_log (this->name, GF_LOG_ERROR, - "%s: %s", priv->base_path, - strerror (errno)); - return -1; - } - - ret = posix_handle_mkdir_hashes (this, rootstr); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "mkdir %s failed (%s)", - rootstr, strerror (errno)); - return -1; - } + if (errno != ENOENT) { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_HANDLE_CREATE, + "%s", priv->base_path); + return -1; + } + ret = posix_handle_mkdir_hashes(this, dfd, gfid); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "mkdir %s failed", rootstr); + return -1; + } - ret = symlink ("../../..", rootstr); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "symlink %s creation failed (%s)", - rootstr, strerror (errno)); - return -1; - } - break; - case 0: - if ((exportbuf.st_ino == rootbuf.st_ino) && - (exportbuf.st_dev == rootbuf.st_dev)) - return 0; - - gf_log (this->name, GF_LOG_ERROR, - "Different dirs %s (%lld/%lld) != %s (%lld/%lld)", - priv->base_path, (long long) exportbuf.st_ino, - (long long) exportbuf.st_dev, rootstr, - (long long) rootbuf.st_ino, (long long) rootbuf.st_dev); + ret = sys_symlinkat("../../..", dfd, rootstr); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_HANDLE_CREATE, + "symlink %s creation failed", rootstr); return -1; + } + break; + case 0: + if ((exportbuf.st_ino == rootbuf.st_ino) && + (exportbuf.st_dev == rootbuf.st_dev)) + return 0; - break; - } + gf_msg(this->name, GF_LOG_ERROR, 0, P_MSG_HANDLE_CREATE, + "Different dirs %s (%lld/%lld) != %s (%lld/%lld)", + priv->base_path, (long long)exportbuf.st_ino, + (long long)exportbuf.st_dev, rootstr, + (long long)rootbuf.st_ino, (long long)rootbuf.st_dev); + return -1; + + break; + } - return 0; + return 0; } gf_boolean_t -posix_does_old_trash_exists (char *old_trash) +posix_does_old_trash_exists(char *old_trash) { - uuid_t gfid = {0}; - gf_boolean_t exists = _gf_false; - struct stat stbuf = {0}; - int ret = 0; - - ret = lstat (old_trash, &stbuf); - if ((ret == 0) && S_ISDIR (stbuf.st_mode)) { - ret = sys_lgetxattr (old_trash, "trusted.gfid", gfid, 16); - if ((ret < 0) && (errno == ENODATA)) - exists = _gf_true; - } - return exists; + uuid_t gfid = {0}; + gf_boolean_t exists = _gf_false; + struct stat stbuf = {0}; + int ret = 0; + + ret = sys_lstat(old_trash, &stbuf); + if ((ret == 0) && S_ISDIR(stbuf.st_mode)) { + ret = sys_lgetxattr(old_trash, "trusted.gfid", gfid, 16); + if ((ret < 0) && (errno == ENODATA || errno == ENOATTR)) + exists = _gf_true; + } + return exists; } int -posix_handle_new_trash_init (xlator_t *this, char *trash) +posix_handle_new_trash_init(xlator_t *this, char *trash) { - int ret = 0; - struct stat stbuf = {0}; + int ret = 0; + struct stat stbuf = {0}; - ret = lstat (trash, &stbuf); - switch (ret) { + ret = sys_lstat(trash, &stbuf); + switch (ret) { case -1: - if (errno == ENOENT) { - ret = mkdir (trash, 0755); - if (ret != 0) { - gf_log (this->name, GF_LOG_ERROR, - "Creating directory %s failed: %s", - trash, strerror (errno)); - } - } else { - gf_log (this->name, GF_LOG_ERROR, "Checking for %s " - "failed: %s", trash, strerror (errno)); + if (errno == ENOENT) { + ret = sys_mkdir(trash, 0755); + if (ret != 0) { + gf_msg(this->name, GF_LOG_ERROR, errno, + P_MSG_HANDLE_TRASH_CREATE, + "Creating directory %s failed", trash); } - break; + } else { + gf_msg(this->name, GF_LOG_ERROR, errno, + P_MSG_HANDLE_TRASH_CREATE, "Checking for %s failed", + trash); + } + break; case 0: - if (!S_ISDIR (stbuf.st_mode)) { - gf_log (this->name, GF_LOG_ERROR, - "Not a directory: %s", trash); - ret = -1; - } - break; + if (!S_ISDIR(stbuf.st_mode)) { + gf_msg(this->name, GF_LOG_ERROR, errno, + P_MSG_HANDLE_TRASH_CREATE, "Not a directory: %s", trash); + ret = -1; + } + break; default: - break; - } - return ret; + break; + } + return ret; } int -posix_mv_old_trash_into_new_trash (xlator_t *this, char *old, char *new) +posix_mv_old_trash_into_new_trash(xlator_t *this, char *old, char *new) { - char dest_old[PATH_MAX] = {0}; - int ret = 0; - uuid_t dest_name = {0}; - - if (!posix_does_old_trash_exists (old)) - goto out; - uuid_generate (dest_name); - snprintf (dest_old, sizeof (dest_old), "%s/%s", new, - uuid_utoa (dest_name)); - ret = rename (old, dest_old); - if (ret < 0) { - gf_log (this->name, GF_LOG_ERROR, "Not able to move " - "%s -> %s (%s)", old, dest_old, strerror (errno)); - } + char dest_old[PATH_MAX] = {0}; + int ret = 0; + uuid_t dest_name = {0}; + + if (!posix_does_old_trash_exists(old)) + goto out; + gf_uuid_generate(dest_name); + snprintf(dest_old, sizeof(dest_old), "%s/%s", new, uuid_utoa(dest_name)); + ret = sys_rename(old, dest_old); + if (ret < 0) { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_HANDLE_TRASH_CREATE, + "Not able to move %s -> %s ", old, dest_old); + } out: - return ret; + return ret; } int -posix_handle_trash_init (xlator_t *this) +posix_handle_trash_init(xlator_t *this) { - int ret = -1; - struct posix_private *priv = NULL; - char old_trash[PATH_MAX] = {0}; - - priv = this->private; - - priv->trash_path = GF_CALLOC (1, priv->base_path_length + strlen ("/") - + strlen (HANDLE_PFX) + strlen ("/") - + strlen (TRASH_DIR) + 1, - gf_posix_mt_trash_path); - - if (!priv->trash_path) - goto out; - - strncpy (priv->trash_path, priv->base_path, priv->base_path_length); - strcat (priv->trash_path, "/" HANDLE_PFX "/" TRASH_DIR); - ret = posix_handle_new_trash_init (this, priv->trash_path); - if (ret) - goto out; - snprintf (old_trash, sizeof (old_trash), "%s/.landfill", - priv->base_path); - ret = posix_mv_old_trash_into_new_trash (this, old_trash, - priv->trash_path); + int ret = -1; + struct posix_private *priv = NULL; + char old_trash[PATH_MAX] = {0}; + + priv = this->private; + + priv->trash_path = GF_MALLOC(priv->base_path_length + SLEN("/") + + SLEN(GF_HIDDEN_PATH) + SLEN("/") + + SLEN(TRASH_DIR) + 1, + gf_posix_mt_trash_path); + + if (!priv->trash_path) + goto out; + + snprintf( + priv->trash_path, + priv->base_path_length + SLEN(GF_HIDDEN_PATH) + SLEN(TRASH_DIR) + 3, + "%s/%s/%s", priv->base_path, GF_HIDDEN_PATH, TRASH_DIR); + + ret = posix_handle_new_trash_init(this, priv->trash_path); + if (ret) + goto out; + snprintf(old_trash, sizeof(old_trash), "%s/.landfill", priv->base_path); + ret = posix_mv_old_trash_into_new_trash(this, old_trash, priv->trash_path); out: - return ret; + return ret; } int -posix_handle_mkdir_hashes (xlator_t *this, const char *newpath) +posix_handle_mkdir_hashes(xlator_t *this, int dirfd, uuid_t gfid) { - char *duppath = NULL; - char *parpath = NULL; - int ret = 0; - - duppath = strdupa (newpath); - parpath = dirname (duppath); - parpath = dirname (duppath); - - ret = mkdir (parpath, 0700); - if (ret == -1 && errno != EEXIST) { - gf_log (this->name, GF_LOG_ERROR, - "error mkdir hash-1 %s (%s)", - parpath, strerror (errno)); - return -1; - } - - strcpy (duppath, newpath); - parpath = dirname (duppath); - - ret = mkdir (parpath, 0700); - if (ret == -1 && errno != EEXIST) { - gf_log (this->name, GF_LOG_ERROR, - "error mkdir hash-2 %s (%s)", - parpath, strerror (errno)); - return -1; - } + int ret = -1; + char d2[3] = { + 0, + }; + + snprintf(d2, sizeof(d2), "%02x", gfid[1]); + ret = sys_mkdirat(dirfd, d2, 0700); + if (ret == -1 && errno != EEXIST) { + gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_HANDLE_CREATE, + "error mkdir hash-2 %s ", uuid_utoa(gfid)); + return -1; + } - return 0; + return 0; } - int -posix_handle_hard (xlator_t *this, const char *oldpath, uuid_t gfid, struct stat *oldbuf) +posix_handle_hard(xlator_t *this, const char *oldpath, uuid_t gfid, + struct stat *oldbuf) { - char *newpath = NULL; - struct stat newbuf; - int ret = -1; - - - MAKE_HANDLE_PATH (newpath, this, gfid, NULL); + struct stat newbuf; + struct stat hashbuf; + int ret = -1; + gf_boolean_t link_exists = _gf_false; + char d2[3] = { + 0, + }; + int dfd = -1; + char *newstr = NULL; + + MAKE_HANDLE_ABSPATH_FD(newstr, this, gfid, dfd); + ret = sys_fstatat(dfd, newstr, &newbuf, AT_SYMLINK_NOFOLLOW); + + if (ret == -1 && errno != ENOENT) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, "%s", + uuid_utoa(gfid)); + return -1; + } - ret = lstat (newpath, &newbuf); - if (ret == -1 && errno != ENOENT) { - gf_log (this->name, GF_LOG_WARNING, - "%s: %s", newpath, strerror (errno)); + if (ret == -1 && errno == ENOENT) { + snprintf(d2, sizeof(d2), "%02x", gfid[1]); + ret = sys_fstatat(dfd, d2, &hashbuf, 0); + if (ret) { + ret = posix_handle_mkdir_hashes(this, dfd, gfid); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "mkdir %s failed ", uuid_utoa(gfid)); return -1; + } } + ret = sys_linkat(AT_FDCWD, oldpath, dfd, newstr); - if (ret == -1 && errno == ENOENT) { - ret = posix_handle_mkdir_hashes (this, newpath); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "mkdir %s failed (%s)", - newpath, strerror (errno)); - return -1; - } - -#ifdef HAVE_LINKAT - /* - * Use linkat if the target may be a symlink to a directory - * or without an existing target. See comment about linkat() - * usage in posix_link() in posix.c for details - */ - ret = linkat (AT_FDCWD, oldpath, AT_FDCWD, newpath, 0); -#else - ret = link (oldpath, newpath); -#endif - if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "link %s -> %s failed (%s)", - oldpath, newpath, strerror (errno)); - return -1; - } - - ret = lstat (newpath, &newbuf); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "lstat on %s failed (%s)", - newpath, strerror (errno)); - return -1; - } - } - - if (newbuf.st_ino != oldbuf->st_ino || - newbuf.st_dev != oldbuf->st_dev) { - gf_log (this->name, GF_LOG_WARNING, - "mismatching ino/dev between file %s (%lld/%lld) " - "and handle %s (%lld/%lld)", - oldpath, (long long) oldbuf->st_ino, (long long) oldbuf->st_dev, - newpath, (long long) newbuf.st_ino, (long long) newbuf.st_dev); - ret = -1; + if (ret) { + if (errno != EEXIST) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "link %s -> %s" + "failed ", + oldpath, newstr); + return -1; + } else { + link_exists = _gf_true; + } } + ret = sys_fstatat(dfd, newstr, &newbuf, AT_SYMLINK_NOFOLLOW); - return ret; + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "lstat on %s failed", uuid_utoa(gfid)); + return -1; + } + if ((link_exists) && (!S_ISREG(newbuf.st_mode))) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, P_MSG_HANDLE_CREATE, + "%s - Expected regular file", uuid_utoa(gfid)); + return -1; + } + } + + if (newbuf.st_ino != oldbuf->st_ino || newbuf.st_dev != oldbuf->st_dev) { + gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_HANDLE_CREATE, + "mismatching ino/dev between file %s (%lld/%lld) " + "and handle %s (%lld/%lld)", + oldpath, (long long)oldbuf->st_ino, (long long)oldbuf->st_dev, + uuid_utoa(gfid), (long long)newbuf.st_ino, + (long long)newbuf.st_dev); + ret = -1; + } + + return ret; } - int -posix_handle_soft (xlator_t *this, const char *real_path, loc_t *loc, - uuid_t gfid, struct stat *oldbuf) +posix_handle_soft(xlator_t *this, const char *real_path, loc_t *loc, + uuid_t gfid, struct stat *oldbuf) { - char *oldpath = NULL; - char *newpath = NULL; - struct stat newbuf; - int ret = -1; - - - MAKE_HANDLE_PATH (newpath, this, gfid, NULL); - MAKE_HANDLE_RELPATH (oldpath, this, loc->pargfid, loc->name); - + char *oldpath = NULL; + char *newpath = NULL; + struct stat newbuf; + struct stat hashbuf; + int ret = -1; + char d2[3] = { + 0, + }; + int dfd = -1; + char *newstr = NULL; + + MAKE_HANDLE_ABSPATH(newpath, this, gfid); + MAKE_HANDLE_ABSPATH_FD(newstr, this, gfid, dfd); + MAKE_HANDLE_RELPATH(oldpath, this, loc->pargfid, loc->name); + + ret = sys_fstatat(dfd, newstr, &newbuf, AT_SYMLINK_NOFOLLOW); + + if (ret == -1 && errno != ENOENT) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, "%s", + newstr); + return -1; + } - ret = lstat (newpath, &newbuf); - if (ret == -1 && errno != ENOENT) { - gf_log (this->name, GF_LOG_WARNING, - "%s: %s", newpath, strerror (errno)); - return -1; + if (ret == -1 && errno == ENOENT) { + if (posix_is_malformed_link(this, newpath, oldpath, strlen(oldpath))) { + GF_ASSERT(!"Malformed link"); + errno = EINVAL; + return -1; } - if (ret == -1 && errno == ENOENT) { - ret = posix_handle_mkdir_hashes (this, newpath); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "mkdir %s failed (%s)", - newpath, strerror (errno)); - return -1; - } - - ret = symlink (oldpath, newpath); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "symlink %s -> %s failed (%s)", - oldpath, newpath, strerror (errno)); - return -1; - } + snprintf(d2, sizeof(d2), "%02x", gfid[1]); + ret = sys_fstatat(dfd, d2, &hashbuf, 0); - ret = lstat (newpath, &newbuf); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "stat on %s failed (%s)", - newpath, strerror (errno)); - return -1; - } - } - - ret = stat (real_path, &newbuf); if (ret) { - gf_log (this->name, GF_LOG_WARNING, - "stat on %s failed (%s)", newpath, strerror (errno)); + ret = posix_handle_mkdir_hashes(this, dfd, gfid); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "mkdir %s failed ", newstr); return -1; + } } - - if (!oldbuf) - return ret; - - if (newbuf.st_ino != oldbuf->st_ino || - newbuf.st_dev != oldbuf->st_dev) { - gf_log (this->name, GF_LOG_WARNING, - "mismatching ino/dev between file %s (%lld/%lld) " - "and handle %s (%lld/%lld)", - oldpath, (long long) oldbuf->st_ino, (long long) oldbuf->st_dev, - newpath, (long long) newbuf.st_ino, (long long) newbuf.st_dev); - ret = -1; + ret = sys_symlinkat(oldpath, dfd, newstr); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "symlink %s -> %s failed", oldpath, newstr); + return -1; } - return ret; -} + ret = sys_fstatat(dfd, newstr, &newbuf, AT_SYMLINK_NOFOLLOW); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "stat on %s failed ", newstr); + return -1; + } + } -static int -posix_handle_unset_gfid (xlator_t *this, uuid_t gfid) -{ - char *path = NULL; - int ret = 0; - struct stat stat; + ret = sys_stat(real_path, &newbuf); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "stat on %s failed ", real_path); + return -1; + } - MAKE_HANDLE_GFID_PATH (path, this, gfid, NULL); + if (!oldbuf) + return ret; - ret = lstat (path, &stat); + if (newbuf.st_ino != oldbuf->st_ino || newbuf.st_dev != oldbuf->st_dev) { + gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_HANDLE_CREATE, + "mismatching ino/dev between file %s (%lld/%lld) " + "and handle %s (%lld/%lld)", + oldpath, (long long)oldbuf->st_ino, (long long)oldbuf->st_dev, + newpath, (long long)newbuf.st_ino, (long long)newbuf.st_dev); + ret = -1; + } - if (ret == -1) { - if (errno != ENOENT) { - gf_log (this->name, GF_LOG_WARNING, - "%s: %s", path, strerror (errno)); - } - goto out; - } + return ret; +} - ret = unlink (path); - if (ret == -1) { - gf_log (this->name, GF_LOG_WARNING, - "unlink %s failed (%s)", path, strerror (errno)); - } +int +posix_handle_unset_gfid(xlator_t *this, uuid_t gfid) +{ + int ret = 0; + struct stat stat; + int index = 0; + int dfd = 0; + char newstr[POSIX_GFID_HASH2_LEN] = { + 0, + }; + struct posix_private *priv = this->private; + + index = gfid[0]; + dfd = priv->arrdfd[index]; + + snprintf(newstr, sizeof(newstr), "%02x/%s", gfid[1], uuid_utoa(gfid)); + ret = sys_fstatat(dfd, newstr, &stat, AT_SYMLINK_NOFOLLOW); + + if (ret == -1) { + if (errno != ENOENT) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_DELETE, "%s", + newstr); + } + goto out; + } + + ret = sys_unlinkat(dfd, newstr); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_DELETE, + "unlink %s is failed", newstr); + } out: - return ret; + return ret; } - int -posix_handle_unset (xlator_t *this, uuid_t gfid, const char *basename) +posix_handle_unset(xlator_t *this, uuid_t gfid, const char *basename) { - int ret; - struct iatt stat; - char *path = NULL; - - - if (!basename) { - ret = posix_handle_unset_gfid (this, gfid); - return ret; - } - - MAKE_HANDLE_PATH (path, this, gfid, basename); + int ret; + struct iatt stat; + char *path = NULL; - ret = posix_istat (this, gfid, basename, &stat); + if (!basename) { + ret = posix_handle_unset_gfid(this, gfid); + return ret; + } - if (ret == -1) { - gf_log (this->name, GF_LOG_WARNING, - "%s: %s", path, strerror (errno)); - return -1; - } + MAKE_HANDLE_PATH(path, this, gfid, basename); + if (!path) { + gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_HANDLE_DELETE, + "Failed to create handle path for %s (%s)", basename, + uuid_utoa(gfid)); + return -1; + } + + /* stat is being used only for gfid, so passing a NULL inode + * doesn't fetch time attributes which is fine + */ + ret = posix_istat(this, NULL, gfid, basename, &stat); + if (ret == -1) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_DELETE, "%s", + path); + return -1; + } - ret = posix_handle_unset_gfid (this, stat.ia_gfid); + ret = posix_handle_unset_gfid(this, stat.ia_gfid); - return ret; + return ret; } - int -posix_create_link_if_gfid_exists (xlator_t *this, uuid_t gfid, - char *real_path) +posix_create_link_if_gfid_exists(xlator_t *this, uuid_t gfid, char *real_path, + inode_table_t *itable) { - int ret = -1; - struct stat stbuf = {0,}; - char *newpath = NULL; - - MAKE_HANDLE_PATH (newpath, this, gfid, NULL); - ret = lstat (newpath, &stbuf); - if (!ret) { -#ifdef HAVE_LINKAT - /* - * Use linkat if the target may be a symlink to a directory - * or without an existing target. See comment about linkat() - * usage in posix_link() in posix.c for details - */ - ret = linkat (AT_FDCWD, newpath, AT_FDCWD, real_path, 0); -#else - ret = link (newpath, real_path); -#endif - } - + int ret = -1; + char *newpath = NULL; + char *unlink_path = NULL; + uint64_t ctx_int = 0; + inode_t *inode = NULL; + struct stat stbuf = { + 0, + }; + struct posix_private *priv = NULL; + posix_inode_ctx_t *ctx = NULL; + + priv = this->private; + + MAKE_HANDLE_PATH(newpath, this, gfid, NULL); + if (!newpath) { + gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_HANDLE_CREATE, + "Failed to create handle path (%s)", uuid_utoa(gfid)); return ret; + } + + ret = sys_lstat(newpath, &stbuf); + if (!ret) { + ret = sys_link(newpath, real_path); + } else { + inode = inode_find(itable, gfid); + if (!inode) + return -1; + + LOCK(&inode->lock); + { + ret = __posix_inode_ctx_get_all(inode, this, &ctx); + if (ret) + goto unlock; + + if (ctx->unlink_flag != GF_UNLINK_TRUE) { + ret = -1; + goto unlock; + } + + POSIX_GET_FILE_UNLINK_PATH(priv->base_path, gfid, unlink_path); + ret = sys_link(unlink_path, real_path); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "Failed to link " + "%s with %s", + real_path, unlink_path); + goto unlock; + } + ret = sys_rename(unlink_path, newpath); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_HANDLE_CREATE, + "Failed to link " + "%s with %s", + real_path, unlink_path); + goto unlock; + } + ctx_int = GF_UNLINK_FALSE; + ret = __posix_inode_ctx_set_unlink_flag(inode, this, ctx_int); + } + unlock: + UNLOCK(&inode->lock); + + inode_unref(inode); + } + + return ret; } |
