diff options
-rw-r--r-- | xlators/features/trash/src/trash.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c index 89cb1221af0..ad8d1a7e3fd 100644 --- a/xlators/features/trash/src/trash.c +++ b/xlators/features/trash/src/trash.c @@ -154,6 +154,11 @@ out: 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); int32_t trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, @@ -227,6 +232,18 @@ trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } +int +trash_common_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct stat *stbuf, + struct stat *preoldparent, struct stat *postoldparent, + struct stat *prenewparent, struct stat *postnewparent) +{ + TRASH_STACK_UNWIND (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 stat *buf) @@ -278,6 +295,246 @@ fail: } +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 = 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 = 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 = 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); + + 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 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; + 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"); + } + + 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 = 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_rename_mkdir_cbk, + tmp_path, this->children->xlator, + this->children->xlator->fops->mkdir, + &tmp_loc, 0755); + } + + 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); + } + +out: + free (cookie); /* strdup (dir_name) was sent here :) */ + 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 stat *buf, dict_t *xattr, + struct stat *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->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->newloc.path, buf->st_size); + } + + STACK_WIND (frame, trash_common_rename_cbk, + this->children->xlator, + this->children->xlator->fops->rename, + &local->loc, &local->newloc); + return 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); + + return 0; +} + + +int32_t +trash_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, + loc_t *newloc) +{ + 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, 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); + + return 0; + } + + local = CALLOC (1, sizeof (trash_local_t)); + if (!local) { + gf_log (this->name, GF_LOG_ERROR, "out of memory"); + TRASH_STACK_UNWIND (frame, -1, ENOMEM, + NULL, NULL, NULL, NULL, NULL); + return 0; + } + + 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? */ + 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; +} int32_t trash_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc) @@ -467,6 +724,7 @@ fini (xlator_t *this) struct xlator_fops fops = { .unlink = trash_unlink, + .rename = trash_rename, }; struct xlator_mops mops = { |