summaryrefslogtreecommitdiffstats
path: root/xlators/features/trash/src
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/features/trash/src')
-rw-r--r--xlators/features/trash/src/trash.c329
-rw-r--r--xlators/features/trash/src/trash.h9
2 files changed, 337 insertions, 1 deletions
diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c
index 98d0663279c..89cb1221af0 100644
--- a/xlators/features/trash/src/trash.c
+++ b/xlators/features/trash/src/trash.c
@@ -24,6 +24,333 @@
#include "trash.h"
+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);
+
+void
+trash_local_wipe (trash_local_t *local)
+{
+ if (!local)
+ goto out;
+
+ loc_wipe (&local->loc);
+ loc_wipe (&local->newloc);
+
+ if (local->fd)
+ fd_unref (local->fd);
+
+ if (local->newfd)
+ fd_unref (local->newfd);
+
+ FREE (local);
+out:
+ return;
+}
+
+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_STACK_UNWIND (frame, op_ret, op_errno, preparent, postparent);
+ return 0;
+}
+
+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 stat *stbuf, struct stat *preparent,
+ struct stat *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;
+ int32_t loop_count = 0;
+ int i = 0;
+ loc_t tmp_loc = {0,};
+
+ local = frame->local;
+ tmp_str = strdup (local->newpath);
+ if (!tmp_str) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ }
+ loop_count = local->loop_count;
+
+ 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;
+ i++;
+ if (i > loop_count)
+ break;
+ tmp_dirname = strchr (tmp_str + count + 1, '/');
+ }
+ tmp_path = strndup (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_unlink_mkdir_cbk, tmp_path,
+ this->children->xlator,
+ this->children->xlator->fops->mkdir,
+ &tmp_loc, 0755);
+
+ goto out;
+ }
+
+ if (op_ret == 0) {
+ dir_name = dirname (tmp_str);
+ if (strcmp((char*)cookie, dir_name) == 0) {
+ tmp_loc.path = local->newpath;
+ STACK_WIND (frame, trash_unlink_rename_cbk,
+ this->children->xlator,
+ this->children->xlator->fops->rename,
+ &local->loc, &tmp_loc);
+ goto out;
+ }
+ }
+
+ LOCK (&frame->lock);
+ {
+ 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 = strndup (local->newpath, count);
+ if (!tmp_path) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ }
+ tmp_loc.path = tmp_path;
+
+ STACK_WIND_COOKIE (frame, trash_unlink_mkdir_cbk, tmp_path,
+ this->children->xlator,
+ this->children->xlator->fops->mkdir,
+ &tmp_loc, 0755);
+
+out:
+ free (cookie);
+ free (tmp_str);
+
+ return 0;
+}
+
+
+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 = NULL;
+ trash_private_t *priv = NULL;
+ char *tmp_str = NULL;
+ char *dir_name = NULL;
+ char *tmp_cookie = NULL;
+ loc_t tmp_loc = {0,};
+
+ priv = this->private;
+ local = frame->local;
+
+ if ((op_ret == -1) && (op_errno == ENOENT)) {
+ tmp_str = strdup (local->newpath);
+ if (!tmp_str) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ }
+ dir_name = dirname (tmp_str);
+
+ tmp_loc.path = dir_name;
+
+ tmp_cookie = strdup (dir_name);
+ if (!tmp_cookie) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ }
+ /* TODO: 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);
+
+ 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 copy, deleting",
+ local->newpath);
+
+ STACK_WIND (frame, trash_common_unwind_cbk,
+ this->children->xlator,
+ this->children->xlator->fops->unlink, &local->loc);
+
+ return 0;
+ }
+
+ if ((op_ret == -1) && (op_errno == EISDIR)) {
+ 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;
+ }
+
+ /* All other cases, unlink should return success */
+ TRASH_STACK_UNWIND (frame, 0, op_errno, &local->preparent,
+ &local->postparent);
+
+ 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 stat *buf)
+{
+ trash_private_t *priv = NULL;
+ trash_local_t *local = NULL;
+ loc_t new_loc = {0,};
+
+ priv = this->private;
+ local = frame->local;
+
+ if (-1 == op_ret) {
+ gf_log (this->name, GF_LOG_DEBUG, "%s: %s",
+ local->loc.path, strerror (op_errno));
+ goto fail;
+ }
+
+ if ((buf->st_size == 0) ||
+ (buf->st_size > priv->max_trash_file_size)) {
+ /* if the file is too big or zero, just unlink it */
+
+ if (buf->st_size > priv->max_trash_file_size) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "%s: file size too big (%"GF_PRI_SIZET") to "
+ "move into trash directory",
+ local->loc.path, buf->st_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 (frame, op_ret, op_errno, buf,
+ NULL, NULL, NULL, NULL);
+
+ 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;
+ struct tm *tm = NULL;
+ char timestr[256] = {0,};
+ time_t utime = 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;
+ }
+ }
+
+ if ((strncmp (loc->path, priv->trash_dir,
+ strlen (priv->trash_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 */
+ ;
+ }
+
+ STACK_WIND (frame, trash_common_unwind_cbk,
+ this->children->xlator,
+ this->children->xlator->fops->unlink, loc);
+ return 0;
+ }
+
+ local = CALLOC (1, sizeof (trash_local_t));
+ if (!local) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ TRASH_STACK_UNWIND (frame, -1, ENOMEM, NULL, NULL);
+ return 0;
+ }
+ frame->local = local;
+ loc_copy (&local->loc, loc);
+
+ strcpy (local->origpath, loc->path);
+ strcpy (local->newpath, priv->trash_dir);
+ strcat (local->newpath, loc->path);
+
+ {
+ /* append timestamp to file name */
+ /* TODO: can we make it optional? */
+ utime = time (NULL);
+ tm = localtime (&utime);
+ strftime (timestr, 256, ".%Y-%m-%d-%H%M%S", tm);
+ strcat (local->newpath, timestr);
+ }
+
+ LOCK_INIT (&frame->lock);
+
+ STACK_WIND (frame, trash_unlink_stat_cbk,
+ this->children->xlator,
+ this->children->xlator->fops->stat, loc);
+
+ return 0;
+}
+
/**
* trash_init -
*/
@@ -139,10 +466,10 @@ fini (xlator_t *this)
}
struct xlator_fops fops = {
+ .unlink = trash_unlink,
};
struct xlator_mops mops = {
-
};
struct xlator_cbks cbks = {
diff --git a/xlators/features/trash/src/trash.h b/xlators/features/trash/src/trash.h
index 7f0e13085b1..48d5196bd2d 100644
--- a/xlators/features/trash/src/trash.h
+++ b/xlators/features/trash/src/trash.h
@@ -77,4 +77,13 @@ struct trash_priv {
};
typedef struct trash_priv trash_private_t;
+#define TRASH_STACK_UNWIND(frame, params ...) do { \
+ trash_local_t *__local = NULL; \
+ __local = frame->local; \
+ frame->local = NULL; \
+ STACK_UNWIND (frame, params); \
+ trash_local_wipe (__local); \
+ } while (0)
+
+
#endif /* __TRASH_H__ */