diff options
| author | Amar Tumballi <amar@gluster.com> | 2009-11-30 01:18:09 +0000 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2009-12-01 10:02:52 -0800 | 
| commit | 056e3e7a56a24291c6f07b9ef572ee8c8ff7c700 (patch) | |
| tree | cf395d9d7a1e10f928559cca29ea5523e6535e71 | |
| parent | 936001b147a3adcf9731d02e8f2fb62e5e50caf4 (diff) | |
trash_unlink 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
| -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__ */  | 
