summaryrefslogtreecommitdiffstats
path: root/xlators
diff options
context:
space:
mode:
authorAnoop C S <achiraya@redhat.com>2015-02-27 15:14:08 +0530
committerVijay Bellur <vbellur@redhat.com>2015-03-16 03:36:37 -0700
commit0ef870741a2f49d47a02725aed13a95335a6e42f (patch)
treefa7e63dae2c23674d61172650a6785b8502d59b8 /xlators
parent393cdb2613250031fce92cab8dede9154514f816 (diff)
Features/trash : Combined patches for trash translator
This is the combined patch set for supporting trash feature. http://www.gluster.org/community/documentation/index.php/Features/Trash Current patch includes the following features: * volume set options for enabling trash globally and exclusively for internal operations like self-heal and re-balance * volume set options for setting the eliminate path, trash directory path and maximum trashable file size. * test script for checking the functionality of the feature * brief documentation on different aspects of trash feature. Change-Id: Ic7486982dcd6e295d1eba0f4d5ee6d33bf1b4cb3 BUG: 1132465 Signed-off-by: Anoop C S <achiraya@redhat.com> Signed-off-by: Jiffin Tony Thottan <jthottan@redhat.com> Reviewed-on: http://review.gluster.org/8312 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'xlators')
-rw-r--r--xlators/features/Makefile.am2
-rw-r--r--xlators/features/trash/src/Makefile.am2
-rw-r--r--xlators/features/trash/src/trash-mem-types.h3
-rw-r--r--xlators/features/trash/src/trash.c2635
-rw-r--r--xlators/features/trash/src/trash.h36
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-op-sm.c78
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c34
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.h1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volume-set.c22
9 files changed, 2086 insertions, 727 deletions
diff --git a/xlators/features/Makefile.am b/xlators/features/Makefile.am
index 8093441a043..dcb3cc8e5a7 100644
--- a/xlators/features/Makefile.am
+++ b/xlators/features/Makefile.am
@@ -1,4 +1,4 @@
SUBDIRS = locks quota read-only mac-compat quiesce marker index barrier \
- protect compress changelog gfid-access $(GLUPY_SUBDIR) qemu-block snapview-client snapview-server # trash path-converter # filter
+ protect compress changelog gfid-access $(GLUPY_SUBDIR) qemu-block snapview-client snapview-server trash # path-converter # filter
CLEANFILES =
diff --git a/xlators/features/trash/src/Makefile.am b/xlators/features/trash/src/Makefile.am
index 5251eb08256..2000359a6a9 100644
--- a/xlators/features/trash/src/Makefile.am
+++ b/xlators/features/trash/src/Makefile.am
@@ -1,5 +1,5 @@
xlator_LTLIBRARIES = trash.la
-xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/testing/features
+xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features
trash_la_LDFLAGS = -module -avoid-version
diff --git a/xlators/features/trash/src/trash-mem-types.h b/xlators/features/trash/src/trash-mem-types.h
index 0e6ef572fcc..b7cad3ce3a9 100644
--- a/xlators/features/trash/src/trash-mem-types.h
+++ b/xlators/features/trash/src/trash-mem-types.h
@@ -15,7 +15,8 @@
enum gf_trash_mem_types_ {
gf_trash_mt_trash_private_t = gf_common_mt_end + 1,
gf_trash_mt_char,
- gf_trash_mt_trash_elim_pattern_t,
+ gf_trash_mt_uuid,
+ gf_trash_mt_trash_elim_path,
gf_trash_mt_end
};
#endif
diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c
index addeb66a053..4eecaf241c6 100644
--- a/xlators/features/trash/src/trash.c
+++ b/xlators/features/trash/src/trash.c
@@ -15,82 +15,598 @@
#include "trash.h"
#include "trash-mem-types.h"
+#define root_gfid (uuid_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+#define trash_gfid (uuid_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}
+#define internal_op_gfid (uuid_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6}
+/* Common routines used in this translator */
+
+/**
+ * When a directory/file is created under trash directory, it should have
+ * the same permission as before. This function will fetch permission from
+ * the existing directory and returns the same
+ */
+mode_t
+get_permission (char *path)
+{
+ mode_t mode = 0755;
+ struct stat sbuf = {0,};
+ struct iatt ibuf = {0,};
+ int ret = 0;
+
+ ret = stat (path, &sbuf);
+ if (!ret) {
+ iatt_from_stat (&ibuf, &sbuf);
+ mode = st_mode_from_ia (ibuf.ia_prot, ibuf.ia_type);
+ } else
+ gf_log ("trash", GF_LOG_DEBUG, "stat on %s failed"
+ " using default", path);
+ return mode;
+}
+
+/**
+ * For normalization, trash directory name is stored inside priv structure as
+ * '/trash_directory/'. As a result the trailing and leading slashes are being
+ * striped out for additional usage.
+ */
+int
+extract_trash_directory (char *priv_value, const char **trash_directory)
+{
+ char *tmp = NULL;
+ int ret = 0;
+
+ GF_VALIDATE_OR_GOTO("trash", priv_value, out);
+
+ tmp = gf_strdup (priv_value + 1);
+ if (!tmp) {
+ ret = ENOMEM;
+ goto out;
+ }
+ if (tmp[strlen(tmp)-1] == '/')
+ tmp[strlen(tmp)-1] = '\0';
+ *trash_directory = gf_strdup (tmp);
+ if (!(*trash_directory)) {
+ ret = ENOMEM;
+ goto out;
+ }
+out:
+ if (tmp)
+ GF_FREE (tmp);
+ return ret;
+}
+
+/**
+ * The trash directory path should be append at begining of file path for
+ * delete or truncate operations. Normal trashing moves the contents to
+ * trash directory and trashing done by internal operations are moved to
+ * internal_op directory inside trash.
+ */
+void
+copy_trash_path (const char *priv_value, gf_boolean_t internal, char *path)
+{
+ char trash_path[PATH_MAX] = {0,};
+
+ strcpy (trash_path, priv_value);
+ if (internal)
+ strcat (trash_path, "internal_op/");
+
+ strcpy (path, trash_path);
+}
+
+/**
+ * This function performs the reverse operation of copy_trash_path(). It gives
+ * out a pointer, whose starting value will be the path inside trash directory,
+ * similar to orginal path.
+ */
+void
+remove_trash_path (const char *path, gf_boolean_t internal, char *rem_path)
+{
+
+ rem_path = strchr (path + 1, '/');
+ if (internal)
+ rem_path = strchr (path + 1, '/');
+}
+
+/**
+ * Check whether the path includes trash directory or internal op directory
+ * inside trash. This check is used to make sure that we avoid deletion,
+ * rename and creation operations from trash directory.
+ */
+int
+check_whether_trash_directory (const char *path,
+ const char *trash_directory_path)
+{
+ char tmp_path[PATH_MAX] = {0,};
+ char internal_op_path[PATH_MAX] = {0,};
+ int ret = 0;
+
+ if (path[strlen(path)-1] == '/')
+ sprintf (tmp_path, "%s", path);
+ else
+ sprintf (tmp_path, "%s/", path);
+
+ copy_trash_path (trash_directory_path, _gf_true, internal_op_path);
+ ret = strcmp (tmp_path, trash_directory_path) &&
+ strcmp (tmp_path, internal_op_path);
+
+ return ret;
+}
+
+/**
+ * Checks whether the given path reside under the specified eliminate path
+ */
+int
+check_whether_eliminate_path (trash_elim_path *trav, const char *path)
+{
+ int match = 0;
+
+ while (trav) {
+ if (strncmp (path, trav->path, strlen(trav->path)) == 0) {
+ match++;
+ break;
+ }
+ trav = trav->next;
+ }
+ return match;
+}
+
+/**
+ * Stores the eliminate path into internal eliminate path structure
+ */
+int
+store_eliminate_path (char *str, trash_elim_path *eliminate)
+{
+ trash_elim_path *trav = NULL;
+ char *component = NULL;
+ char elm_path[PATH_MAX] = {0,};
+ int ret = 0;
+ char *strtokptr = NULL;
+
+ component = strtok_r (str, ",", &strtokptr);
+ while (component) {
+ trav = GF_CALLOC (1, sizeof (*trav),
+ gf_trash_mt_trash_elim_path);
+ if (!trav) {
+ ret = ENOMEM;
+ goto out;
+ }
+ if (component[0] == '/')
+ sprintf(elm_path, "%s", component);
+ else
+ sprintf(elm_path, "/%s", component);
+
+ if (component[strlen(component)-1] != '/')
+ strcat (elm_path, "/");
+
+ trav->path = gf_strdup(elm_path);
+ if (!trav->path) {
+ ret = ENOMEM;
+ gf_log ("trash", GF_LOG_DEBUG, "out of memory");
+ goto out;
+ }
+ trav->next = eliminate;
+ eliminate = trav;
+ component = strtok_r (NULL, ",", &strtokptr);
+ }
+out:
+ return ret;
+}
+
+/**
+ * Appends time stamp to given string
+ */
+void
+append_time_stamp (char *name)
+{
+ int i;
+ char timestr[64] = {0,};
+
+ gf_time_fmt (timestr, sizeof(timestr), time (NULL),
+ gf_timefmt_F_HMS);
+
+ /* removing white spaces in timestamp */
+ for (i = 0; i < strlen (timestr); i++) {
+ if (timestr[i] == ' ')
+ timestr[i] = '_';
+ }
+ strcat (name, "_");
+ strcat (name, timestr);
+}
+
+/**
+ * Wipe the memory used by trash location variable
+ */
+void
+trash_local_wipe (trash_local_t *local)
+{
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
+
+ loc_wipe (&local->loc);
+ loc_wipe (&local->newloc);
+
+ if (local->fd)
+ fd_unref (local->fd);
+ if (local->newfd)
+ fd_unref (local->newfd);
+
+ mem_put (local);
+out:
+ return;
+}
+
+/**
+ * Wipe the memory used by eliminate path through a
+ * recursive call
+ */
+void
+wipe_eliminate_path (trash_elim_path *trav)
+{
+ if (trav) {
+ wipe_eliminate_path (trav->next);
+ GF_FREE (trav->path);
+ GF_FREE (trav);
+ }
+}
+
int32_t
trash_ftruncate_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
struct iovec *vector, int32_t count,
- struct iatt *stbuf, struct iobref *iobuf);
+ struct iatt *stbuf, struct iobref *iobuf,
+ dict_t *xdata);
int32_t
trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
- struct iatt *prebuf, struct iatt *postbuf);
+ struct iatt *prebuf, struct iatt *postbuf,
+ dict_t *xdata);
int32_t
trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, inode_t *inode,
struct iatt *stbuf, struct iatt *preparent,
- struct iatt *postparent);
+ struct iatt *postparent, dict_t *xdata);
+
+int32_t
+trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *stbuf, struct iatt *preparent,
+ struct iatt *postparent, dict_t *xdata);
int32_t
trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, struct iatt *buf,
struct iatt *preoldparent, struct iatt *postoldparent,
- struct iatt *prenewparent, struct iatt *postnewparent);
+ struct iatt *prenewparent, struct iatt *postnewparent,
+ dict_t *xdata);
-void
-trash_local_wipe (trash_local_t *local)
+/**
+ * This getxattr calls returns existing trash directory path in
+ * the dictionary
+ */
+int32_t
+trash_notify_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, dict_t *dict,
+ dict_t *xdata)
{
- if (!local)
+ data_t *data = NULL;
+ trash_private_t *priv = NULL;
+ int ret = 0;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ data = dict_get (dict, GET_ANCESTRY_PATH_KEY);
+ if (!data) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "oldtrash-directory doesnot exists");
+ priv->oldtrash_dir = gf_strdup (priv->newtrash_dir);
+ if (!priv->oldtrash_dir) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ } else {
+ priv->oldtrash_dir = gf_strdup (data->data);
+ if (!priv->oldtrash_dir) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ gf_log (this->name, GF_LOG_DEBUG, "old trash directory"
+ " path is %s", data->data);
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * This is a nameless look up for old trash directory
+ * The lookup is based on gfid, because trash directory
+ * has fixed gfid.
+ */
+int32_t
+trash_notify_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, dict_t *xdata,
+ struct iatt *postparent)
+{
+ trash_private_t *priv = NULL;
+ loc_t loc = {0,};
+ int ret = 0;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ if (op_ret == 0) {
+
+ gf_log (this->name, GF_LOG_DEBUG, "inode found with gfid %s",
+ uuid_utoa(buf->ia_gfid));
+
+ uuid_copy (loc.gfid, trash_gfid);
+
+ /* Find trash inode using available information */
+ priv->trash_inode = inode_link (inode, NULL, NULL, buf);
+
+ loc.inode = inode_ref (priv->trash_inode);
+
+ /*Used to find path of old trash directory*/
+ STACK_WIND (frame, trash_notify_getxattr_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->getxattr, &loc,
+ GET_ANCESTRY_PATH_KEY, xdata);
+ }
+
+ /* If there is no old trash directory we set its value to new one,
+ * which is the valid condition for trash directory creation
+ */
+ else {
+ priv->oldtrash_dir = gf_strdup (priv->newtrash_dir);
+ if (!priv->oldtrash_dir) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ goto out;
+ }
+ }
+
+out:
+ loc_wipe (&loc);
+ return ret;
+}
+
+int32_t
+trash_internal_op_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent, dict_t *xdata)
+{
+ if (op_ret != 0)
+ gf_log (this->name, GF_LOG_ERROR, "mkdir failed for "
+ "internal op directory : %s", strerror (op_errno));
+ return op_ret;
+}
+
+/**
+ * This is the call back of mkdir fop initated using STACK_WIND in
+ * notify function which is used to create trash directory in the brick
+ * when a volume starts.The frame of the mkdir must destroyed from
+ * this function itself since it was created by trash xlator
+ */
+int32_t
+trash_notify_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent, dict_t *xdata)
+{
+ uuid_t *gfid_ptr = NULL;
+ loc_t loc = {0, };
+ int ret = 0;
+ dict_t *dict = NULL;
+ char internal_op_path[PATH_MAX] = {0,};
+ trash_private_t *priv = NULL;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ dict = dict_new ();
+ if (!dict) {
+ ret = -1;
goto out;
+ }
+ if ((op_ret == 0) || (op_ret == -1 && op_errno == EEXIST)) {
+ gfid_ptr = GF_CALLOC (1, sizeof(uuid_t),
+ gf_common_mt_uuid_t);
+ if (!gfid_ptr) {
+ ret = ENOMEM;
+ goto out;
+ }
+ uuid_copy (*gfid_ptr, internal_op_gfid);
- loc_wipe (&local->loc);
- loc_wipe (&local->newloc);
+ uuid_copy (loc.gfid, internal_op_gfid);
+ uuid_copy (loc.pargfid, trash_gfid);
+ loc.name = gf_strdup ("internal_op");
- if (local->fd)
- fd_unref (local->fd);
+ if (!loc.name) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ sprintf (internal_op_path, "%s%s",
+ priv->newtrash_dir, loc.name);
- if (local->newfd)
- fd_unref (local->newfd);
+ loc.path = gf_strdup (internal_op_path);
- mem_put (local);
+ if (!loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ loc.inode = inode_new (priv->trash_itable);
+ loc.inode->ia_type = IA_IFDIR;
+ /* Fixed gfid is set for trash directory with
+ * this function
+ */
+ ret = dict_set_dynptr (dict, "gfid-req", gfid_ptr,
+ sizeof (uuid_t));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "setting key gfid-req failed");
+ goto out;
+ }
+
+ /* The mkdir call for creating trash directory */
+ STACK_WIND (frame, trash_internal_op_mkdir_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir, &loc, 0755,
+ 0022, dict);
+ /* After creating we must call other notify functions */
+ default_notify (this, GF_EVENT_CHILD_UP, NULL);
+ } else {
+ gf_log (this->name, GF_LOG_ERROR, "mkdir failed for trash"
+ " directory : %s", strerror (op_errno));
+ }
+
+ STACK_DESTROY (frame->root);
out:
- return;
+ if (ret && gfid_ptr)
+ GF_FREE (gfid_ptr);
+ if (dict)
+ dict_unref (dict);
+ return 0;
+}
+
+int32_t
+trash_notify_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ struct iatt *preoldparent, struct iatt *postoldparent,
+ struct iatt *prenewparent, struct iatt *postnewparent,
+ dict_t *xdata)
+{
+ if ((op_ret == 0) || (op_ret == -1 && op_errno == EEXIST)) {
+ /* After creating we must call other notify functions */
+ default_notify (this, GF_EVENT_CHILD_UP, NULL);
+ } else {
+ gf_log (this->name, GF_LOG_ERROR, "rename failed: %s",
+ strerror (op_errno));
+ }
+
+ STACK_DESTROY (frame->root);
+ return op_ret;
+}
+
+/**
+ * This is the call back of rename fop initated using STACK_WIND in
+ * reconfigure function which is used to rename trash directory in
+ * the brick when we perform volume set.This frame must destroyed
+ * from this function itself since it was created by trash xlator
+ */
+int32_t
+trash_reconf_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ struct iatt *preoldparent, struct iatt *postoldparent,
+ struct iatt *prenewparent, struct iatt *postnewparent,
+ dict_t *xdata)
+{
+ if (op_ret == -1 && op_errno == EEXIST) {
+
+ gf_log (this->name, GF_LOG_ERROR, "rename failed: %s",
+ strerror (op_errno));
+ }
+
+ STACK_DESTROY (frame->root);
+
+ return op_ret;
}
int32_t
+trash_common_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent, dict_t *xdata)
+{
+ STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno, inode,
+ buf, preparent, postparent, xdata);
+ return 0;
+}
+
+int32_t
+trash_common_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ struct iatt *preoldparent, struct iatt *postoldparent,
+ struct iatt *prenewparent, struct iatt *postnewparent,
+ dict_t *xdata)
+{
+ STACK_UNWIND_STRICT (rename, frame, op_ret, op_errno, buf, preoldparent,
+ postoldparent, prenewparent, postnewparent, xdata);
+ return 0;
+}
+
+int32_t
+trash_common_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *preparent,
+ struct iatt *postparent,
+ dict_t *xdata)
+{
+ STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno, preparent,
+ postparent, xdata);
+ return 0;
+}
+
+/**
+ * move backs from trash translator to unlink call
+ */
+int32_t
trash_common_unwind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
- struct iatt *preparent, struct iatt *postparent)
+ struct iatt *preparent, struct iatt *postparent,
+ dict_t *xdata)
{
- TRASH_STACK_UNWIND (unlink, frame, op_ret, op_errno, preparent, postparent);
+ TRASH_STACK_UNWIND (unlink, frame, op_ret, op_errno, preparent,
+ postparent, xdata);
return 0;
}
+/**
+ * If the path is not present in the trash directory,it will recursively
+ * call this call-back and one by one directories will be created from
+ * the starting
+ */
int32_t
trash_unlink_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, inode_t *inode,
struct iatt *stbuf, struct iatt *preparent,
- struct iatt *postparent)
+ struct iatt *postparent, dict_t *xdata)
{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *tmp_path = NULL;
- char *tmp_dirname = NULL;
- char *dir_name = NULL;
- int32_t count = 0;
- int32_t loop_count = 0;
- int i = 0;
- loc_t tmp_loc = {0,};
+ trash_local_t *local = NULL;
+ char *tmp_str = NULL;
+ char *tmp_path = NULL;
+ char *tmp_dirname = NULL;
+ char *tmp_stat = NULL;
+ char real_path[PATH_MAX] = {0,};
+ char *dir_name = NULL;
+ size_t count = 0;
+ int32_t loop_count = 0;
+ int i = 0;
+ loc_t tmp_loc = {0,};
+ trash_private_t *priv = NULL;
+ int ret = 0;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
+
tmp_str = gf_strdup (local->newpath);
if (!tmp_str) {
gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = -1;
goto out;
}
loop_count = local->loop_count;
+ /* The directory is not present , need to create it */
if ((op_ret == -1) && (op_errno == ENOENT)) {
tmp_dirname = strchr (tmp_str, '/');
while (tmp_dirname) {
@@ -102,31 +618,53 @@ trash_unlink_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
break;
tmp_dirname = strchr (tmp_str + count + 1, '/');
}
- tmp_path = memdup (local->newpath, count);
+ tmp_path = gf_memdup (local->newpath, count + 1);
if (!tmp_path) {
gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = ENOMEM;
goto out;
}
+ tmp_path[count] = '\0';
- tmp_loc.path = tmp_path;
+ loc_copy (&tmp_loc, &local->loc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
- /* TODO:create the directory with proper permissions */
+ /* Stores the the name of directory to be created */
+ tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1);
+ if (!tmp_loc.name) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
STACK_WIND_COOKIE (frame, trash_unlink_mkdir_cbk, tmp_path,
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
-
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir,
+ &tmp_loc, get_permission(real_path),
+ 0022, xdata);
+ loc_wipe (&tmp_loc);
goto out;
}
+ /* Given path is created , comparing to the required path */
if (op_ret == 0) {
dir_name = dirname (tmp_str);
- if (strcmp((char*)cookie, dir_name) == 0) {
+ if (strcmp((char *)cookie, dir_name) == 0) {
+ /* File path exists we can rename it*/
+ loc_copy (&tmp_loc, &local->loc);
tmp_loc.path = local->newpath;
STACK_WIND (frame, trash_unlink_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc, &tmp_loc);
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rename,
+ &local->loc, &tmp_loc, xdata);
goto out;
}
}
@@ -136,7 +674,10 @@ trash_unlink_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
loop_count = ++local->loop_count;
}
UNLOCK (&frame->lock);
+
tmp_dirname = strchr (tmp_str, '/');
+
+ /* Path is not completed , need to create remaining path */
while (tmp_dirname) {
count = tmp_dirname - tmp_str;
if (count == 0)
@@ -146,492 +687,356 @@ trash_unlink_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
break;
tmp_dirname = strchr (tmp_str + count + 1, '/');
}
- tmp_path = memdup (local->newpath, count);
+ tmp_path = gf_memdup (local->newpath, count + 1);
if (!tmp_path) {
gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = -1;
+ goto out;
+ }
+ tmp_path[count] = '\0';
+
+ loc_copy (&tmp_loc, &local->loc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = -1;
+ goto out;
+ }
+
+ /* Stores the the name of directory to be created */
+ tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1);
+ if (!tmp_loc.name) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = -1;
goto out;
}
- tmp_loc.path = tmp_path;
+
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
STACK_WIND_COOKIE (frame, trash_unlink_mkdir_cbk, tmp_path,
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir, &tmp_loc,
+ get_permission(real_path), 0022, xdata);
out:
- GF_FREE (cookie);
- GF_FREE (tmp_str);
-
- return 0;
+ if (tmp_path)
+ GF_FREE (tmp_path);
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ return ret;
}
-int32_t
-trash_rename_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, inode_t *inode,
- struct iatt *stbuf, struct iatt *preparent,
- struct iatt *postparent);
-
+/**
+ * The name of unlinking file should be renamed as starting
+ * from trash directory as mentioned in the mount point
+ */
int32_t
trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, struct iatt *buf,
struct iatt *preoldparent, struct iatt *postoldparent,
- struct iatt *prenewparent, struct iatt *postnewparent)
+ struct iatt *prenewparent, struct iatt *postnewparent,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *dir_name = NULL;
- char *tmp_cookie = NULL;
- loc_t tmp_loc = {0,};
+ trash_local_t *local = NULL;
+ trash_private_t *priv = NULL;
+ char *tmp_str = NULL;
+ char *dir_name = NULL;
+ char *tmp_cookie = NULL;
+ loc_t tmp_loc = {0,};
+ char *tmp_stat = NULL;
+ char real_path[PATH_MAX] = {0,};
+ int ret = 0;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if ((op_ret == -1) && (op_errno == ENOENT)) {
+ /* the file path doesnot exists we want to create path
+ * for the file
+ */
tmp_str = gf_strdup (local->newpath);
if (!tmp_str) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
}
- dir_name = dirname (tmp_str);
+ dir_name = dirname (tmp_str); /* stores directory name */
- tmp_loc.path = dir_name;
+ loc_copy (&tmp_loc, &local->loc);
+ tmp_loc.path = gf_strdup (dir_name);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
tmp_cookie = gf_strdup (dir_name);
if (!tmp_cookie) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
}
- /* TODO: create the directory with proper permissions */
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_str, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
+ /* create the directory with proper permissions */
STACK_WIND_COOKIE (frame, trash_unlink_mkdir_cbk, tmp_cookie,
FIRST_CHILD(this),
FIRST_CHILD(this)->fops->mkdir,
- &tmp_loc, 0755, NULL);
-
- GF_FREE (tmp_str);
-
- return 0;
+ &tmp_loc, get_permission(real_path),
+ 0022, xdata);
+ loc_wipe (&tmp_loc);
+ goto out;
}
if ((op_ret == -1) && (op_errno == ENOTDIR)) {
-
+ /* if entry is already present in trash directory,
+ * new one is not copied*/
gf_log (this->name, GF_LOG_DEBUG,
"target(%s) exists, cannot keep the copy, deleting",
local->newpath);
STACK_WIND (frame, trash_common_unwind_cbk,
- this->children->xlator,
- this->children->xlator->fops->unlink, &local->loc);
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->unlink,
+ &local->loc, 0, xdata);
- return 0;
+ goto out;
}
if ((op_ret == -1) && (op_errno == EISDIR)) {
+
+ /* if entry is directory,we remove directly */
gf_log (this->name, GF_LOG_DEBUG,
"target(%s) exists as directory, cannot keep copy, "
"deleting", local->newpath);
STACK_WIND (frame, trash_common_unwind_cbk,
FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->unlink, &local->loc);
- return 0;
+ FIRST_CHILD(this)->fops->unlink,
+ &local->loc, 0, xdata);
+ goto out;
}
/* All other cases, unlink should return success */
TRASH_STACK_UNWIND (unlink, frame, 0, op_errno, &local->preparent,
- &local->postparent);
+ &local->postparent, xdata);
+out:
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ if (tmp_cookie)
+ GF_FREE (tmp_cookie);
- return 0;
+ return ret;
}
-
-
+/**
+ * move backs from trash translator to truncate call
+ */
int32_t
trash_common_unwind_buf_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
- struct iatt *prebuf, struct iatt *postbuf)
+ struct iatt *prebuf, struct iatt *postbuf,
+ dict_t *xdata)
{
- TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, prebuf, postbuf);
+ TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, prebuf,
+ postbuf, xdata);
return 0;
}
-int
-trash_common_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, struct iatt *stbuf,
- struct iatt *preoldparent, struct iatt *postoldparent,
- struct iatt *prenewparent, struct iatt *postnewparent)
-{
- TRASH_STACK_UNWIND (rename, frame, op_ret, op_errno, stbuf, preoldparent,
- postoldparent, prenewparent, postnewparent);
- return 0;
-}
int32_t
trash_unlink_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, struct iatt *buf)
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ dict_t *xdata)
{
- trash_private_t *priv = NULL;
- trash_local_t *local = NULL;
- loc_t new_loc = {0,};
+ trash_private_t *priv = NULL;
+ trash_local_t *local = NULL;
+ loc_t new_loc = {0,};
+ int ret = 0;
priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
- if (-1 == op_ret) {
+ if (op_ret == -1) {
gf_log (this->name, GF_LOG_DEBUG, "%s: %s",
local->loc.path, strerror (op_errno));
- goto fail;
+ TRASH_STACK_UNWIND (unlink, frame, op_ret, op_errno, buf,
+ NULL, xdata);
+ ret = -1;
+ goto out;
}
- if ((buf->ia_size == 0) ||
- (buf->ia_size > priv->max_trash_file_size)) {
- /* if the file is too big or zero, just unlink it */
+ /* if the file is too big just unlink it */
- if (buf->ia_size > priv->max_trash_file_size) {
- gf_log (this->name, GF_LOG_DEBUG,
+ if (buf->ia_size > (priv->max_trash_file_size)) {
+ gf_log (this->name, GF_LOG_DEBUG,
"%s: file size too big (%"PRId64") to "
"move into trash directory",
local->loc.path, buf->ia_size);
- }
STACK_WIND (frame, trash_common_unwind_cbk,
- this->children->xlator,
- this->children->xlator->fops->unlink, &local->loc);
- return 0;
- }
-
- new_loc.path = local->newpath;
-
- STACK_WIND (frame, trash_unlink_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc, &new_loc);
-
- return 0;
-
-fail:
- TRASH_STACK_UNWIND (unlink, frame, op_ret, op_errno, buf,
- NULL);
-
- return 0;
-
-}
-
-int32_t
-trash_rename_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, struct iatt *buf,
- struct iatt *preoldparent, struct iatt *postoldparent,
- struct iatt *prenewparent, struct iatt *postnewparent)
-{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *dir_name = NULL;
- char *tmp_path = NULL;
- loc_t tmp_loc = {0,};
-
- local = frame->local;
- if ((op_ret == -1) && (op_errno == ENOENT)) {
- tmp_str = gf_strdup (local->newpath);
- if (!tmp_str) {
- gf_log (this->name, GF_LOG_DEBUG, "out of memory");
- }
- dir_name = dirname (tmp_str);
-
- /* check for the errno, if its ENOENT create directory and call
- * rename later
- */
- tmp_path = gf_strdup (dir_name);
- if (!tmp_path) {
- gf_log (this->name, GF_LOG_DEBUG, "out of memory");
- }
- tmp_loc.path = tmp_path;
-
- /* TODO: create the directory with proper permissions */
- STACK_WIND_COOKIE (frame, trash_rename_mkdir_cbk, tmp_path,
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
-
- GF_FREE (tmp_str);
- return 0;
- }
-
- if ((op_ret == -1) && (op_errno == ENOTDIR)) {
- gf_log (this->name, GF_LOG_DEBUG,
- "target(%s) exists, cannot keep the dest entry(%s): "
- "renaming", local->newpath, local->origpath);
- } else if ((op_ret == -1) && (op_errno == EISDIR)) {
- gf_log (this->name, GF_LOG_DEBUG,
- "target(%s) exists as a directory, cannot keep the "
- "copy (%s), renaming", local->newpath, local->origpath);
- }
-
- STACK_WIND (frame, trash_common_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename, &local->loc,
- &local->newloc);
-
- return 0;
-}
-
-
-int32_t
-trash_rename_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, inode_t *inode,
- struct iatt *stbuf, struct iatt *preparent,
- struct iatt *postparent)
-{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *tmp_path = NULL;
- char *tmp_dirname = NULL;
- char *dir_name = NULL;
- int32_t count = 0;
- loc_t tmp_loc = {0,};
-
- local = frame->local;
- tmp_str = gf_strdup (local->newpath);
- if (!tmp_str) {
- gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->unlink, &local->loc,
+ 0, xdata);
goto out;
}
- if ((op_ret == -1) && (op_errno == ENOENT)) {
- tmp_dirname = strchr (tmp_str, '/');
- while (tmp_dirname) {
- count = tmp_dirname - tmp_str;
- if (count == 0)
- count = 1;
-
- tmp_dirname = strchr (tmp_str + count + 1, '/');
-
- tmp_path = memdup (local->newpath, count);
- if (!tmp_path) {
- gf_log (this->name, GF_LOG_DEBUG, "out of memory");
- }
-
- tmp_loc.path = tmp_path;
-
- /* TODO: create the directory with proper permissions */
- STACK_WIND_COOKIE (frame, trash_rename_mkdir_cbk,
- tmp_path, this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
- }
-
+ /* Copies new path for renaming */
+ loc_copy (&new_loc, &local->loc);
+ new_loc.path = gf_strdup (local->newpath);
+ if (!new_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
goto out;
}
- dir_name = dirname (tmp_str);
- if (strcmp ((char*)cookie, dir_name) == 0) {
- tmp_loc.path = local->newpath;
- STACK_WIND (frame, trash_rename_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->newloc, &tmp_loc);
- }
+ STACK_WIND (frame, trash_unlink_rename_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rename,
+ &local->loc, &new_loc, xdata);
out:
- GF_FREE (cookie); /* strdup (dir_name) was sent here :) */
- GF_FREE (tmp_str);
-
- return 0;
-}
-
-int32_t
-trash_rename_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, inode_t *inode,
- struct iatt *buf, dict_t *xattr,
- struct iatt *postparent)
-{
- trash_private_t *priv = NULL;
- trash_local_t *local = NULL;
- loc_t tmp_loc = {0,};
-
- local = frame->local;
- priv = this->private;
-
- if (op_ret == -1) {
- STACK_WIND (frame, trash_common_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc, &local->newloc);
- return 0;
- }
- if ((buf->ia_size == 0) ||
- (buf->ia_size > priv->max_trash_file_size)) {
- /* if the file is too big or zero, just unlink it */
-
- if (buf->ia_size > priv->max_trash_file_size) {
- gf_log (this->name, GF_LOG_DEBUG,
- "%s: file size too big (%"PRId64") to "
- "move into trash directory",
- local->newloc.path, buf->ia_size);
- }
-
- STACK_WIND (frame, trash_common_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc, &local->newloc);
- return 0;
- }
+ loc_wipe (&new_loc);
- tmp_loc.path = local->newpath;
+ return ret;
- STACK_WIND (frame, trash_rename_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->newloc, &tmp_loc);
-
- return 0;
}
-
+/**
+ * Unlink is called internally by rm system call and also
+ * by internal operations of gluster such as self-heal
+ */
int32_t
-trash_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc,
- loc_t *newloc)
+trash_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags,
+ dict_t *xdata)
{
- trash_elim_pattern_t *trav = NULL;
- trash_private_t *priv = NULL;
- trash_local_t *local = NULL;
- char timestr[64] = {0,};
- int32_t match = 0;
+ trash_private_t *priv = NULL;
+ trash_local_t *local = NULL;/* files inside trash */
+ int32_t match = 0;
+ char *pathbuf = NULL;
+ int ret = 0;
priv = this->private;
- if (priv->eliminate) {
- trav = priv->eliminate;
- while (trav) {
- if (fnmatch(trav->pattern, newloc->name, 0) == 0) {
- match++;
- break;
- }
- trav = trav->next;
- }
- }
-
- if ((strncmp (oldloc->path, priv->trash_dir,
- strlen (priv->trash_dir)) == 0) || match) {
- /* Trying to rename from the trash dir,
- do the actual rename */
- STACK_WIND (frame, trash_common_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- oldloc, newloc);
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
- return 0;
- }
-
- local = mem_get0 (this->local_pool);
- if (!local) {
- gf_log (this->name, GF_LOG_ERROR, "out of memory");
- TRASH_STACK_UNWIND (rename, frame, -1, ENOMEM,
- NULL, NULL, NULL, NULL, NULL);
- return 0;
+ /* If trash is not active or not enabled through cli, then
+ * we bypass and wind back
+ */
+ if (!priv->state) {
+ STACK_WIND (frame, trash_common_unwind_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->unlink, loc, 0,
+ xdata);
+ goto out;
}
- frame->local = local;
- loc_copy (&local->loc, oldloc);
-
- loc_copy (&local->newloc, newloc);
-
- strcpy (local->origpath, newloc->path);
- strcpy (local->newpath, priv->trash_dir);
- strcat (local->newpath, newloc->path);
-
- {
- /* append timestamp to file name */
- /* TODO: can we make it optional? */
- gf_time_ftm (timestr, sizeof timestr, time (NULL),
- gf_timefmt_F_HMS);
- strcat (local->newpath, timestr);
+ /* The files removed by gluster internal operations such as self-heal,
+ * should moved to trash directory , but files by client should not
+ * moved
+ */
+ if ((frame->root->pid < 0) && !priv->internal) {
+ STACK_WIND (frame, trash_common_unwind_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->unlink, loc, 0,
+ xdata);
+ goto out;
}
+ /* loc need some gfid which will be present in inode */
+ uuid_copy (loc->gfid, loc->inode->gfid);
- /* Send a lookup call on newloc, to ensure we are not
- overwriting */
- STACK_WIND (frame, trash_rename_lookup_cbk,
- this->children->xlator,
- this->children->xlator->fops->lookup, newloc, 0);
-
- return 0;
-}
-
-int32_t
-trash_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc)
-{
- trash_elim_pattern_t *trav = NULL;
- trash_private_t *priv = NULL;
- trash_local_t *local = NULL;
- char timestr[64] = {0,};
- int32_t match = 0;
-
- priv = this->private;
-
- if (priv->eliminate) {
- trav = priv->eliminate;
- while (trav) {
- if (fnmatch(trav->pattern, loc->name, 0) == 0) {
- match++;
- break;
- }
- trav = trav->next;
- }
+ /* Checking for valid location */
+ if (uuid_is_null (loc->gfid) && uuid_is_null (loc->inode->gfid)) {
+ gf_log (this->name, GF_LOG_DEBUG, "Bad address");
+ STACK_WIND (frame, trash_common_unwind_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->unlink, loc, 0,
+ xdata);
+ ret = EFAULT;
+ goto out;
}
- if ((strncmp (loc->path, priv->trash_dir,
- strlen (priv->trash_dir)) == 0) || (match)) {
+ /* This will be more accurate */
+ inode_path (loc->inode, NULL, &pathbuf);
+ /* Check whether the file is present under eliminate paths or
+ * inside trash directory. In both cases we don't need to move the
+ * file to trash directory. Instead delete it permanently
+ */
+ match = check_whether_eliminate_path (priv->eliminate, pathbuf);
+ if ((strncmp (pathbuf, priv->newtrash_dir,
+ strlen (priv->newtrash_dir)) == 0) || (match)) {
if (match) {
gf_log (this->name, GF_LOG_DEBUG,
- "%s: file matches eliminate pattern, "
- "not moved to trash", loc->name);
- } else {
- /* unlink from the trash-dir, not keeping any copy */
- ;
+ "%s is a file comes under an eliminate path, "
+ "so it is not moved to trash", loc->name);
}
+ /* Trying to unlink from the trash-dir. So do the
+ * actual unlink without moving to trash-dir.
+ */
STACK_WIND (frame, trash_common_unwind_cbk,
- this->children->xlator,
- this->children->xlator->fops->unlink, loc);
- return 0;
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->unlink, loc, 0,
+ xdata);
+ goto out;
}
local = mem_get0 (this->local_pool);
if (!local) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
- TRASH_STACK_UNWIND (unlink, frame, -1, ENOMEM, NULL, NULL);
- return 0;
+ TRASH_STACK_UNWIND (unlink, frame, -1, ENOMEM, NULL, NULL,
+ xdata);
+ ret = ENOMEM;
+ goto out;
}
frame->local = local;
loc_copy (&local->loc, loc);
- strcpy (local->origpath, loc->path);
- strcpy (local->newpath, priv->trash_dir);
- strcat (local->newpath, loc->path);
+ /* rename new location of file as starting from trash directory */
+ strcpy (local->origpath, pathbuf);
+ copy_trash_path (priv->newtrash_dir, (frame->root->pid < 0),
+ local->newpath);
+ strcat (local->newpath, pathbuf);
- {
- /* append timestamp to file name */
- /* TODO: can we make it optional? */
- gf_time_fmt (timestr, sizeof timestr, time (NULL),
- gf_timefmt_F_HMS);
- strcat (local->newpath, timestr);
- }
+ /* append timestamp to file name so that we can avoid
+ * name collisions inside trash
+ */
+ append_time_stamp (local->newpath);
LOCK_INIT (&frame->lock);
STACK_WIND (frame, trash_unlink_stat_cbk,
- this->children->xlator,
- this->children->xlator->fops->stat, loc);
-
- return 0;
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->stat, loc, xdata);
+out:
+ return ret;
}
+/**
+ * Use this when a failure occurs, and delete the newly created file
+ */
int32_t
trash_truncate_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
- struct iatt *preparent, struct iatt *postparent)
+ struct iatt *preparent, struct iatt *postparent,
+ dict_t *xdata)
{
- /* use this Function when a failure occurs, and
- delete the newly created file. */
- trash_local_t *local = NULL;
+ trash_local_t *local = NULL;
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if (op_ret == -1) {
gf_log (this->name, GF_LOG_DEBUG,
@@ -641,20 +1046,26 @@ trash_truncate_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
STACK_WIND (frame, trash_common_unwind_buf_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->truncate,
- &local->loc, local->fop_offset);
-
+ &local->loc, local->fop_offset, xdata);
+out:
return 0;
}
+/**
+ * Read from source file
+ */
int32_t
trash_truncate_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
struct iovec *vector, int32_t count,
- struct iatt *stbuf, struct iobref *iobuf)
+ struct iatt *stbuf, struct iobref *iobuf,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
+
+ trash_local_t *local = NULL;
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if (op_ret == -1) {
gf_log (this->name, GF_LOG_DEBUG,
@@ -663,28 +1074,34 @@ trash_truncate_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
STACK_WIND (frame, trash_truncate_unlink_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink,
- &local->newloc);
+ &local->newloc, 0, xdata);
goto out;
}
local->fsize = stbuf->ia_size;
STACK_WIND (frame, trash_truncate_writev_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->writev,
- local->newfd, vector, count, local->cur_offset, 0, iobuf);
+ local->newfd, vector, count, local->cur_offset, 0, iobuf,
+ xdata);
out:
return 0;
}
+/**
+ * Write to file created in trash directory
+ */
int32_t
trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
- struct iatt *prebuf, struct iatt *postbuf)
+ struct iatt *prebuf, struct iatt *postbuf,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
+ trash_local_t *local = NULL;
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if (op_ret == -1) {
/* Let truncate work, but previous copy is not preserved. */
@@ -693,7 +1110,8 @@ trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
strerror (op_errno));
STACK_WIND (frame, trash_truncate_unlink_cbk, FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->unlink, &local->newloc);
+ FIRST_CHILD(this)->fops->unlink, &local->newloc, 0,
+ xdata);
goto out;
}
@@ -703,7 +1121,7 @@ trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
STACK_WIND (frame, trash_truncate_readv_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->readv,
local->fd, (size_t)GF_BLOCK_READV_SIZE,
- local->cur_offset, 0);
+ local->cur_offset, 0, xdata);
goto out;
}
@@ -711,86 +1129,115 @@ trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
/* OOFH.....Finally calling Truncate. */
STACK_WIND (frame, trash_common_unwind_buf_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->truncate, &local->loc,
- local->fop_offset);
+ local->fop_offset, xdata);
out:
return 0;
}
-
-
+/**
+ * The source file is opened for reading and writing
+ */
int32_t
trash_truncate_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, fd_t *fd)
+ int32_t op_ret, int32_t op_errno, fd_t *fd,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
+ trash_local_t *local = NULL;
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if (op_ret == -1) {
- //Let truncate work, but previous copy is not preserved.
+ /* Let truncate work, but previous copy is not preserved. */
gf_log (this->name, GF_LOG_DEBUG,
"open on the existing file failed: %s",
strerror (op_errno));
STACK_WIND (frame, trash_truncate_unlink_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink,
- &local->newloc);
+ &local->newloc, 0, xdata);
goto out;
}
- local->cur_offset = local->fop_offset;
+ local->cur_offset = 0;
STACK_WIND (frame, trash_truncate_readv_cbk,
FIRST_CHILD (this), FIRST_CHILD (this)->fops->readv,
- local->fd, (size_t)GF_BLOCK_READV_SIZE, local->cur_offset, 0);
+ local->fd, (size_t)GF_BLOCK_READV_SIZE, local->cur_offset,
+ 0, xdata);
out:
return 0;
}
-
+/**
+ * Creates new file descriptor for read and write operations,
+ * if the path is present in trash directory
+ */
int32_t
trash_truncate_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, fd_t *fd,
inode_t *inode, struct iatt *buf,
- struct iatt *preparent, struct iatt *postparent)
+ struct iatt *preparent, struct iatt *postparent,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *dir_name = NULL;
- char *tmp_path = NULL;
- int32_t flags = 0;
- loc_t tmp_loc = {0,};
+ trash_local_t *local = NULL;
+ char *tmp_str = NULL;
+ char *dir_name = NULL;
+ char *tmp_path = NULL;
+ int32_t flags = 0;
+ loc_t tmp_loc = {0,};
+ char *tmp_stat = NULL;
+ char real_path[PATH_MAX] = {0,};
+ trash_private_t *priv = NULL;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
+
+ /* Checks whether path is present in trash directory or not */
if ((op_ret == -1) && (op_errno == ENOENT)) {
- //Creating the directory structure here.
+ /* Creating the directory structure here. */
tmp_str = gf_strdup (local->newpath);
if (!tmp_str) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
}
dir_name = dirname (tmp_str);
tmp_path = gf_strdup (dir_name);
if (!tmp_path) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
}
- tmp_loc.path = tmp_path;
-
- /* TODO: create the directory with proper permissions */
+ loc_copy (&tmp_loc, &local->newloc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
+ }
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
+ /* create the directory with proper permissions */
STACK_WIND_COOKIE (frame, trash_truncate_mkdir_cbk,
tmp_path, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->mkdir,
- &tmp_loc, 0755, NULL);
- GF_FREE (tmp_str);
+ &tmp_loc, get_permission(real_path),
+ 0022, xdata);
+ loc_wipe (&tmp_loc);
goto out;
}
if (op_ret == -1) {
- //Let truncate work, but previous copy is not preserved.
- //Deleting the newly created copy.
+ /* Let truncate work, but previous copy is not preserved.
+ * Deleting the newly created copy.
+ */
gf_log (this->name, GF_LOG_DEBUG,
"creation of new file in trash-dir failed, "
"when truncate was called: %s", strerror (op_errno));
@@ -798,47 +1245,66 @@ trash_truncate_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
STACK_WIND (frame, trash_common_unwind_buf_cbk,
FIRST_CHILD(this),
FIRST_CHILD(this)->fops->truncate, &local->loc,
- local->fop_offset);
+ local->fop_offset, xdata);
goto out;
}
flags = O_RDONLY;
+ /* fd which represents source file for reading and writing from it */
+
local->fd = fd_create (local->loc.inode, frame->root->pid);
STACK_WIND (frame, trash_truncate_open_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->open, &local->loc, flags,
local->fd, 0);
out:
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ if (tmp_path)
+ GF_FREE (tmp_path);
+
return 0;
}
+/**
+ * If the path is not present in the trash directory,it will recursively call
+ * this call-back and one by one directories will be created from the
+ * beginning
+ */
int32_t
trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, inode_t *inode,
struct iatt *stbuf, struct iatt *preparent,
- struct iatt *postparent)
+ struct iatt *postparent, dict_t *xdata)
{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *tmp_path = NULL;
- char *tmp_dirname = NULL;
- char *dir_name = NULL;
- int32_t count = 0;
- int32_t flags = 0;
- int32_t loop_count = 0;
- int i = 0;
- loc_t tmp_loc = {0,};
+ trash_local_t *local = NULL;
+ trash_private_t *priv = NULL;
+ char *tmp_str = NULL;
+ char *tmp_path = NULL;
+ char *tmp_dirname = NULL;
+ char *dir_name = NULL;
+ char *tmp_stat = NULL;
+ char real_path[PATH_MAX] = {0,};
+ size_t count = 0;
+ int32_t flags = 0;
+ int32_t loop_count = 0;
+ int i = 0;
+ loc_t tmp_loc = {0,};
+ int ret = 0;
- local = frame->local;
- if (!local)
- goto out;
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
loop_count = local->loop_count;
tmp_str = gf_strdup (local->newpath);
if (!tmp_str) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
goto out;
}
@@ -853,16 +1319,39 @@ trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
break;
tmp_dirname = strchr (tmp_str + count + 1, '/');
}
- tmp_path = memdup (local->newpath, count);
+ tmp_path = gf_memdup (local->newpath, count + 1);
if (!tmp_path) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
}
- tmp_loc.path = tmp_path;
- STACK_WIND_COOKIE (frame, trash_truncate_mkdir_cbk,
- tmp_path, this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
+ tmp_path[count] = '\0';
+ loc_copy (&tmp_loc, &local->newloc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /* Stores the the name of directory to be created */
+ tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1);
+ if (!tmp_loc.name) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
+ STACK_WIND_COOKIE (frame, trash_truncate_mkdir_cbk,
+ tmp_path, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir,
+ &tmp_loc, get_permission(real_path),
+ 0022, xdata);
+ loc_wipe (&tmp_loc);
goto out;
}
@@ -870,14 +1359,16 @@ trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
dir_name = dirname (tmp_str);
if (strcmp ((char*)cookie, dir_name) == 0) {
flags = O_CREAT|O_EXCL|O_WRONLY;
- ia_prot_t prot = {0, };
-
- //Call create again once directory structure is created.
+ strcpy (real_path, priv->brick_path);
+ strcat (real_path, local->origpath);
+ /* Call create again once directory structure
+ is created. */
STACK_WIND (frame, trash_truncate_create_cbk,
- FIRST_CHILD(this), FIRST_CHILD(this)->fops->create,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->create,
&local->newloc, flags,
- st_mode_from_ia (prot, local->loc.inode->ia_type),
- local->newfd, NULL);
+ get_permission (real_path),
+ 0022, local->newfd, xdata);
goto out;
}
}
@@ -893,82 +1384,147 @@ trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
count = tmp_dirname - tmp_str;
if (count == 0)
count = 1;
-
i++;
if ((i > loop_count) || (count > PATH_MAX))
break;
tmp_dirname = strchr (tmp_str + count + 1, '/');
}
- tmp_path = memdup (local->newpath, count);
+ tmp_path = gf_memdup (local->newpath, count + 1);
if (!tmp_path) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
}
- tmp_loc.path = tmp_path;
+ tmp_path[count] = '\0';
+
+ loc_copy (&tmp_loc, &local->newloc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /* Stores the the name of directory to be created */
+ tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1);
+ if (!tmp_loc.name) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
+ }
+
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
STACK_WIND_COOKIE (frame, trash_truncate_mkdir_cbk, tmp_path,
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir, &tmp_loc,
+ get_permission(real_path),
+ 0022, xdata);
out:
- GF_FREE (cookie); /* strdup (dir_name) was sent here :) */
- GF_FREE (tmp_str);
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ if (tmp_path)
+ GF_FREE (tmp_path);
- return 0;
+ return ret;
}
int32_t
trash_truncate_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, struct iatt *buf)
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ dict_t *xdata)
{
- trash_private_t *priv = NULL;
- trash_local_t *local = NULL;
- char timestr[64] = {0,};
- char loc_newname[PATH_MAX] = {0,};
- int32_t flags = 0;
+ trash_private_t *priv = NULL;
+ trash_local_t *local = NULL;
+ char loc_newname[PATH_MAX] = {0,};
+ int32_t flags = 0;
+ dentry_t *dir_entry = NULL;
+ inode_table_t *table = NULL;
+ int ret = 0;
priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
+
+ table = local->loc.inode->table;
+
+ pthread_mutex_lock (&table->lock);
+ {
+ dir_entry = __dentry_search_arbit (local->loc.inode);
+ }
+ pthread_mutex_unlock (&table->lock);
if (op_ret == -1) {
gf_log (this->name, GF_LOG_DEBUG,
"fstat on the file failed: %s",
strerror (op_errno));
- TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, buf, NULL);
- return 0;
+ TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, buf,
+ NULL, xdata);
+ goto out;
}
-
- if ((buf->ia_size == 0) || (buf->ia_size > priv->max_trash_file_size)) {
- // If the file is too big, just unlink it.
- if (buf->ia_size > priv->max_trash_file_size)
- gf_log (this->name, GF_LOG_DEBUG, "%s: file too big, "
+ /* If the file is too big, just unlink it. */
+ if (buf->ia_size > (priv->max_trash_file_size)) {
+ gf_log (this->name, GF_LOG_DEBUG, "%s: file too big, "
"not moving to trash", local->loc.path);
STACK_WIND (frame, trash_common_unwind_buf_cbk,
- this->children->xlator,
- this->children->xlator->fops->truncate,
- &local->loc, local->fop_offset);
- return 0;
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->truncate,
+ &local->loc, local->fop_offset, xdata);
+ goto out;
}
- strcpy (local->newpath, priv->trash_dir);
+ /* Retrives the name of file from path */
+ local->loc.name = gf_strdup (strrchr (local->loc.path, '/'));
+ if (!local->loc.name) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
+ }
+
+ /* Stores new path for source file */
+ copy_trash_path (priv->newtrash_dir, (frame->root->pid < 0),
+ local->newpath);
strcat (local->newpath, local->loc.path);
- {
- gf_time_fmt (timestr, sizeof timestr, time (NULL),
- gf_timefmt_F_HMS);
- strcat (local->newpath, timestr);
- }
- strcpy (loc_newname,local->loc.name);
- strcat (loc_newname,timestr);
+ /* append timestamp to file name so that we can avoid
+ name collisions inside trash */
+ append_time_stamp (local->newpath);
+ strcpy (loc_newname, local->loc.name);
+ append_time_stamp (loc_newname);
+ /* local->newloc represents old file(file inside trash),
+ where as local->loc represents truncated file. We need
+ to create new inode and fd for new file*/
local->newloc.name = gf_strdup (loc_newname);
+ if (!local->newloc.name) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
local->newloc.path = gf_strdup (local->newpath);
+ if (!local->newloc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
local->newloc.inode = inode_new (local->loc.inode->table);
local->newfd = fd_create (local->newloc.inode, frame->root->pid);
+ /* Creating vaild parent and pargfids for both files */
+
+ local->loc.parent = inode_ref (dir_entry->parent);
+ uuid_copy (local->loc.pargfid, dir_entry->parent->gfid);
+
+ local->newloc.parent = inode_ref (dir_entry->parent);
+ uuid_copy (local->newloc.pargfid, dir_entry->parent->gfid);
+
flags = O_CREAT|O_EXCL|O_WRONLY;
STACK_WIND (frame, trash_truncate_create_cbk,
@@ -976,45 +1532,73 @@ trash_truncate_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
FIRST_CHILD(this)->fops->create,
&local->newloc, flags,
st_mode_from_ia (buf->ia_prot, local->loc.inode->ia_type),
- local->newfd, NULL);
+ 0022, local->newfd, xdata);
- return 0;
+out:
+ return ret;
}
+/**
+ * Truncate can be explicitly called or implicitly by some other applications
+ * like text editors etc..
+ */
int32_t
trash_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc,
- off_t offset)
+ off_t offset, dict_t *xdata)
{
- trash_elim_pattern_t *trav = NULL;
- trash_private_t *priv = NULL;
- trash_local_t *local = NULL;
- int32_t match = 0;
+ trash_private_t *priv = NULL;
+ trash_local_t *local = NULL;
+ int32_t match = 0;
+ char *pathbuf = NULL;
+ int ret = 0;
priv = this->private;
- if (priv->eliminate) {
- trav = priv->eliminate;
- while (trav) {
- if (fnmatch(trav->pattern, loc->name, 0) == 0) {
- match++;
- break;
- }
- trav = trav->next;
- }
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+ /* If trash is not active or not enabled through cli, then
+ * we bypass and wind back
+ */
+ if (!priv->state) {
+ STACK_WIND (frame, trash_common_unwind_buf_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->truncate, loc,
+ offset, xdata);
+ goto out;
+ }
+
+ /* The files removed by gluster operations such as self-heal,
+ should moved to trash directory, but files by client should
+ not moved */
+ if ((frame->root->pid < 0) && !priv->internal) {
+ STACK_WIND (frame, trash_common_unwind_buf_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->truncate, loc,
+ offset, xdata);
+ goto out;
}
+ /* This will be more accurate */
+ inode_path(loc->inode, NULL, &pathbuf);
- if ((strncmp (loc->path, priv->trash_dir,
- strlen (priv->trash_dir)) == 0) || (offset) || (match)) {
+ /* Checks whether file is in trash directory or eliminate path.
+ * In all such cases it does not move to trash directory,
+ * truncate will be performed
+ */
+ match = check_whether_eliminate_path (priv->eliminate, pathbuf);
+
+ if ((strncmp (pathbuf, priv->newtrash_dir,
+ strlen (priv->newtrash_dir)) == 0) || (match)) {
if (match) {
gf_log (this->name, GF_LOG_DEBUG,
"%s: file not moved to trash as per option "
- "'eliminate'", loc->path);
+ "'eliminate path'", loc->path);
}
- // Trying to truncate from the trash can dir,
- // do the actual truncate without moving to trash-dir.
+ /* Trying to truncate from the trash-dir. So do the
+ * actual truncate without moving to trash-dir.
+ */
STACK_WIND (frame, trash_common_unwind_buf_cbk,
FIRST_CHILD(this),
- FIRST_CHILD(this)->fops->truncate, loc, offset);
+ FIRST_CHILD(this)->fops->truncate, loc, offset,
+ xdata);
goto out;
}
@@ -1023,60 +1607,66 @@ trash_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc,
local = mem_get0 (this->local_pool);
if (!local) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
- TRASH_STACK_UNWIND (truncate, frame, -1, ENOMEM, NULL, NULL);
- return 0;
+ TRASH_STACK_UNWIND (truncate, frame, -1, ENOMEM, NULL, NULL,
+ xdata);
+ ret = ENOMEM;
+ goto out;
}
loc_copy (&local->loc, loc);
-
+ local->loc.path = pathbuf;
local->fop_offset = offset;
frame->local = local;
STACK_WIND (frame, trash_truncate_stat_cbk,
- this->children->xlator,
- this->children->xlator->fops->stat, loc);
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->stat, loc,
+ xdata);
out:
- return 0;
+ return ret;
}
int32_t
trash_ftruncate_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
- struct iatt *preparent, struct iatt *postparent)
+ struct iatt *preparent, struct iatt *postparent,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
+ trash_local_t *local = NULL;
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if (op_ret == -1) {
gf_log (this->name, GF_LOG_DEBUG,
"%s: failed to unlink new file: %s",
local->newloc.path, strerror(op_errno));
-
}
STACK_WIND (frame, trash_common_unwind_buf_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->ftruncate,
- local->fd, local->fop_offset);
-
+ local->fd, local->fop_offset, xdata);
+out:
return 0;
}
int32_t
trash_ftruncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
- struct iatt *prebuf, struct iatt *postbuf)
+ struct iatt *prebuf, struct iatt *postbuf,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
+ trash_local_t *local = NULL;
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if (op_ret == -1) {
STACK_WIND (frame, trash_ftruncate_unlink_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink,
- &local->newloc);
+ &local->newloc, 0, xdata);
return 0;
}
@@ -1085,14 +1675,14 @@ trash_ftruncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
STACK_WIND (frame, trash_ftruncate_readv_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->readv,
local->fd, (size_t)GF_BLOCK_READV_SIZE,
- local->cur_offset, 0);
+ local->cur_offset, 0, xdata);
return 0;
}
STACK_WIND (frame, trash_common_unwind_buf_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->ftruncate, local->fd,
- local->fop_offset);
-
+ local->fop_offset, xdata);
+out:
return 0;
}
@@ -1101,24 +1691,28 @@ int32_t
trash_ftruncate_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
struct iovec *vector, int32_t count,
- struct iatt *stbuf, struct iobref *iobuf)
+ struct iatt *stbuf, struct iobref *iobuf,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
+ trash_local_t *local = NULL;
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
+
local->fsize = stbuf->ia_size;
if (op_ret == -1) {
STACK_WIND (frame, trash_ftruncate_unlink_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink,
- &local->newloc);
+ &local->newloc, 0, xdata);
return 0;
}
STACK_WIND (frame, trash_ftruncate_writev_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->writev,
- local->newfd, vector, count, local->cur_offset, 0, NULL);
-
+ local->newfd, vector, count, local->cur_offset, 0,
+ NULL, xdata);
+out:
return 0;
}
@@ -1127,49 +1721,77 @@ int32_t
trash_ftruncate_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, fd_t *fd,
inode_t *inode, struct iatt *buf,
- struct iatt *preparent, struct iatt *postparent)
+ struct iatt *preparent, struct iatt *postparent,
+ dict_t *xdata)
{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *dir_name = NULL;
- char *tmp_path = NULL;
- loc_t tmp_loc = {0,};
+ trash_local_t *local = NULL;
+ char *tmp_str = NULL;
+ char *dir_name = NULL;
+ char *tmp_path = NULL;
+ loc_t tmp_loc = {0,};
+ char *pathbuf = NULL;
+ char *tmp_stat = NULL;
+ char real_path[PATH_MAX] = {0,};
+ trash_private_t *priv = NULL;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
+
+ /* This will be more accurate */
+ inode_path (fd->inode, NULL, &pathbuf);
if ((op_ret == -1) && (op_errno == ENOENT)) {
tmp_str = gf_strdup (local->newpath);
if (!tmp_str) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
}
dir_name = dirname (tmp_str);
tmp_path = gf_strdup (dir_name);
if (!tmp_path) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
}
- tmp_loc.path = tmp_path;
-
- /* TODO: create the directory with proper permissions */
+ loc_copy (&tmp_loc, &local->newloc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
+ }
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
+ /* create the directory with proper permissions */
STACK_WIND_COOKIE (frame, trash_truncate_mkdir_cbk,
tmp_path, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->mkdir,
- &tmp_loc, 0755, NULL);
- GF_FREE (tmp_str);
- return 0;
+ &tmp_loc, get_permission(real_path),
+ 0022, xdata);
+ loc_wipe (&tmp_loc);
+ goto out;
}
if (op_ret == -1) {
STACK_WIND (frame, trash_common_unwind_buf_cbk,
FIRST_CHILD(this),
FIRST_CHILD(this)->fops->ftruncate,
- local->fd, local->fop_offset);
- return 0;
+ local->fd, local->fop_offset, xdata);
+ goto out;
}
STACK_WIND (frame, trash_ftruncate_readv_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->readv, local->fd,
- (size_t)GF_BLOCK_READV_SIZE, local->cur_offset, 0);
+ (size_t)GF_BLOCK_READV_SIZE, local->cur_offset, 0, xdata);
+out:
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ if (tmp_path)
+ GF_FREE (tmp_path);
return 0;
}
@@ -1179,28 +1801,35 @@ int32_t
trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, inode_t *inode,
struct iatt *stbuf, struct iatt *preparent,
- struct iatt *postparent)
+ struct iatt *postparent, dict_t *xdata)
{
- trash_local_t *local = NULL;
- char *tmp_str = NULL;
- char *tmp_path = NULL;
- char *tmp_dirname = NULL;
- char *dir_name = NULL;
- int32_t count = 0;
- int32_t flags = 0;
- int32_t loop_count = 0;
- int i = 0;
- loc_t tmp_loc = {0,};
+ trash_local_t *local = NULL;
+ trash_private_t *priv = NULL;
+ char *tmp_str = NULL;
+ char *tmp_path = NULL;
+ char *tmp_dirname = NULL;
+ char *dir_name = NULL;
+ char *tmp_stat = NULL;
+ char real_path[PATH_MAX] = {0,};
+ size_t count = 0;
+ int32_t flags = 0;
+ int32_t loop_count = 0;
+ int i = 0;
+ loc_t tmp_loc = {0,};
+ int ret = 0;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
local = frame->local;
- if (!local)
- goto out;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
loop_count = local->loop_count;
tmp_str = gf_strdup (local->newpath);
if (!tmp_str) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
goto out;
}
@@ -1215,32 +1844,48 @@ trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
break;
tmp_dirname = strchr (tmp_str + count + 1, '/');
}
- tmp_path = memdup (local->newpath, count);
+ tmp_path = gf_memdup (local->newpath, count + 1);
if (!tmp_path) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ tmp_path[count] = '\0';
+
+ loc_copy (&tmp_loc, &local->newloc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
}
- tmp_loc.path = tmp_path;
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
STACK_WIND_COOKIE (frame, trash_ftruncate_mkdir_cbk,
- tmp_path, this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
-
+ tmp_path, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir,
+ &tmp_loc, get_permission(real_path),
+ 0022, xdata);
+ loc_wipe (&tmp_loc);
goto out;
}
if (op_ret == 0) {
dir_name = dirname (tmp_str);
- if (strcmp ((char*)cookie, dir_name) == 0) {
- ia_prot_t prot = {0, };
+ if (strcmp ((char *)cookie, dir_name) == 0) {
flags = O_CREAT|O_EXCL|O_WRONLY;
-
- //Call create again once directory structure is created.
+ strcpy (real_path, priv->brick_path);
+ strcat (real_path, local->origpath);
+ /* Call create again once directory structure
+ is created. */
STACK_WIND (frame, trash_ftruncate_create_cbk,
FIRST_CHILD(this),
FIRST_CHILD(this)->fops->create,
&local->newloc, flags,
- st_mode_from_ia (prot, local->loc.inode->ia_type),
- local->newfd, NULL);
+ get_permission (real_path),
+ 0022, local->newfd, xdata);
goto out;
}
}
@@ -1250,288 +1895,864 @@ trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
loop_count = ++local->loop_count;
}
UNLOCK (&frame->lock);
+
tmp_dirname = strchr (tmp_str, '/');
while (tmp_dirname) {
count = tmp_dirname - tmp_str;
if (count == 0)
count = 1;
-
i++;
if ((i > loop_count) || (count > PATH_MAX))
break;
tmp_dirname = strchr (tmp_str + count + 1, '/');
}
- tmp_path = memdup (local->newpath, count);
+ tmp_path = gf_memdup (local->newpath, count + 1);
if (!tmp_path) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
}
- tmp_loc.path = tmp_path;
+ tmp_path[count] = '\0';
- STACK_WIND_COOKIE (frame, trash_ftruncate_mkdir_cbk, tmp_path,
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc, 0755, NULL);
+ loc_copy (&tmp_loc, &local->newloc);
+ tmp_loc.path = gf_strdup (tmp_path);
+ if (!tmp_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /* Stores the the name of directory to be created */
+ tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1);
+ if (!tmp_loc.name) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ strcpy (real_path, priv->brick_path);
+ remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat);
+ if (tmp_stat)
+ strcat (real_path, tmp_stat);
+ STACK_WIND_COOKIE (frame, trash_ftruncate_mkdir_cbk, tmp_path,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir, &tmp_loc,
+ get_permission(real_path),
+ 0022, xdata);
out:
- GF_FREE (cookie); /* strdup (dir_name) was sent here :) */
- GF_FREE (tmp_str);
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ if (tmp_path)
+ GF_FREE (tmp_path);
- return 0;
+ return ret;
}
int32_t
trash_ftruncate_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno, struct iatt *buf)
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ dict_t *xdata)
{
trash_private_t *priv = NULL;
trash_local_t *local = NULL;
priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
local = frame->local;
+ GF_VALIDATE_OR_GOTO ("trash", local, out);
if (op_ret == -1) {
gf_log (this->name, GF_LOG_DEBUG,
"%s: %s",local->newloc.path, strerror(op_errno));
- TRASH_STACK_UNWIND (ftruncate, frame, -1, op_errno, buf, NULL);
- return 0;
+ TRASH_STACK_UNWIND (ftruncate, frame, -1, op_errno, buf,
+ NULL, xdata);
+ goto out;
}
- if ((buf->ia_size == 0) || (buf->ia_size > priv->max_trash_file_size))
+ if ((buf->ia_size > (priv->max_trash_file_size)))
{
STACK_WIND (frame, trash_common_unwind_buf_cbk,
- this->children->xlator,
- this->children->xlator->fops->ftruncate,
- local->fd, local->fop_offset);
- return 0;
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->ftruncate,
+ local->fd, local->fop_offset, xdata);
+ goto out;
}
- STACK_WIND (frame, trash_ftruncate_create_cbk, FIRST_CHILD(this),
+ STACK_WIND (frame, trash_truncate_create_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->create, &local->newloc,
( O_CREAT | O_EXCL | O_WRONLY ),
st_mode_from_ia (buf->ia_prot, local->loc.inode->ia_type),
- local->newfd, NULL);
+ 0022, local->newfd, xdata);
+out:
return 0;
}
+/**
+ * When we call truncate from terminal it comes to ftruncate of trash-xlator.
+ * Since truncate internally calls ftruncate and we receive fd of the file,
+ * other than that it also called by Rebalance operation
+ */
int32_t
-trash_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset)
+trash_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
+ dict_t *xdata)
{
- trash_elim_pattern_t *trav = NULL;
- trash_private_t *priv = NULL;
- trash_local_t *local = NULL;
- dentry_t *dir_entry = NULL;
- char *pathbuf = NULL;
- inode_t *newinode = NULL;
- char timestr[64];
- int32_t retval = 0;
- int32_t match = 0;
+ trash_private_t *priv = NULL;
+ trash_local_t *local = NULL;/* file inside trash */
+ char *pathbuf = NULL;/* path of file from fd */
+ int32_t retval = 0;
+ int32_t match = 0;
+ int ret = 0;
priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+ /* If trash is not active or not enabled through cli, then
+ * we bypass and wind back
+ */
+ if (!priv->state) {
+ STACK_WIND (frame, trash_common_unwind_buf_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->ftruncate, fd,
+ offset, xdata);
+ goto out;
+ }
- dir_entry = __dentry_search_arbit (fd->inode);
+ /* The files removed by gluster operations such as self-heal,
+ * should moved to trash directory, but files by client
+ * should not moved
+ */
+ if ((frame->root->pid < 0) && !priv->internal) {
+ STACK_WIND (frame, trash_common_unwind_buf_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->ftruncate, fd,
+ offset, xdata);
+ goto out;
+ }
+ /* This will be more accurate */
retval = inode_path (fd->inode, NULL, &pathbuf);
- if (priv->eliminate) {
- trav = priv->eliminate;
- while (trav) {
- if (fnmatch(trav->pattern, dir_entry->name, 0) == 0) {
- match++;
- break;
- }
- trav = trav->next;
+ /* Checking the eliminate path */
+
+ /* Checks whether file is trash directory or eliminate path or
+ * invalid fd. In all such cases it does not move to trash directory,
+ * ftruncate will be performed
+ */
+ match = check_whether_eliminate_path (priv->eliminate, pathbuf);
+ if ((strncmp (pathbuf, priv->newtrash_dir,
+ strlen (priv->newtrash_dir)) == 0) || match ||
+ !retval) {
+
+ if (match) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "%s: file matches eliminate path, "
+ "not moved to trash", pathbuf);
}
- }
- if ((strncmp (pathbuf, priv->trash_dir,
- strlen (priv->trash_dir)) == 0) ||
- (offset >= priv->max_trash_file_size) ||
- (!retval) ||
- match) {
+ /* Trying to ftruncate from the trash-dir. So do the
+ * actual ftruncate without moving to trash-dir
+ */
STACK_WIND (frame, trash_common_unwind_buf_cbk,
FIRST_CHILD(this),
FIRST_CHILD(this)->fops->ftruncate,
- fd, offset);
- return 0;
+ fd, offset, xdata);
+ goto out;
}
local = mem_get0 (this->local_pool);
if (!local) {
gf_log (this->name, GF_LOG_DEBUG, "out of memory");
- TRASH_STACK_UNWIND (ftruncate, frame, -1, ENOMEM, NULL, NULL);
- return 0;
+ TRASH_STACK_UNWIND (ftruncate, frame, -1, ENOMEM, NULL,
+ NULL, xdata);
+ ret = -1;
+ goto out;
}
- gf_time_fmt (timestr, sizeof timestr, time (NULL), gf_timefmt_F_HMS);
- strcpy (local->newpath, priv->trash_dir);
- strcat (local->newpath, pathbuf);
- strcat (local->newpath, timestr);
-
- local->fd = fd_ref (fd);
- newinode = inode_new (fd->inode->table);
- local->newfd = fd_create (newinode, frame->root->pid);
+ /* To convert fd to location */
frame->local=local;
- local->newloc.inode = newinode;
- local->newloc.path = local->newpath;
-
- local->loc.inode = inode_ref (fd->inode);
local->loc.path = pathbuf;
+ local->loc.inode = inode_ref (fd->inode);
+ uuid_copy (local->loc.gfid, local->loc.inode->gfid);
local->fop_offset = offset;
- local->cur_offset = offset;
- STACK_WIND (frame, trash_ftruncate_fstat_cbk, this->children->xlator,
- this->children->xlator->fops->fstat, fd);
+ /* Else remains same to truncate code, so from here flow goes
+ * to truncate_stat
+ */
+ STACK_WIND (frame, trash_truncate_stat_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fstat, fd, xdata);
+out:
+ return ret;
+}
+
+/**
+ * The mkdir call is intercepted to avoid creation of
+ * trash directory in the mount by the user
+ */
+int32_t
+trash_mkdir (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, mode_t mode, mode_t umask, dict_t *xdata)
+{
+ int32_t op_ret = 0;
+ int32_t op_errno = 0;
+ trash_private_t *priv = NULL;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ if (!check_whether_trash_directory (loc->path, priv->newtrash_dir)) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "mkdir issued on %s, which is not permitted",
+ priv->newtrash_dir);
+ op_errno = EPERM;
+ op_ret = -1;
+ STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno,
+ NULL, NULL, NULL, NULL, xdata);
+ } else {
+ STACK_WIND (frame, trash_common_mkdir_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir, loc, mode, umask, xdata);
+ }
+out:
return 0;
}
/**
- * trash_init -
+ * The rename call is intercepted to avoid renaming
+ * of trash directory in the mount by the user
+ */
+int
+trash_rename (call_frame_t *frame, xlator_t *this,
+ loc_t *oldloc, loc_t *newloc, dict_t *xdata)
+{
+ int32_t op_ret = 0;
+ int32_t op_errno = 0;
+ trash_private_t *priv = NULL;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ if (!check_whether_trash_directory (oldloc->path, priv->newtrash_dir)) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "rename issued on %s, which is not permitted",
+ priv->newtrash_dir);
+ op_errno = EPERM;
+ op_ret = -1;
+
+ STACK_UNWIND_STRICT (rename, frame, op_ret, op_errno, NULL,
+ NULL, NULL, NULL, NULL, xdata);
+ } else {
+ STACK_WIND (frame, trash_common_rename_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rename, oldloc, newloc, xdata);
+ }
+out:
+ return 0;
+}
+
+/**
+ * The rmdir call is intercepted to avoid deletion of
+ * trash directory in the mount by the user
+ */
+int32_t
+trash_rmdir (call_frame_t *frame, xlator_t *this,
+ loc_t *loc, int flags, dict_t *xdata)
+{
+ int32_t op_ret = 0;
+ int32_t op_errno = 0;
+ trash_private_t *priv = NULL;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ if (!check_whether_trash_directory (loc->path, priv->newtrash_dir)) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "rmdir issued on %s, which is not permitted",
+ priv->newtrash_dir);
+ op_errno = EPERM;
+ op_ret = -1;
+
+ STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno,
+ NULL, NULL, xdata);
+ } else {
+ STACK_WIND (frame, trash_common_rmdir_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rmdir, loc, flags, xdata);
+ }
+out:
+ return 0;
+}
+
+/**
+ * Volume set option is handled by the reconfigure funtion.
+ * Here we checks whether each option is set or not ,if it
+ * sets then corresponding modifciations will be made
+ */
+int
+reconfigure (xlator_t *this, dict_t *options)
+{
+ uint64_t max_fsize = 0;
+ int ret = 0;
+ char *tmp = NULL;
+ char *tmp_str = NULL;
+ trash_private_t *priv = NULL;
+ loc_t old_loc = {0, };
+ loc_t new_loc = {0, };
+ call_frame_t *frame = NULL;
+ char trash_dir[PATH_MAX] = {0,};
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ GF_OPTION_RECONF ("trash", priv->state, options, bool, out);
+
+ GF_OPTION_RECONF ("trash-dir", tmp, options, str, out);
+ if (tmp) {
+ sprintf(trash_dir, "/%s/", tmp);
+ if (strcmp(priv->newtrash_dir, trash_dir) != 0) {
+
+ /* When user set a new name for trash directory, trash
+ * xlator will perform a rename operation on old trash
+ * directory to the new one using a STACK_WIND from here.
+ * This option can be configured only when volume is in
+ * started state
+ */
+
+ GF_FREE (priv->newtrash_dir);
+
+ priv->newtrash_dir = gf_strdup (trash_dir);
+ if (!priv->newtrash_dir) {
+ ret = ENOMEM;
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+ gf_log (this->name, GF_LOG_DEBUG,
+ "Renaming %s -> %s from reconfigure",
+ priv->oldtrash_dir, priv->newtrash_dir);
+
+ if (!priv->newtrash_dir) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ frame = create_frame (this, this->ctx->pool);
+
+ /* assign new location values to new_loc members */
+ uuid_copy (new_loc.gfid, trash_gfid);
+ uuid_copy (new_loc.pargfid, root_gfid);
+ ret = extract_trash_directory (priv->newtrash_dir,
+ &new_loc.name);
+ if (ret) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+ new_loc.path = gf_strdup (priv->newtrash_dir);
+ if (!new_loc.path) {
+ ret = ENOMEM;
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+
+ /* assign old location values to old_loc members */
+ uuid_copy (old_loc.gfid, trash_gfid);
+ uuid_copy (old_loc.pargfid, root_gfid);
+ ret = extract_trash_directory (priv->oldtrash_dir,
+ &old_loc.name);
+ if (ret) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+ old_loc.path = gf_strdup (priv->oldtrash_dir);
+ if (!old_loc.path) {
+ ret = ENOMEM;
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+
+ old_loc.inode = inode_ref (priv->trash_inode);
+ uuid_copy(old_loc.inode->gfid, old_loc.gfid);
+
+ STACK_WIND (frame, trash_reconf_rename_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rename,
+ &old_loc, &new_loc, options);
+ if (priv->oldtrash_dir)
+ GF_FREE (priv->oldtrash_dir);
+
+ priv->oldtrash_dir = gf_strdup(priv->newtrash_dir);
+ if (!priv->oldtrash_dir) {
+ ret = ENOMEM;
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+ }
+ }
+ tmp = NULL;
+
+ GF_OPTION_RECONF ("trash-internal-op", priv->internal, options,
+ bool, out);
+
+ GF_OPTION_RECONF ("trash-max-filesize", max_fsize, options,
+ size_uint64, out);
+ if (max_fsize) {
+ if (max_fsize > GF_ALLOWED_MAX_FILE_SIZE) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "Size specified for max-size(in MB) is too "
+ "large so using 1GB as max-size (NOT IDEAL)");
+ priv->max_trash_file_size = GF_ALLOWED_MAX_FILE_SIZE;
+ } else
+ priv->max_trash_file_size = max_fsize;
+ gf_log (this->name, GF_LOG_DEBUG, "%"GF_PRI_SIZET" max-size",
+ priv->max_trash_file_size);
+ }
+ GF_OPTION_RECONF ("trash-eliminate-path", tmp, options, str, out);
+ if (!tmp) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "no option specified for 'eliminate', using NULL");
+ } else {
+ if (priv->eliminate)
+ wipe_eliminate_path (priv->eliminate);
+
+ tmp_str = gf_strdup (tmp);
+ if (!tmp_str) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = store_eliminate_path (tmp_str, priv->eliminate);
+
+ }
+
+out:
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ loc_wipe (&new_loc);
+ loc_wipe (&old_loc);
+
+ return ret;
+}
+
+/**
+ * Notify is used to create the trash directory with fixed gfid
+ * using STACK_WIND only when posix xlator is up
+ */
+int
+notify (xlator_t *this, int event, void *data, ...)
+{
+ trash_private_t *priv = NULL;
+ dict_t *dict = NULL;
+ int ret = 0;
+ uuid_t *tgfid_ptr = NULL;
+ loc_t loc = {0, };
+ loc_t old_loc = {0, };
+ call_frame_t *frame = NULL;
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO ("trash", priv, out);
+
+ /* Check whether posix is up not */
+ if (event == GF_EVENT_CHILD_UP) {
+ frame = create_frame(this, this->ctx->pool);
+ dict = dict_new ();
+ if (!dict) {
+ ret = ENOMEM;
+ goto out;
+ }
+ priv->trash_itable = inode_table_new (0, this);
+
+ /* Here there is two possiblities ,if trash directory already
+ * exist ,then we need to perform a rename operation on the
+ * old one. Otherwise, we need to create the trash directory
+ * For both, we need to pass location variable, gfid of parent
+ * and a frame for calling STACK_WIND.The location variable
+ * requires name,path,gfid and inode
+ */
+ if (!priv->oldtrash_dir) {
+ loc.inode = inode_new (priv->trash_itable);
+ uuid_copy (loc.gfid, trash_gfid);
+
+ gf_log (this->name, GF_LOG_DEBUG, "nameless lookup for"
+ "old trash directory");
+ STACK_WIND (frame, trash_notify_lookup_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->lookup,
+ &loc, dict);
+ gf_log (this->name, GF_LOG_DEBUG, "old_trash_dir %s",
+ priv->oldtrash_dir);
+ loc_wipe (&loc);
+ }
+
+ if (strcmp (priv->oldtrash_dir, priv->newtrash_dir) == 0) {
+ gf_log (this->name, GF_LOG_DEBUG, "Creating trash "
+ "directory %s from notify",
+ priv->newtrash_dir);
+
+ tgfid_ptr = GF_CALLOC (1, sizeof(uuid_t),
+ gf_common_mt_uuid_t);
+ if (!tgfid_ptr) {
+ ret = ENOMEM;
+ goto out;
+ }
+ uuid_copy (*tgfid_ptr, trash_gfid);
+
+ uuid_copy (loc.gfid, trash_gfid);
+ uuid_copy (loc.pargfid, root_gfid);
+ ret = extract_trash_directory (priv->newtrash_dir,
+ &loc.name);
+ if (ret) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+ loc.path = gf_strdup (priv->newtrash_dir);
+ if (!loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ priv->trash_inode = inode_new (priv->trash_itable);
+ priv->trash_inode->ia_type = IA_IFDIR;
+ loc.inode = inode_ref (priv->trash_inode);
+
+ /* Fixed gfid is set for trash directory with
+ * this function
+ */
+ ret = dict_set_dynptr (dict, "gfid-req", tgfid_ptr,
+ sizeof (uuid_t));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "setting key gfid-req failed");
+ goto out;
+ }
+
+ /* The mkdir call for creating trash directory */
+ STACK_WIND (frame, trash_notify_mkdir_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir, &loc, 0755,
+ 0022, dict);
+ } else {
+ /* assign new location values to new_loc members */
+ gf_log (this->name, GF_LOG_DEBUG, "Renaming %s -> %s"
+ " from notify", priv->oldtrash_dir,
+ priv->newtrash_dir);
+ uuid_copy (loc.gfid, trash_gfid);
+ uuid_copy (loc.pargfid, root_gfid);
+ ret = extract_trash_directory (priv->newtrash_dir,
+ &loc.name);
+ if (ret) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+ loc.path = gf_strdup (priv->newtrash_dir);
+ if (!loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ /* assign old location values to old_loc members */
+ uuid_copy (old_loc.gfid, trash_gfid);
+ uuid_copy (old_loc.pargfid, root_gfid);
+ ret = extract_trash_directory (priv->oldtrash_dir,
+ &old_loc.name);
+ if (ret) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ goto out;
+ }
+ old_loc.path = gf_strdup (priv->oldtrash_dir);
+ if (!old_loc.path) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ old_loc.inode = inode_ref (priv->trash_inode);
+ uuid_copy(old_loc.inode->gfid, old_loc.gfid);
+
+ STACK_WIND (frame, trash_notify_rename_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->rename,
+ &old_loc, &loc, dict);
+ if (priv->oldtrash_dir)
+ GF_FREE (priv->oldtrash_dir);
+
+ priv->oldtrash_dir = gf_strdup(priv->newtrash_dir);
+ if (!priv->oldtrash_dir) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ }
+ } else {
+ ret = default_notify (this, event, data);
+ if (ret)
+ gf_log (this->name, GF_LOG_INFO,
+ "default notify event failed");
+ }
+
+out:
+ if (ret && tgfid_ptr)
+ GF_FREE (tgfid_ptr);
+ if (dict)
+ dict_unref (dict);
+ loc_wipe (&loc);
+ loc_wipe (&old_loc);
+
+ return ret;
+}
+
+int32_t
+mem_acct_init (xlator_t *this)
+{
+ int ret = -1;
+
+ GF_VALIDATE_OR_GOTO ("trash", this, out);
+
+ ret = xlator_mem_acct_init (this, gf_trash_mt_end + 1);
+ if (ret != 0) {
+ gf_log(this->name, GF_LOG_ERROR, "Memory accounting init"
+ "failed");
+ return ret;
+ }
+out:
+ return ret;
+}
+
+/**
+ * trash_init
*/
int32_t
init (xlator_t *this)
{
- data_t *data = NULL;
- trash_private_t *_priv = NULL;
- trash_elim_pattern_t *trav = NULL;
- char *tmp_str = NULL;
- char *strtokptr = NULL;
- char *component = NULL;
- char trash_dir[PATH_MAX] = {0,};
- uint64_t max_trash_file_size64 = 0;
-
- /* Create .trashcan directory in init */
+ trash_private_t *priv = NULL;
+ int ret = -1;
+ char *tmp = NULL;
+ char *tmp_str = NULL;
+ char trash_dir[PATH_MAX] = {0,};
+ uint64_t max_trash_file_size64 = 0;
+ data_t *data = NULL;
+
+ GF_VALIDATE_OR_GOTO ("trash", this, out);
+
if (!this->children || this->children->next) {
gf_log (this->name, GF_LOG_ERROR,
"not configured with exactly one child. exiting");
- return -1;
+ ret = -1;
+ goto out;
}
if (!this->parents) {
gf_log (this->name, GF_LOG_WARNING,
- "dangling volume. check volfile ");
+ "dangling volume. check volfile");
}
- _priv = GF_CALLOC (1, sizeof (*_priv), gf_trash_mt_trash_private_t);
- if (!_priv) {
+ priv = GF_CALLOC (1, sizeof (*priv), gf_trash_mt_trash_private_t);
+ if (!priv) {
gf_log (this->name, GF_LOG_ERROR, "out of memory");
- return -1;
+ ret = ENOMEM;
+ goto out;
}
- data = dict_get (this->options, "trash-dir");
- if (!data) {
+ /* Trash priv data members are initialized through the following
+ * set of statements
+ */
+ GF_OPTION_INIT ("trash", priv->state, bool, out);
+
+ GF_OPTION_INIT ("trash-dir", tmp, str, out);
+
+ /* We store trash dir value as path for easier manipulation*/
+ if (!tmp) {
gf_log (this->name, GF_LOG_INFO,
"no option specified for 'trash-dir', "
"using \"/.trashcan/\"");
- _priv->trash_dir = gf_strdup ("/.trashcan");
+ priv->newtrash_dir = gf_strdup ("/.trashcan/");
+ if (!priv->newtrash_dir) {
+ ret = ENOMEM;
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
+ }
} else {
- /* Need a path with '/' as the first char, if not
- given, append it */
- if (data->data[0] == '/') {
- _priv->trash_dir = gf_strdup (data->data);
- } else {
- /* TODO: Make sure there is no ".." in the path */
- strcpy (trash_dir, "/");
- strcat (trash_dir, data->data);
- _priv->trash_dir = gf_strdup (trash_dir);
+ sprintf(trash_dir, "/%s/", tmp);
+ priv->newtrash_dir = gf_strdup (trash_dir);
+ if (!priv->newtrash_dir) {
+ ret = ENOMEM;
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
}
}
+ tmp = NULL;
- data = dict_get (this->options, "eliminate-pattern");
- if (!data) {
- gf_log (this->name, GF_LOG_TRACE,
+ GF_OPTION_INIT ("trash-eliminate-path", tmp, str, out);
+ if (!tmp) {
+ gf_log (this->name, GF_LOG_INFO,
"no option specified for 'eliminate', using NULL");
} else {
- tmp_str = gf_strdup (data->data);
+ tmp_str = gf_strdup (tmp);
if (!tmp_str) {
- gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ gf_log (this->name, GF_LOG_ERROR,
+ "out of memory");
+ ret = ENOMEM;
+ goto out;
}
+ ret = store_eliminate_path (tmp_str, priv->eliminate);
- /* Match Filename to option specified in eliminate. */
- component = strtok_r (tmp_str, "|", &strtokptr);
- while (component) {
- trav = GF_CALLOC (1, sizeof (*trav),
- gf_trash_mt_trash_elim_pattern_t);
- if (!trav) {
- gf_log (this->name, GF_LOG_DEBUG, "out of memory");
- break;
- }
- trav->pattern = component;
- trav->next = _priv->eliminate;
- _priv->eliminate = trav;
-
- component = strtok_r (NULL, "|", &strtokptr);
- }
}
+ tmp = NULL;
- /* TODO: do gf_string2sizet () */
- data = dict_get (this->options, "max-trashable-file-size");
- if (!data) {
- gf_log (this->name, GF_LOG_DEBUG,
+ GF_OPTION_INIT ("trash-max-filesize", max_trash_file_size64,
+ size_uint64, out);
+ if (!max_trash_file_size64) {
+ gf_log (this->name, GF_LOG_ERROR,
"no option specified for 'max-trashable-file-size', "
"using default = %lld MB",
GF_DEFAULT_MAX_FILE_SIZE / GF_UNIT_MB);
- _priv->max_trash_file_size = GF_DEFAULT_MAX_FILE_SIZE;
+ priv->max_trash_file_size = GF_DEFAULT_MAX_FILE_SIZE;
} else {
- (void)gf_string2bytesize (data->data,
- &max_trash_file_size64);
if( max_trash_file_size64 > GF_ALLOWED_MAX_FILE_SIZE ) {
gf_log (this->name, GF_LOG_DEBUG,
"Size specified for max-size(in MB) is too "
"large so using 1GB as max-size (NOT IDEAL)");
- _priv->max_trash_file_size = GF_ALLOWED_MAX_FILE_SIZE;
+ priv->max_trash_file_size = GF_ALLOWED_MAX_FILE_SIZE;
} else
- _priv->max_trash_file_size = max_trash_file_size64;
+ priv->max_trash_file_size = max_trash_file_size64;
gf_log (this->name, GF_LOG_DEBUG, "%"GF_PRI_SIZET" max-size",
- _priv->max_trash_file_size);
+ priv->max_trash_file_size);
}
+ GF_OPTION_INIT ("trash-internal-op", priv->internal, bool, out);
+
this->local_pool = mem_pool_new (trash_local_t, 64);
if (!this->local_pool) {
gf_log (this->name, GF_LOG_ERROR,
"failed to create local_t's memory pool");
- return -1;
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /* For creating directories inside trash with proper permissions,
+ * we need to perform stat on that directories, for this we use
+ * brick path
+ */
+ data = dict_get (this->options, "brick-path");
+ if (!data) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "no option specified for 'brick-path'");
+ ret = ENOMEM;
+ goto out;
+ }
+ priv->brick_path = gf_strdup (data->data);
+ if (!priv->brick_path) {
+ ret = ENOMEM;
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ goto out;
}
+ gf_log (this->name, GF_LOG_DEBUG, "brick path is%s", priv->brick_path);
- this->private = (void *)_priv;
- return 0;
+ this->private = (void *)priv;
+ ret = 0;
+
+out:
+ if (tmp_str)
+ GF_FREE (tmp_str);
+ if (ret) {
+ if (priv) {
+ if (priv->newtrash_dir)
+ GF_FREE (priv->newtrash_dir);
+ if (priv->oldtrash_dir)
+ GF_FREE (priv->oldtrash_dir);
+ if (priv->brick_path)
+ GF_FREE (priv->brick_path);
+ if (priv->eliminate)
+ wipe_eliminate_path (priv->eliminate);
+ GF_FREE (priv);
+ }
+ mem_pool_destroy (this->local_pool);
+ }
+ return ret;
}
+/**
+ * trash_fini
+ */
void
fini (xlator_t *this)
{
trash_private_t *priv = NULL;
+ GF_VALIDATE_OR_GOTO ("trash", this, out);
priv = this->private;
- GF_FREE (priv);
+ if (priv) {
+ if (priv->newtrash_dir)
+ GF_FREE (priv->newtrash_dir);
+ if (priv->oldtrash_dir)
+ GF_FREE (priv->oldtrash_dir);
+ if (priv->brick_path)
+ GF_FREE (priv->brick_path);
+ if (priv->eliminate)
+ wipe_eliminate_path (priv->eliminate);
+ GF_FREE (priv);
+ }
+ mem_pool_destroy (this->local_pool);
+ this->private = NULL;
+out:
return;
}
struct xlator_fops fops = {
- .unlink = trash_unlink,
- .rename = trash_rename,
- .truncate = trash_truncate,
- .ftruncate = trash_ftruncate,
+ .unlink = trash_unlink,
+ .truncate = trash_truncate,
+ .ftruncate = trash_ftruncate,
+ .rmdir = trash_rmdir,
+ .mkdir = trash_mkdir,
+ .rename = trash_rename,
};
struct xlator_cbks cbks = {
};
struct volume_options options[] = {
- { .key = { "trash-directory" },
- .type = GF_OPTION_TYPE_PATH,
+ { .key = { "trash" },
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "off",
+ .description = "Enable/disable trash translator",
+ },
+ { .key = { "trash-dir" },
+ .type = GF_OPTION_TYPE_STR,
+ .default_value = ".trashcan",
+ .description = "Directory for trash files",
+ },
+ { .key = { "trash-eliminate-path" },
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Eliminate paths to be excluded "
+ "from trashing",
},
- { .key = { "eliminate-pattern" },
- .type = GF_OPTION_TYPE_STR,
+ { .key = { "trash-max-filesize" },
+ .type = GF_OPTION_TYPE_SIZET,
+ .default_value = "5MB",
+ .description = "Maximum size of file that can be "
+ "moved to trash",
},
- { .key = { "max-trashable-file-size" },
- .type = GF_OPTION_TYPE_SIZET,
+ { .key = { "trash-internal-op" },
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "off",
+ .description = "Enable/disable trash translator for "
+ "internal operations",
},
- { .key = {NULL} },
+ { .key = {NULL} },
};
diff --git a/xlators/features/trash/src/trash.h b/xlators/features/trash/src/trash.h
index 9a7c033617d..3e03edf5474 100644
--- a/xlators/features/trash/src/trash.h
+++ b/xlators/features/trash/src/trash.h
@@ -37,7 +37,6 @@
#define GF_ALLOWED_MAX_FILE_SIZE (1 * GF_UNIT_GB)
#endif
-
struct trash_struct {
fd_t *fd; /* for the fd of existing file */
fd_t *newfd; /* for the newly created file */
@@ -54,26 +53,31 @@ struct trash_struct {
};
typedef struct trash_struct trash_local_t;
-struct _trash_elim_pattern;
-typedef struct _trash_elim_pattern {
- struct _trash_elim_pattern *next;
- char *pattern;
-} trash_elim_pattern_t;
+struct _trash_elim_path {
+ struct _trash_elim_path *next;
+ char *path;
+};
+typedef struct _trash_elim_path trash_elim_path;
struct trash_priv {
- char *trash_dir;
- trash_elim_pattern_t *eliminate;
+ char *oldtrash_dir;
+ char *newtrash_dir;
+ char *brick_path;
+ trash_elim_path *eliminate;
size_t max_trash_file_size;
+ gf_boolean_t state;
+ gf_boolean_t internal;
+ inode_t *trash_inode;
+ inode_table_t *trash_itable;
};
typedef struct trash_priv trash_private_t;
-#define TRASH_STACK_UNWIND(op, frame, params ...) do { \
- trash_local_t *__local = NULL; \
- __local = frame->local; \
- frame->local = NULL; \
- STACK_UNWIND_STRICT (op, frame, params); \
- trash_local_wipe (__local); \
- } while (0)
-
+#define TRASH_STACK_UNWIND(op, frame, params ...) do { \
+ trash_local_t *__local = NULL; \
+ __local = frame->local; \
+ frame->local = NULL; \
+ STACK_UNWIND_STRICT (op, frame, params); \
+ trash_local_wipe (__local); \
+ } while (0)
#endif /* __TRASH_H__ */
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
index a78c80eceb4..2f121e49e9e 100644
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
@@ -647,11 +647,14 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr)
char *key = NULL;
char *key_fixed = NULL;
char *value = NULL;
+ char *val_dup = NULL;
char str[100] = {0, };
+ char *trash_path = NULL;
int count = 0;
int dict_count = 0;
char errstr[2048] = {0, };
glusterd_volinfo_t *volinfo = NULL;
+ glusterd_brickinfo_t *brickinfo = NULL;
dict_t *val_dict = NULL;
gf_boolean_t global_opt = _gf_false;
glusterd_volinfo_t *voliter = NULL;
@@ -663,7 +666,9 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr)
uint32_t local_key_op_version = 0;
gf_boolean_t origin_glusterd = _gf_true;
gf_boolean_t check_op_version = _gf_true;
+ gf_boolean_t trash_enabled = _gf_false;
gf_boolean_t all_vol = _gf_false;
+ struct stat stbuf = {0, };
GF_ASSERT (dict);
this = THIS;
@@ -940,6 +945,76 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr)
if (glusterd_check_globaloption (key))
global_opt = _gf_true;
+ if (volinfo) {
+ ret = glusterd_volinfo_get (volinfo,
+ VKEY_FEATURES_TRASH, &val_dup);
+ if (val_dup) {
+ ret = gf_string2boolean (val_dup,
+ &trash_enabled);
+ if (ret)
+ goto out;
+ }
+ }
+
+ if (!strcmp(key, "features.trash-dir") && trash_enabled) {
+ if (strchr (value, '/')) {
+ snprintf (errstr, sizeof (errstr),
+ "Path is not allowed as option");
+ gf_log (this->name, GF_LOG_ERROR,
+ "Unable to set the options in 'volume "
+ "set': %s", errstr);
+ ret = -1;
+ goto out;
+ }
+
+ list_for_each_entry (brickinfo, &volinfo->bricks,
+ brick_list) {
+ /* Check for local brick */
+ if (!uuid_compare (brickinfo->uuid, MY_UUID)) {
+ trash_path = gf_strdup (brickinfo->path);
+ strcat(trash_path, "/");
+ strcat(trash_path, value);
+
+ /* Checks whether a directory with
+ given option exists or not */
+ if (!stat(trash_path, &stbuf)) {
+ snprintf (errstr, sizeof (errstr),
+ "Path %s exists", value);
+ gf_log (this->name, GF_LOG_ERROR,
+ "Unable to set the options in "
+ "'volume set': %s", errstr);
+ ret = -1;
+ goto out;
+ } else {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "Directory with given name "
+ "does not exists, continuing");
+ }
+
+ if (volinfo->status == GLUSTERD_STATUS_STARTED
+ && brickinfo->status != GF_BRICK_STARTED) {
+ /* If volume is in started state , checks
+ whether bricks are online */
+ snprintf (errstr, sizeof (errstr),
+ "One or more bricks are down");
+ gf_log (this->name, GF_LOG_ERROR,
+ "Unable to set the options in "
+ "'volume set': %s", errstr);
+ ret = -1;
+ goto out;
+ }
+ }
+ }
+ } else if (!strcmp(key, "features.trash-dir") && !trash_enabled) {
+ snprintf (errstr, sizeof (errstr),
+ "Trash translator is not enabled. Use "
+ "volume set %s trash on", volname);
+ gf_log (this->name, GF_LOG_ERROR,
+ "Unable to set the options in 'volume "
+ "set': %s", errstr);
+ ret = -1;
+ goto out;
+ }
ret = dict_set_str (val_dict, key, value);
if (ret) {
@@ -1015,6 +1090,9 @@ out:
if (val_dict)
dict_unref (val_dict);
+ if (trash_path)
+ GF_FREE (trash_path);
+
GF_FREE (key_fixed);
if (errstr[0] != '\0')
*op_errstr = gf_strdup (errstr);
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
index 1af7a77cff1..779d6be34a4 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
@@ -1421,6 +1421,7 @@ brick_graph_add_posix (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
{
int ret = -1;
gf_boolean_t quota_enabled = _gf_true;
+ gf_boolean_t trash_enabled = _gf_false;
gf_boolean_t pgfid_feat = _gf_false;
char *value = NULL;
xlator_t *xl = NULL;
@@ -1435,6 +1436,13 @@ brick_graph_add_posix (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
goto out;
}
+ ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_TRASH, &value);
+ if (value) {
+ ret = gf_string2boolean (value, &trash_enabled);
+ if (ret)
+ goto out;
+ }
+
ret = glusterd_volinfo_get (volinfo,
"update-link-count-parent",
&value);
@@ -1459,7 +1467,7 @@ brick_graph_add_posix (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
if (ret)
goto out;
- if (quota_enabled || pgfid_feat)
+ if (quota_enabled || pgfid_feat || trash_enabled)
xlator_set_option (xl, "update-link-count-parent",
"on");
out:
@@ -1467,6 +1475,29 @@ out:
}
static int
+brick_graph_add_trash (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
+ dict_t *set_dict, glusterd_brickinfo_t *brickinfo)
+{
+ int ret = -1;
+ xlator_t *xl = NULL;
+
+ xl = volgen_graph_add (graph, "features/trash", volinfo->volname);
+ if (!xl)
+ goto out;
+ ret = xlator_set_option (xl, "trash-dir", ".trashcan");
+ if (ret)
+ goto out;
+ ret = xlator_set_option (xl, "brick-path", brickinfo->path);
+ if (ret)
+ goto out;
+ ret = xlator_set_option (xl, "trash-internal-op", "off");
+ if (ret)
+ goto out;
+out:
+ return ret;
+}
+
+static int
brick_graph_add_bd (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,
dict_t *set_dict, glusterd_brickinfo_t *brickinfo)
{
@@ -2018,6 +2049,7 @@ static volgen_brick_xlator_t server_graph_table[] = {
{brick_graph_add_acl, "acl"},
{brick_graph_add_changelog, "changelog"},
{brick_graph_add_bd, "bd"},
+ {brick_graph_add_trash, "trash"},
{brick_graph_add_posix, "posix"},
};
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h
index bc9c2265384..947de76c926 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.h
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h
@@ -32,6 +32,7 @@
#define VKEY_MARKER_XTIME_FORCE GEOREP".ignore-pid-check"
#define VKEY_CHANGELOG "changelog.changelog"
#define VKEY_FEATURES_QUOTA "features.quota"
+#define VKEY_FEATURES_TRASH "features.trash"
#define AUTH_ALLOW_MAP_KEY "auth.allow"
#define AUTH_REJECT_MAP_KEY "auth.reject"
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
index b0cf2609210..77f6853dd51 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
@@ -1641,6 +1641,28 @@ struct volopt_map_entry glusterd_volopt_map[] = {
.voltype = "mgmt/glusterd",
.op_version = GD_OP_VERSION_3_6_0,
},
+
+ /*Trash translator options */
+ { .key = "features.trash",
+ .voltype = "features/trash",
+ .op_version = GD_OP_VERSION_3_7_0,
+ },
+ { .key = "features.trash-dir",
+ .voltype = "features/trash",
+ .op_version = GD_OP_VERSION_3_7_0,
+ },
+ { .key = "features.trash-eliminate-path",
+ .voltype = "features/trash",
+ .op_version = GD_OP_VERSION_3_7_0,
+ },
+ { .key = "features.trash-max-filesize",
+ .voltype = "features/trash",
+ .op_version = GD_OP_VERSION_3_7_0,
+ },
+ { .key = "features.trash-internal-op",
+ .voltype = "features/trash",
+ .op_version = GD_OP_VERSION_3_7_0,
+ },
{ .key = "locks.trace",
.voltype = "features/locks",
.type = NO_DOC,