diff options
Diffstat (limited to 'xlators/features/trash/src')
-rw-r--r-- | xlators/features/trash/src/trash.c | 329 | ||||
-rw-r--r-- | xlators/features/trash/src/trash.h | 9 |
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__ */ |