summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xlators/features/trash/src/trash.c445
1 files changed, 443 insertions, 2 deletions
diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c
index ad8d1a7e3..2efca78b7 100644
--- a/xlators/features/trash/src/trash.c
+++ b/xlators/features/trash/src/trash.c
@@ -24,6 +24,18 @@
#include "trash.h"
+
+int32_t
+trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno,
+ struct stat *prebuf, struct stat *postbuf);
+
+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 stat *stbuf, struct stat *preparent,
+ struct stat *postparent);
+
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,
@@ -232,6 +244,16 @@ trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
}
+
+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 *prebuf, struct stat *postbuf)
+{
+ TRASH_STACK_UNWIND (frame, op_ret, op_errno, prebuf, postbuf);
+ 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 stat *stbuf,
@@ -608,6 +630,424 @@ trash_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc)
return 0;
}
+int32_t
+trash_truncate_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno,
+ struct stat *preparent, struct stat *postparent)
+{
+ /* use this Function when a failure occurs, and
+ delete the newly created file. */
+ trash_local_t *local = NULL;
+
+ local = frame->local;
+
+ if (op_ret == -1) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "deleting the newly created file: %s",
+ strerror (op_errno));
+ }
+
+ STACK_WIND (frame, trash_common_unwind_buf_cbk,
+ FIRST_CHILD(this), FIRST_CHILD(this)->fops->truncate,
+ &local->loc, local->fop_offset);
+
+ return 0;
+}
+
+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 stat *stbuf, struct iobref *iobuf)
+{
+ trash_local_t *local = NULL;
+
+ local = frame->local;
+
+ if (op_ret == -1) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "readv 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);
+ goto out;
+ }
+
+ local->fsize = stbuf->st_size;
+ STACK_WIND (frame, trash_truncate_writev_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->writev,
+ local->newfd, vector, count, local->cur_offset, iobuf);
+
+out:
+ return 0;
+
+}
+
+int32_t
+trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno,
+ struct stat *prebuf, struct stat *postbuf)
+{
+ trash_local_t *local = NULL;
+
+ local = frame->local;
+
+ if (op_ret == -1) {
+ /* Let truncate work, but previous copy is not preserved. */
+ gf_log (this->name, GF_LOG_DEBUG,
+ "writev 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);
+ goto out;
+ }
+
+ if (local->cur_offset < local->fsize) {
+ local->cur_offset += GF_BLOCK_READV_SIZE;
+ /* Loop back and Read the contents again. */
+ 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);
+ goto out;
+ }
+
+
+ /* 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);
+
+out:
+ return 0;
+}
+
+
+
+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)
+{
+ trash_local_t *local = NULL;
+
+ local = frame->local;
+
+ if (op_ret == -1) {
+ //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);
+ goto out;
+ }
+
+ local->cur_offset = local->fop_offset;
+
+ 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);
+
+out:
+ return 0;
+}
+
+
+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 stat *buf,
+ struct stat *preparent, struct stat *postparent)
+{
+ 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,};
+
+ local = frame->local;
+
+ if ((op_ret == -1) && (op_errno == ENOENT)) {
+ //Creating the directory structure here.
+ tmp_str = strdup (local->newpath);
+ if (!tmp_str) {
+ gf_log (this->name, GF_LOG_DEBUG, "out of memory");
+ }
+ dir_name = dirname (tmp_str);
+
+ 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_truncate_mkdir_cbk,
+ tmp_path, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->mkdir,
+ &tmp_loc, 0755);
+ free (tmp_str);
+ goto out;
+ }
+
+ if (op_ret == -1) {
+ //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));
+
+ STACK_WIND (frame, trash_common_unwind_buf_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->truncate, &local->loc,
+ local->fop_offset);
+ goto out;
+ }
+
+ flags = O_RDONLY;
+
+ 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:
+ return 0;
+}
+
+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 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 flags = 0;
+ int32_t loop_count = 0;
+ int i = 0;
+ loc_t tmp_loc = {0,};
+
+ local = frame->local;
+ if (!local)
+ return 0;
+
+ loop_count = local->loop_count;
+
+ 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;
+ 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;
+ STACK_WIND_COOKIE (frame, trash_truncate_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) {
+ flags = O_CREAT|O_EXCL|O_WRONLY;
+
+ //Call create again once directory structure is created.
+ STACK_WIND (frame, trash_truncate_create_cbk,
+ FIRST_CHILD(this), FIRST_CHILD(this)->fops->create,
+ &local->newloc, flags, local->loc.inode->st_mode,
+ local->newfd);
+ 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_truncate_mkdir_cbk, tmp_path,
+ this->children->xlator,
+ this->children->xlator->fops->mkdir,
+ &tmp_loc, 0755);
+
+out:
+ free (cookie); /* strdup (dir_name) was sent here :) */
+ free (tmp_str);
+
+ return 0;
+}
+
+
+int32_t
+trash_truncate_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;
+ struct tm *tm = NULL;
+ char timestr[256] = {0,};
+ char loc_newname[PATH_MAX] = {0,};
+ time_t utime = 0;
+ int32_t flags = 0;
+
+ priv = this->private;
+ local = frame->local;
+
+ if (op_ret == -1) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "fstat on the file failed: %s",
+ strerror (op_errno));
+
+ TRASH_STACK_UNWIND (frame, op_ret, op_errno, buf);
+ return 0;
+ }
+
+ if ((buf->st_size == 0) || (buf->st_size > priv->max_trash_file_size)) {
+ // If the file is too big, just unlink it.
+ if (buf->st_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;
+ }
+
+ strcpy (local->newpath, priv->trash_dir);
+ strcat (local->newpath, local->loc.path);
+
+ {
+ utime = time (NULL);
+ tm = localtime (&utime);
+ strftime (timestr, 256, ".%Y-%m-%d-%H%M%S", tm);
+ strcat (local->newpath, timestr);
+ }
+ strcpy (loc_newname,local->loc.name);
+ strcat (loc_newname,timestr);
+
+ local->newloc.name = strdup (loc_newname);
+ local->newloc.path = strdup (local->newpath);
+ local->newloc.inode = inode_new (local->loc.inode->table);
+ local->newloc.ino = local->newloc.inode->ino;
+ local->newfd = fd_create (local->newloc.inode, frame->root->pid);
+
+ flags = O_CREAT|O_EXCL|O_WRONLY;
+
+ STACK_WIND (frame, trash_truncate_create_cbk,
+ FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->create,
+ &local->newloc, flags, local->loc.inode->st_mode,
+ local->newfd);
+
+ return 0;
+}
+
+int32_t
+trash_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc,
+ off_t offset)
+{
+ trash_elim_pattern_t *trav = NULL;
+ trash_private_t *priv = NULL;
+ trash_local_t *local = NULL;
+ 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) || (offset) || (match)) {
+ if (match) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "%s: file not moved to trash as per option "
+ "'eliminate'", loc->path);
+ }
+
+ // Trying to truncate from the trash can dir,
+ // 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);
+ goto out;
+ }
+
+ LOCK_INIT (&frame->lock);
+
+ 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);
+ return 0;
+ }
+
+ loc_copy (&local->loc, loc);
+
+ local->fop_offset = offset;
+
+ frame->local = local;
+
+ STACK_WIND (frame, trash_truncate_stat_cbk,
+ this->children->xlator,
+ this->children->xlator->fops->stat, loc);
+
+out:
+ return 0;
+}
+
/**
* trash_init -
*/
@@ -723,8 +1163,9 @@ fini (xlator_t *this)
}
struct xlator_fops fops = {
- .unlink = trash_unlink,
- .rename = trash_rename,
+ .unlink = trash_unlink,
+ .rename = trash_rename,
+ .truncate = trash_truncate,
};
struct xlator_mops mops = {