summaryrefslogtreecommitdiffstats
path: root/xlators/features/trash/src/trash.c
diff options
context:
space:
mode:
authorAmar Tumballi <amar@gluster.com>2009-11-30 01:16:35 +0000
committerAnand V. Avati <avati@dev.gluster.com>2009-12-01 10:02:48 -0800
commit936001b147a3adcf9731d02e8f2fb62e5e50caf4 (patch)
treeed0592d8276a3ff16ec3e15e58c4819b33352992 /xlators/features/trash/src/trash.c
parent90cebe19380b4319e3a4345f31268563b51e08c3 (diff)
features/trash initial cleanup commit
* support O_TRUNC flag in open (call comes to FS as 'truncate' or 'ftruncate' fop) * option to provide 'eliminate-pattern' so those files matching won't be kept in trash. Eg: option eliminate-pattern *.out|*~ * option to give 'maximum' file size to keep in trash, ie, when a 20GB file is deleted, it won't be kept in trash if max file size given is 1GB. Eg: option max-trashable-file-size 1GB These particular features are developped as a part of college project by following team: Sunil bhagwath <sunilkbhagwat@gmail.com> Yashaswi Kumar <yashaswikumar@gmail.com> Rashmi B K <rashmibk17@gmail.com> Sandeep M <astrophyster@gmail.com> Submitting after minor coding standard edits and memoryleak fixes. Signed-off-by: Amar Tumballi <amar@gluster.com> Signed-off-by: Anand V. Avati <avati@dev.gluster.com> BUG: 142 (enhance features/trash translator so it can work on client side too..) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=142
Diffstat (limited to 'xlators/features/trash/src/trash.c')
-rw-r--r--xlators/features/trash/src/trash.c722
1 files changed, 112 insertions, 610 deletions
diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c
index b2de4cdbe50..98d0663279c 100644
--- a/xlators/features/trash/src/trash.c
+++ b/xlators/features/trash/src/trash.c
@@ -22,556 +22,7 @@
#include "config.h"
#endif
-
-#include "glusterfs.h"
-#include "logging.h"
-#include "dict.h"
-#include "xlator.h"
-#include "defaults.h"
-
-#include <libgen.h>
-
-/* TODO: currently it can work only above posix, no other translators
- * between them. Not a good thing. Try making more reliable methods.
- */
-
-struct trash_struct {
- inode_t *inode;
- loc_t loc1;
- loc_t loc2;
- char origpath[ZR_PATH_MAX];
- char newpath[ZR_PATH_MAX];
- char oldpath[ZR_PATH_MAX]; // used only in case of rename
-};
-typedef struct trash_struct trash_local_t;
-
-struct trash_priv {
- char trash_dir[ZR_PATH_MAX];
-};
-typedef struct trash_priv trash_private_t;
-
-int32_t
-trash_unlink_rename_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf,
- struct stat *preoldparent,
- struct stat *postoldparent,
- struct stat *prenewparent,
- struct stat *postnewparent);
-int32_t
-trash_rename_rename_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf,
- struct stat *preoldparent,
- struct stat *postoldparent,
- struct stat *prenewparent,
- struct stat *postnewparent);
-
-/**
- * trash_common_unwind_cbk -
- */
-int32_t
-trash_common_unwind_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *preparent,
- struct stat *postparent)
-{
- trash_local_t *local = frame->local;
-
- if (!local)
- goto out;
-
- if (local->loc1.path)
- loc_wipe (&local->loc1);
-
- if (local->loc2.path)
- loc_wipe (&local->loc2);
-
- out:
- STACK_UNWIND (frame, op_ret, op_errno);
- return 0;
-}
-
-
-/**
- * trash_rename_unwind_buf_cbk -
- */
-int32_t
-trash_rename_unwind_buf_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf,
- struct stat *preoldparent,
- struct stat *postoldparent,
- struct stat *prenewparent,
- struct stat *postnewparent)
-{
- trash_local_t *local = frame->local;
-
- if (!local)
- goto out;
-
- if (local->loc1.path)
- loc_wipe (&local->loc1);
-
- if (local->loc2.path)
- loc_wipe (&local->loc2);
-
- out:
- STACK_UNWIND (frame, op_ret, op_errno, buf);
- return 0;
-}
-
-
-/**
- * trash_common_unwind_buf_cbk -
- */
-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 stat *buf)
-{
- trash_local_t *local = frame->local;
-
- if (!local)
- goto out;
-
- if (local->loc1.path)
- loc_wipe (&local->loc1);
-
- if (local->loc2.path)
- loc_wipe (&local->loc2);
-
- out:
- STACK_UNWIND (frame, op_ret, op_errno, buf);
- return 0;
-}
-
-int32_t
-trash_mkdir_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- inode_t *inode,
- struct stat *stbuf,
- struct stat *preparent,
- struct stat *postparent)
-{
- trash_local_t *local = frame->local;
- char *tmp_str = strdup (local->newpath);
- int32_t count = 0;
- char *tmp_path = NULL;
- char *tmp_dirname = NULL;
-
- 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_path = CALLOC (1, count + 1);
- ERR_ABORT (tmp_path);
- memcpy (tmp_path, local->newpath, count);
- loc_t tmp_loc = {
- .inode = NULL,
- .path = tmp_path,
- };
-
- /* TODO:create the directory with proper permissions */
- STACK_WIND_COOKIE (frame,
- trash_mkdir_cbk,
- tmp_path,
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc,
- 0777);
- tmp_dirname = strchr (tmp_str + count + 1, '/');
- }
- free (cookie);
- free (tmp_str);
- return 0;
- }
- char *dir_name = dirname (tmp_str);
- if (strcmp((char*)cookie, dir_name) == 0) {
- loc_t new_loc = {
- .inode = NULL,
- .path = local->newpath
- };
- STACK_WIND (frame,
- trash_unlink_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc2,
- &new_loc);
-
- }
- free (cookie); /* strdup (dir_name) was sent here :) */
- free (tmp_str);
- return 0;
-}
-
-/**
- * trash_unlink_rename_cbk -
- */
-int32_t
-trash_unlink_rename_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf,
- struct stat *preoldparent,
- struct stat *postoldparent,
- struct stat *prenewparent,
- struct stat *postnewparent)
-{
- trash_local_t *local = frame->local;
- if (op_ret == -1 && op_errno == ENOENT) {
- /* check for the errno, if its ENOENT create directory and call
- * rename later
- */
- char *tmp_str = strdup (local->newpath);
- char *dir_name = dirname (tmp_str);
- loc_t tmp_loc = {
- .inode = NULL,
- .path = dir_name,
- };
- /* TODO: create the directory with proper permissions */
- STACK_WIND_COOKIE (frame,
- trash_mkdir_cbk,
- strdup (dir_name),
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc,
- 0777);
- free (tmp_str);
- } else if (op_ret == -1 && op_errno == ENOTDIR) {
- gf_log (this->name, GF_LOG_WARNING,
- "Target exists, cannot keep the copy, deleting");
- STACK_WIND (frame,
- trash_common_unwind_cbk,
- this->children->xlator,
- this->children->xlator->fops->unlink,
- &local->loc2);
- } else if (op_ret == -1 && op_errno == EISDIR) {
- gf_log (this->name, GF_LOG_WARNING,
- "Target exists as a directory, cannot keep the copy, "
- "deleting");
- STACK_WIND (frame,
- trash_common_unwind_cbk,
- this->children->xlator,
- this->children->xlator->fops->unlink,
- &local->loc2);
- } else {
- /* */
- STACK_UNWIND (frame, 0, op_errno);
- }
-
- return 0;
-}
-
-
-/**
- * trash_unlink -
- */
-int32_t
-trash_unlink (call_frame_t *frame,
- xlator_t *this,
- loc_t *loc)
-{
- trash_private_t *priv = this->private;
- trash_local_t *local = NULL;
- time_t utime = 0;
- struct tm *tm = NULL;
- char timestr[256];
-
- if (strncmp (loc->path, priv->trash_dir,
- strlen(priv->trash_dir)) == 0) {
- /* Trying to rename from the trash can dir, do the
- actual unlink */
- STACK_WIND (frame,
- trash_common_unwind_cbk,
- this->children->xlator,
- this->children->xlator->fops->unlink,
- loc);
- } else {
- local = CALLOC (1, sizeof (trash_local_t));
- if (!local) {
- STACK_UNWIND (frame, -1, ENOMEM);
- return 0;
- }
- frame->local = local;
-
- loc_copy (&local->loc2, loc);
-
- strcpy (local->newpath, priv->trash_dir);
- strcat (local->newpath, loc->path);
-
- utime = time (NULL);
- tm = localtime (&utime);
- strftime (timestr, 256, ".%Y%m%d%H%M%S", tm);
- strcat (local->newpath, timestr);
-
- {
- loc_t new_loc = {
- .inode = NULL,
- .path = local->newpath
- };
- STACK_WIND (frame,
- trash_unlink_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- loc,
- &new_loc);
- }
- }
- 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 stat *stbuf,
- struct stat *preparent,
- struct stat *postparent)
-{
- trash_local_t *local = frame->local;
- char *tmp_str = strdup (local->newpath);
-
- if (op_ret == -1 && op_errno == ENOENT) {
- int32_t count = 0;
- char *tmp_path = NULL;
- char *tmp_dirname = strchr (tmp_str, '/');
-
- while (tmp_dirname) {
- count = tmp_dirname - tmp_str;
- if (count == 0)
- count = 1;
- tmp_path = CALLOC (1, count + 2);
- ERR_ABORT (tmp_path);
- memcpy (tmp_path, local->newpath, count);
- loc_t tmp_loc = {
- .inode = NULL,
- .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,
- 0777);
- tmp_dirname = strchr (tmp_str + count + 1, '/');
- }
- free (cookie);
- free (tmp_str);
- return 0;
- }
- char *dir_name = dirname (tmp_str);
- if (strcmp((char*)cookie, dir_name) == 0) {
- loc_t new_loc = {
- .inode = NULL,
- .path = local->newpath
- };
- STACK_WIND (frame,
- trash_rename_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc2,
- &new_loc);
-
- }
- free (cookie); /* strdup (dir_name) was sent here :) */
- free (tmp_str);
- return 0;
-}
-
-
-/**
- * trash_unlink_rename_cbk -
- */
-int32_t
-trash_rename_rename_cbk (call_frame_t *frame,
- void *cookie,
- xlator_t *this,
- int32_t op_ret,
- int32_t op_errno,
- struct stat *buf,
- struct stat *preoldparent,
- struct stat *postoldparent,
- struct stat *prenewparent,
- struct stat *postnewparent)
-{
- trash_local_t *local = frame->local;
- if (op_ret == -1 && op_errno == ENOENT) {
- /* check for the errno, if its ENOENT create directory and call
- * rename later
- */
- char *tmp_str = strdup (local->newpath);
- char *dir_name = dirname (tmp_str);
- loc_t tmp_loc = {
- .inode = NULL,
- .path = dir_name,
- };
- /* TODO: create the directory with proper permissions */
- STACK_WIND_COOKIE (frame,
- trash_rename_mkdir_cbk,
- strdup (dir_name),
- this->children->xlator,
- this->children->xlator->fops->mkdir,
- &tmp_loc,
- 0777);
- free (tmp_str);
- return 0;
- } else if (op_ret == -1 && op_errno == ENOTDIR) {
- gf_log (this->name, GF_LOG_WARNING,
- "Target exists, cannot keep the dest entry %s, "
- "renaming",
- local->loc2.path);
- } else if (op_ret == -1 && op_errno == EISDIR) {
- gf_log (this->name, GF_LOG_WARNING,
- "Target exists as a directory, cannot keep the "
- "copy %s, renaming",
- local->loc2.path);
- }
- loc_t new_loc = {
- .inode = NULL,
- .parent = local->loc2.parent,
- .path = local->loc2.path,
- };
- STACK_WIND (frame,
- trash_rename_unwind_buf_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc1,
- &new_loc);
-
- return 0;
-}
-
-/**
- * trash_rename_lookup_cbk -
- */
-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 stat *buf,
- dict_t *xattr,
- struct stat *postparent)
-{
- trash_local_t *local = frame->local;
-
- if (op_ret == -1) {
- STACK_WIND (frame,
- trash_rename_unwind_buf_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &local->loc1,
- &local->loc2);
- return 0;
- }
-
- loc_t oldloc = {
- .parent = local->loc2.parent,
- .inode = inode,
- .path = local->loc2.path,
- };
- loc_t newloc = {
- .inode = NULL,
- .path = local->newpath
- };
- STACK_WIND (frame,
- trash_rename_rename_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- &oldloc,
- &newloc);
-
- return 0;
-}
-
-
-/**
- * trash_rename -
- */
-int32_t
-trash_rename (call_frame_t *frame,
- xlator_t *this,
- loc_t *oldloc,
- loc_t *newloc)
-{
- trash_private_t *priv = this->private;
- trash_local_t *local = NULL;
- time_t utime = 0;
- struct tm *tm = NULL;
- char timestr[256];
-
- if (strncmp (oldloc->path, priv->trash_dir,
- strlen(priv->trash_dir)) == 0) {
- /* Trying to rename from the trash can dir,
- do the actual rename */
- STACK_WIND (frame,
- trash_rename_unwind_buf_cbk,
- this->children->xlator,
- this->children->xlator->fops->rename,
- oldloc,
- newloc);
- } else {
- /* Trying to rename a regular file from GlusterFS */
- local = CALLOC (1, sizeof (trash_local_t));
- if (!local) {
- STACK_UNWIND (frame, -1, ENOMEM, NULL);
- return 0;
- }
- frame->local = local;
- loc_copy (&local->loc1, oldloc);
- loc_copy (&local->loc2, newloc);
-
- strcpy (local->newpath, priv->trash_dir);
- strcat (local->newpath, newloc->path);
-
- utime = time (NULL);
- tm = localtime (&utime);
- strftime (timestr, 256, ".%Y%m%d%H%M%S", tm);
- strcat (local->newpath, timestr);
-
- /* 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;
-}
+#include "trash.h"
/**
* trash_init -
@@ -579,70 +30,115 @@ trash_rename (call_frame_t *frame,
int32_t
init (xlator_t *this)
{
- data_t *trash_dir = NULL;
- xlator_list_t *trav = NULL;
- trash_private_t *_priv = NULL;
-
- /* Create .trashcan directory in init */
- if (!this->children || this->children->next) {
- gf_log (this->name, GF_LOG_ERROR,
- "not configured with exactly one child. exiting");
- return -1;
- }
-
- if (!this->parents) {
- gf_log (this->name, GF_LOG_WARNING,
- "dangling volume. check volfile ");
- }
-
- trav = this->children;
- while (trav->xlator->children)
- trav = trav->xlator->children;
-
- if (strncmp ("storage/", trav->xlator->type, 8))
- {
- gf_log (this->name, GF_LOG_ERROR,
- "'trash' translator not loaded over storage "
- "translator, not a supported setup");
- return -1;
- }
-
- _priv = CALLOC (1, sizeof (*_priv));
- ERR_ABORT (_priv);
-
- trash_dir = dict_get (this->options, "trash-dir");
- if (!trash_dir) {
- gf_log (this->name, GF_LOG_WARNING,
- "no option specified for 'trash-dir', "
- "using \"/.trashcan/\"");
- strcpy (_priv->trash_dir, "/.trashcan");
- } else {
- /* Need a path with '/' as the first char, if not
- given, append it */
- if (trash_dir->data[0] == '/') {
- strcpy (_priv->trash_dir, trash_dir->data);
- } else {
- strcpy (_priv->trash_dir, "/");
- strcat (_priv->trash_dir, trash_dir->data);
- }
- }
-
- this->private = (void *)_priv;
- return 0;
+ int32_t ret = 0;
+ 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,};
+
+ /* Create .trashcan directory in init */
+ if (!this->children || this->children->next) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "not configured with exactly one child. exiting");
+ return -1;
+ }
+
+ if (!this->parents) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "dangling volume. check volfile ");
+ }
+
+ _priv = CALLOC (1, sizeof (*_priv));
+ if (!_priv) {
+ gf_log (this->name, GF_LOG_ERROR, "out of memory");
+ return -1;
+ }
+
+ data = dict_get (this->options, "trash-dir");
+ if (!data) {
+ gf_log (this->name, GF_LOG_NORMAL,
+ "no option specified for 'trash-dir', "
+ "using \"/.trashcan/\"");
+ _priv->trash_dir = strdup ("/.trashcan");
+ } else {
+ /* Need a path with '/' as the first char, if not
+ given, append it */
+ if (data->data[0] == '/') {
+ _priv->trash_dir = strdup (data->data);
+ } else {
+ /* TODO: Make sure there is no ".." in the path */
+ strcpy (trash_dir, "/");
+ strcat (trash_dir, data->data);
+ _priv->trash_dir = strdup (trash_dir);
+ }
+ }
+
+ data = dict_get (this->options, "eliminate-pattern");
+ if (!data) {
+ gf_log (this->name, GF_LOG_TRACE,
+ "no option specified for 'eliminate', using NULL");
+ } else {
+ tmp_str = strdup (data->data);
+ if (!tmp_str) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ }
+
+ /* Match Filename to option specified in eliminate. */
+ component = strtok_r (tmp_str, "|", &strtokptr);
+ while (component) {
+ trav = CALLOC (1, sizeof (*trav));
+ if (!trav) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ }
+ trav->pattern = component;
+ trav->next = _priv->eliminate;
+ _priv->eliminate = trav;
+
+ component = strtok_r (NULL, "|", &strtokptr);
+ }
+ }
+
+ /* TODO: do gf_string2sizet () */
+ data = dict_get (this->options, "max-trashable-file-size");
+ if (!data) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "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;
+ } else {
+ ret = gf_string2bytesize (data->data,
+ &_priv->max_trash_file_size);
+ if( _priv->max_trash_file_size > 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;
+ }
+ gf_log (this->name, GF_LOG_DEBUG, "%"GF_PRI_SIZET" max-size",
+ _priv->max_trash_file_size);
+ }
+
+ this->private = (void *)_priv;
+ return 0;
}
void
fini (xlator_t *this)
{
- trash_private_t *priv = this->private;
- FREE (priv);
- return;
-}
+ trash_private_t *priv = NULL;
+
+ priv = this->private;
+ if (priv)
+ FREE (priv);
+ return;
+}
struct xlator_fops fops = {
- .unlink = trash_unlink,
- .rename = trash_rename,
};
struct xlator_mops mops = {
@@ -653,8 +149,14 @@ struct xlator_cbks cbks = {
};
struct volume_options options[] = {
- { .key = { "trash-dir" },
- .type = GF_OPTION_TYPE_PATH
- },
- { .key = {NULL} },
+ { .key = { "trash-directory" },
+ .type = GF_OPTION_TYPE_PATH,
+ },
+ { .key = { "eliminate-pattern" },
+ .type = GF_OPTION_TYPE_STR,
+ },
+ { .key = { "max-trashable-file-size" },
+ .type = GF_OPTION_TYPE_SIZET,
+ },
+ { .key = {NULL} },
};