diff options
| author | Amar Tumballi <amar@gluster.com> | 2009-11-30 01:19:10 +0000 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2009-12-01 10:02:59 -0800 | 
| commit | 4f7886034742709b285499aa0052fdb21e9c42f6 (patch) | |
| tree | db4291db1218adba8daa07544e92374d4a45d273 /xlators/features/trash/src | |
| parent | 7bb52eb192f9541e70bf48a206c2d78b5dbb5cb2 (diff) | |
trash_truncate fop added
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')
| -rw-r--r-- | xlators/features/trash/src/trash.c | 445 | 
1 files changed, 443 insertions, 2 deletions
diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c index ad8d1a7e3fd..2efca78b725 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 = {  | 
