diff options
Diffstat (limited to 'xlators/features/trash/src')
| -rw-r--r-- | xlators/features/trash/src/Makefile.am | 2 | ||||
| -rw-r--r-- | xlators/features/trash/src/trash-mem-types.h | 3 | ||||
| -rw-r--r-- | xlators/features/trash/src/trash.c | 2635 | ||||
| -rw-r--r-- | xlators/features/trash/src/trash.h | 36 | 
4 files changed, 1951 insertions, 725 deletions
diff --git a/xlators/features/trash/src/Makefile.am b/xlators/features/trash/src/Makefile.am index 5251eb08256..2000359a6a9 100644 --- a/xlators/features/trash/src/Makefile.am +++ b/xlators/features/trash/src/Makefile.am @@ -1,5 +1,5 @@  xlator_LTLIBRARIES = trash.la -xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/testing/features +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features  trash_la_LDFLAGS = -module -avoid-version  diff --git a/xlators/features/trash/src/trash-mem-types.h b/xlators/features/trash/src/trash-mem-types.h index 0e6ef572fcc..b7cad3ce3a9 100644 --- a/xlators/features/trash/src/trash-mem-types.h +++ b/xlators/features/trash/src/trash-mem-types.h @@ -15,7 +15,8 @@  enum gf_trash_mem_types_ {          gf_trash_mt_trash_private_t = gf_common_mt_end + 1,          gf_trash_mt_char, -        gf_trash_mt_trash_elim_pattern_t, +        gf_trash_mt_uuid, +        gf_trash_mt_trash_elim_path,          gf_trash_mt_end  };  #endif diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c index addeb66a053..4eecaf241c6 100644 --- a/xlators/features/trash/src/trash.c +++ b/xlators/features/trash/src/trash.c @@ -15,82 +15,598 @@  #include "trash.h"  #include "trash-mem-types.h" +#define root_gfid        (uuid_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} +#define trash_gfid       (uuid_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5} +#define internal_op_gfid (uuid_t){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6} +/* Common routines used in this translator */ + +/** + * When a directory/file is created under trash directory, it should have + * the same permission as before. This function will fetch permission from + * the existing directory and returns the same + */ +mode_t +get_permission (char *path) +{ +        mode_t                  mode                    = 0755; +        struct stat             sbuf                    = {0,}; +        struct iatt             ibuf                    = {0,}; +        int                     ret                     = 0; + +        ret = stat (path, &sbuf); +        if (!ret) { +                iatt_from_stat (&ibuf, &sbuf); +                mode = st_mode_from_ia (ibuf.ia_prot, ibuf.ia_type); +        } else +                gf_log ("trash", GF_LOG_DEBUG, "stat on %s failed" +                                " using default", path); +        return mode; +} + +/** + * For normalization, trash directory name is stored inside priv structure as + * '/trash_directory/'. As a result the trailing and leading slashes are being + * striped out for additional usage. + */ +int +extract_trash_directory (char *priv_value, const char **trash_directory) +{ +        char                    *tmp                    = NULL; +        int                     ret                     = 0; + +        GF_VALIDATE_OR_GOTO("trash", priv_value, out); + +        tmp = gf_strdup (priv_value + 1); +        if (!tmp) { +                ret = ENOMEM; +                goto out; +        } +        if (tmp[strlen(tmp)-1] == '/') +                tmp[strlen(tmp)-1] = '\0'; +        *trash_directory = gf_strdup (tmp); +        if (!(*trash_directory)) { +                ret = ENOMEM; +                goto out; +        } +out: +        if (tmp) +                GF_FREE (tmp); +        return ret; +} + +/** + * The trash directory path should be append at begining of file path for + * delete or truncate operations. Normal trashing moves the contents to + * trash directory and trashing done by internal operations are moved to + * internal_op directory inside trash. + */ +void +copy_trash_path (const char *priv_value, gf_boolean_t internal, char *path) +{ +        char                    trash_path[PATH_MAX]    = {0,}; + +        strcpy (trash_path, priv_value); +        if (internal) +                strcat (trash_path, "internal_op/"); + +        strcpy (path, trash_path); +} + +/** + * This function performs the reverse operation of copy_trash_path(). It gives + * out a pointer, whose starting value will be the path inside trash directory, + * similar to orginal path. + */ +void +remove_trash_path (const char *path, gf_boolean_t internal, char *rem_path) +{ + +        rem_path =  strchr (path + 1, '/'); +        if (internal) +                rem_path =  strchr (path + 1, '/'); +} + +/** + * Check whether the path includes trash directory or internal op directory + * inside trash. This check is used to make sure that we avoid deletion, + * rename and creation operations from trash directory. + */ +int +check_whether_trash_directory (const char *path, +                               const char *trash_directory_path) +{ +        char                    tmp_path[PATH_MAX]              = {0,}; +        char                    internal_op_path[PATH_MAX]      = {0,}; +        int                     ret                             = 0; + +        if (path[strlen(path)-1] == '/') +                sprintf (tmp_path, "%s", path); +        else +                sprintf (tmp_path, "%s/", path); + +        copy_trash_path (trash_directory_path, _gf_true, internal_op_path); +        ret = strcmp (tmp_path, trash_directory_path) && +              strcmp (tmp_path, internal_op_path); + +        return ret; +} + +/** + * Checks whether the given path reside under the specified eliminate path + */ +int +check_whether_eliminate_path (trash_elim_path *trav, const char *path) +{ +        int                     match                           = 0; + +        while (trav) { +                if (strncmp (path, trav->path, strlen(trav->path)) == 0) { +                        match++; +                        break; +                } +                trav = trav->next; +        } +        return match; +} + +/** + * Stores the eliminate path into internal eliminate path structure + */ +int +store_eliminate_path (char *str, trash_elim_path *eliminate) +{ +        trash_elim_path         *trav                   = NULL; +        char                    *component              = NULL; +        char                    elm_path[PATH_MAX]      = {0,}; +        int                     ret                     = 0; +        char                    *strtokptr              = NULL; + +        component = strtok_r (str, ",", &strtokptr); +        while (component) { +                trav = GF_CALLOC (1, sizeof (*trav), +                                 gf_trash_mt_trash_elim_path); +                if (!trav) { +                        ret = ENOMEM; +                        goto out; +                } +                if (component[0] == '/') +                        sprintf(elm_path, "%s", component); +                else +                        sprintf(elm_path, "/%s", component); + +                if (component[strlen(component)-1] != '/') +                        strcat (elm_path, "/"); + +                trav->path = gf_strdup(elm_path); +                if (!trav->path) { +                                ret = ENOMEM; +                                gf_log ("trash", GF_LOG_DEBUG, "out of memory"); +                                goto out; +                } +                trav->next = eliminate; +                eliminate = trav; +                component = strtok_r (NULL, ",", &strtokptr); +        } +out: +        return ret; +} + +/** + * Appends time stamp to given string + */ +void +append_time_stamp (char *name) +{ +        int                     i; +        char                    timestr[64]            = {0,}; + +        gf_time_fmt (timestr, sizeof(timestr), time (NULL), +                     gf_timefmt_F_HMS); + +        /* removing white spaces in timestamp */ +        for (i = 0; i < strlen (timestr); i++) { +                if (timestr[i] == ' ') +                        timestr[i] = '_'; +        } +        strcat (name, "_"); +        strcat (name, timestr); +} + +/** + * Wipe the memory used by trash location variable + */ +void +trash_local_wipe (trash_local_t *local) +{ +        GF_VALIDATE_OR_GOTO ("trash", local, out); + +        loc_wipe (&local->loc); +        loc_wipe (&local->newloc); + +        if (local->fd) +                fd_unref (local->fd); +        if (local->newfd) +                fd_unref (local->newfd); + +        mem_put (local); +out: +        return; +} + +/** + * Wipe the memory used by eliminate path through a + * recursive call + */ +void +wipe_eliminate_path (trash_elim_path *trav) +{ +        if (trav) { +                wipe_eliminate_path (trav->next); +                GF_FREE (trav->path); +                GF_FREE (trav); +        } +} +  int32_t  trash_ftruncate_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 iatt *stbuf, struct iobref *iobuf); +                           struct iatt *stbuf, struct iobref *iobuf, +                           dict_t *xdata);  int32_t  trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                             int32_t op_ret, int32_t op_errno, -                           struct iatt *prebuf, struct iatt *postbuf); +                           struct iatt *prebuf, struct iatt *postbuf, +                           dict_t *xdata);  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 iatt *stbuf, struct iatt *preparent, -                          struct iatt *postparent); +                          struct iatt *postparent, dict_t *xdata); + +int32_t +trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                           int32_t op_ret, int32_t op_errno, inode_t *inode, +                           struct iatt *stbuf, struct iatt *preparent, +                           struct iatt *postparent, dict_t *xdata);  int32_t  trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                           int32_t op_ret, int32_t op_errno, struct iatt *buf,                           struct iatt *preoldparent, struct iatt *postoldparent, -                         struct iatt *prenewparent, struct iatt *postnewparent); +                         struct iatt *prenewparent, struct iatt *postnewparent, +                         dict_t *xdata); -void -trash_local_wipe (trash_local_t *local) +/** + * This getxattr calls returns existing trash directory path in + * the dictionary + */ +int32_t +trash_notify_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                      int32_t op_ret, int32_t op_errno, dict_t *dict, +                      dict_t *xdata)  { -        if (!local) +        data_t                 *data                  = NULL; +        trash_private_t        *priv                  = NULL; +        int ret                                       = 0; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        data = dict_get (dict, GET_ANCESTRY_PATH_KEY); +        if (!data) { +                gf_log (this->name, GF_LOG_DEBUG, +                                "oldtrash-directory doesnot exists"); +                priv->oldtrash_dir = gf_strdup (priv->newtrash_dir); +                if (!priv->oldtrash_dir) { +                        gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } +        } else { +                priv->oldtrash_dir = gf_strdup (data->data); +                if (!priv->oldtrash_dir) { +                        gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                         ret = ENOMEM; +                         goto out; +                } +                gf_log (this->name, GF_LOG_DEBUG, "old trash directory" +                                                  " path is %s", data->data); +        } + +out: +          return ret; +} + +/** + * This is a nameless look up for old trash directory + * The lookup is based on gfid, because trash directory + * has fixed gfid. + */ +int32_t +trash_notify_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                         int32_t op_ret, int32_t op_errno, inode_t *inode, +                         struct iatt *buf, dict_t *xdata, +                         struct iatt *postparent) +{ +        trash_private_t         *priv                  = NULL; +        loc_t                   loc                    = {0,}; +        int                     ret                    = 0; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        if (op_ret == 0) { + +                gf_log (this->name, GF_LOG_DEBUG, "inode found with gfid %s", +                                   uuid_utoa(buf->ia_gfid)); + +                uuid_copy (loc.gfid,  trash_gfid); + +                /* Find trash inode using available information */ +                priv->trash_inode = inode_link (inode, NULL, NULL, buf); + +                loc.inode = inode_ref (priv->trash_inode); + +                /*Used to find path of old trash directory*/ +                STACK_WIND (frame, trash_notify_getxattr_cbk, FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->getxattr, &loc, +                            GET_ANCESTRY_PATH_KEY, xdata); +        } + +        /* If there is no old trash directory we set its value to new one, +         * which is the valid condition for trash directory creation +         */ +        else { +                priv->oldtrash_dir = gf_strdup (priv->newtrash_dir); +                if (!priv->oldtrash_dir) { +                        gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                        goto out; +                } +        } + +out: +        loc_wipe (&loc); +        return ret; +} + +int32_t +trash_internal_op_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                        int32_t op_ret, int32_t op_errno, inode_t *inode, +                        struct iatt *buf, struct iatt *preparent, +                        struct iatt *postparent, dict_t *xdata) +{ +        if (op_ret != 0) +                gf_log (this->name, GF_LOG_ERROR, "mkdir failed for " +                        "internal op directory : %s", strerror (op_errno)); +        return op_ret; +} + +/** + * This is the call back of mkdir fop initated using STACK_WIND in + * notify function which is used to create trash directory in the brick + * when a volume starts.The frame of the mkdir must destroyed from + * this function itself since it was created by trash xlator + */ +int32_t +trash_notify_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                        int32_t op_ret, int32_t op_errno, inode_t *inode, +                        struct iatt *buf, struct iatt *preparent, +                        struct iatt *postparent, dict_t *xdata) +{ +        uuid_t                *gfid_ptr                         = NULL; +        loc_t                 loc                               = {0, }; +        int                   ret                               = 0; +        dict_t                *dict                             = NULL; +        char                  internal_op_path[PATH_MAX]        = {0,}; +        trash_private_t       *priv       = NULL; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        dict = dict_new (); +        if (!dict) { +                ret = -1;                  goto out; +        } +        if ((op_ret == 0) || (op_ret == -1 && op_errno == EEXIST)) { +                gfid_ptr = GF_CALLOC (1, sizeof(uuid_t), +                                           gf_common_mt_uuid_t); +                if (!gfid_ptr) { +                        ret = ENOMEM; +                        goto out; +                } +                uuid_copy (*gfid_ptr, internal_op_gfid); -        loc_wipe (&local->loc); -        loc_wipe (&local->newloc); +                uuid_copy (loc.gfid, internal_op_gfid); +                uuid_copy (loc.pargfid, trash_gfid); +                loc.name = gf_strdup ("internal_op"); -        if (local->fd) -                fd_unref (local->fd); +                if (!loc.name) { +                        gf_log (this->name, GF_LOG_DEBUG, +                                         "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } +                sprintf (internal_op_path, "%s%s", +                                priv->newtrash_dir, loc.name); -        if (local->newfd) -                fd_unref (local->newfd); +                loc.path = gf_strdup (internal_op_path); -        mem_put (local); +                if (!loc.path) { +                        gf_log (this->name, GF_LOG_DEBUG, +                                         "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } + +                loc.inode = inode_new (priv->trash_itable); +                loc.inode->ia_type = IA_IFDIR; +                /* Fixed gfid is set for trash directory with +                 * this function +                 */ +                ret = dict_set_dynptr (dict, "gfid-req", gfid_ptr, +                                       sizeof (uuid_t)); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, +                                 "setting key gfid-req failed"); +                        goto out; +                } + +                /* The mkdir call for creating trash directory */ +                STACK_WIND (frame, trash_internal_op_mkdir_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->mkdir, &loc, 0755, +                            0022, dict); +                /* After creating we must call other notify functions */ +                default_notify (this, GF_EVENT_CHILD_UP, NULL); +        } else { +                gf_log (this->name, GF_LOG_ERROR, "mkdir failed for trash" +                                " directory : %s", strerror (op_errno)); +        } + +        STACK_DESTROY (frame->root);  out: -        return; +        if (ret && gfid_ptr) +                GF_FREE (gfid_ptr); +        if (dict) +                dict_unref (dict); +        return 0; +} + +int32_t +trash_notify_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                    int32_t op_ret, int32_t op_errno, struct iatt *buf, +                    struct iatt *preoldparent, struct iatt *postoldparent, +                    struct iatt *prenewparent, struct iatt *postnewparent, +                    dict_t *xdata) +{ +        if ((op_ret == 0) || (op_ret == -1 && op_errno == EEXIST)) { +                /* After creating we must call other notify functions */ +                default_notify (this, GF_EVENT_CHILD_UP, NULL); +        } else { +                gf_log (this->name, GF_LOG_ERROR, "rename failed: %s", +                        strerror (op_errno)); +        } + +        STACK_DESTROY (frame->root); +        return op_ret; +} + +/** + * This is the call back of rename fop initated using STACK_WIND in + * reconfigure function which is used to rename trash directory in + * the brick when we perform volume set.This frame  must destroyed + * from this function itself since it was created by trash xlator + */ +int32_t +trash_reconf_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                         int32_t op_ret, int32_t op_errno, struct iatt *buf, +                         struct iatt *preoldparent, struct iatt *postoldparent, +                         struct iatt *prenewparent, struct iatt *postnewparent, +                         dict_t *xdata) +{ +        if (op_ret == -1 && op_errno == EEXIST) { + +                gf_log (this->name, GF_LOG_ERROR, "rename failed: %s", +                        strerror (op_errno)); +        } + +        STACK_DESTROY (frame->root); + +        return op_ret;  }  int32_t +trash_common_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                   int32_t op_ret, int32_t op_errno, inode_t *inode, +                   struct iatt *buf, struct iatt *preparent, +                   struct iatt *postparent, dict_t *xdata) +{ +        STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno, inode, +                             buf, preparent, postparent, xdata); +        return 0; +} + +int32_t +trash_common_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                    int32_t op_ret, int32_t op_errno, struct iatt *buf, +                    struct iatt *preoldparent, struct iatt *postoldparent, +                    struct iatt *prenewparent, struct iatt *postnewparent, +                    dict_t *xdata) +{ +        STACK_UNWIND_STRICT (rename, frame, op_ret, op_errno, buf, preoldparent, +                             postoldparent, prenewparent, postnewparent, xdata); +        return 0; +} + +int32_t +trash_common_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                   int32_t op_ret, int32_t op_errno, struct iatt *preparent, +                   struct iatt *postparent, +                   dict_t *xdata) +{ +        STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno, preparent, +                             postparent, xdata); +        return 0; +} + +/** + * move backs from trash translator to unlink call + */ +int32_t  trash_common_unwind_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                           int32_t op_ret, int32_t op_errno, -                         struct iatt *preparent, struct iatt *postparent) +                         struct iatt *preparent, struct iatt *postparent, +                         dict_t *xdata)  { -        TRASH_STACK_UNWIND (unlink, frame, op_ret, op_errno, preparent, postparent); +        TRASH_STACK_UNWIND (unlink, frame, op_ret, op_errno, preparent, +                            postparent, xdata);          return 0;  } +/** + * If the path is not present in the trash directory,it will recursively + * call this call-back and one by one directories will be created from + * the starting + */  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 iatt *stbuf, struct iatt *preparent, -                        struct iatt *postparent) +                        struct iatt *postparent, dict_t *xdata)  { -        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,}; +        trash_local_t       *local              = NULL; +        char                *tmp_str            = NULL; +        char                *tmp_path           = NULL; +        char                *tmp_dirname        = NULL; +        char                *tmp_stat           = NULL; +        char                real_path[PATH_MAX] = {0,}; +        char                *dir_name           = NULL; +        size_t              count               = 0; +        int32_t             loop_count          = 0; +        int                 i                   = 0; +        loc_t               tmp_loc             = {0,}; +        trash_private_t     *priv               = NULL; +        int                 ret                 = 0; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out);          local   = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out); +          tmp_str = gf_strdup (local->newpath);          if (!tmp_str) {                  gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1;                  goto out;          }          loop_count = local->loop_count; +        /* The directory is not present , need to create it */          if ((op_ret == -1) &&  (op_errno == ENOENT)) {                  tmp_dirname = strchr (tmp_str, '/');                  while (tmp_dirname) { @@ -102,31 +618,53 @@ trash_unlink_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                  break;                          tmp_dirname = strchr (tmp_str + count + 1, '/');                  } -                tmp_path = memdup (local->newpath, count); +                tmp_path = gf_memdup (local->newpath, count + 1);                  if (!tmp_path) {                          gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                        ret = ENOMEM;                          goto out;                  } +                tmp_path[count] = '\0'; -                tmp_loc.path = tmp_path; +                loc_copy (&tmp_loc, &local->loc); +                tmp_loc.path = gf_strdup (tmp_path); +                if (!tmp_loc.path) { +                        gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } -                /* TODO:create the directory with proper permissions */ +                /* Stores the the name of directory to be created */ +                tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1); +                if (!tmp_loc.name) { +                        gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } +                strcpy (real_path, priv->brick_path); +                remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +                if (tmp_stat) +                        strcat (real_path, tmp_stat);                  STACK_WIND_COOKIE (frame, trash_unlink_mkdir_cbk, tmp_path, -                                   this->children->xlator, -                                   this->children->xlator->fops->mkdir, -                                   &tmp_loc, 0755, NULL); - +                                   FIRST_CHILD(this), +                                   FIRST_CHILD(this)->fops->mkdir, +                                   &tmp_loc, get_permission(real_path), +                                   0022, xdata); +                loc_wipe (&tmp_loc);                  goto out;          } +        /* Given path is created , comparing to the required path */          if (op_ret == 0) {                  dir_name = dirname (tmp_str); -                if (strcmp((char*)cookie, dir_name) == 0) { +                if (strcmp((char *)cookie, dir_name) == 0) { +                        /* File path exists we can rename it*/ +                        loc_copy (&tmp_loc, &local->loc);                          tmp_loc.path = local->newpath;                          STACK_WIND (frame, trash_unlink_rename_cbk, -                                    this->children->xlator, -                                    this->children->xlator->fops->rename, -                                    &local->loc, &tmp_loc); +                                    FIRST_CHILD(this), +                                    FIRST_CHILD(this)->fops->rename, +                                    &local->loc, &tmp_loc, xdata);                          goto out;                  }          } @@ -136,7 +674,10 @@ trash_unlink_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  loop_count = ++local->loop_count;          }          UNLOCK (&frame->lock); +          tmp_dirname = strchr (tmp_str, '/'); + +        /* Path is not completed , need to create remaining path */          while (tmp_dirname) {                  count = tmp_dirname - tmp_str;                  if (count == 0) @@ -146,492 +687,356 @@ trash_unlink_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                          break;                  tmp_dirname = strchr (tmp_str + count + 1, '/');          } -        tmp_path = memdup (local->newpath, count); +        tmp_path = gf_memdup (local->newpath, count + 1);          if (!tmp_path) {                  gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1; +                goto out; +        } +        tmp_path[count] = '\0'; + +        loc_copy (&tmp_loc, &local->loc); +        tmp_loc.path = gf_strdup (tmp_path); +        if (!tmp_loc.path) { +                gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1; +                goto out; +        } + +        /* Stores the the name of directory to be created */ +        tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1); +        if (!tmp_loc.name) { +                gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1;                  goto out;          } -        tmp_loc.path = tmp_path; + +        strcpy (real_path, priv->brick_path); +        remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +        if (tmp_stat) +                strcat (real_path, tmp_stat);          STACK_WIND_COOKIE (frame, trash_unlink_mkdir_cbk, tmp_path, -                           this->children->xlator, -                           this->children->xlator->fops->mkdir, -                           &tmp_loc, 0755, NULL); +                           FIRST_CHILD(this), +                           FIRST_CHILD(this)->fops->mkdir, &tmp_loc, +                           get_permission(real_path), 0022, xdata);  out: -        GF_FREE (cookie); -        GF_FREE (tmp_str); - -        return 0; +        if (tmp_path) +                GF_FREE (tmp_path); +        if (tmp_str) +                GF_FREE (tmp_str); +        return ret;  } -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 iatt *stbuf, struct iatt *preparent, -                        struct iatt *postparent); - +/** + * The name of unlinking file should be renamed as starting + * from trash directory as mentioned in the mount point + */  int32_t  trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                           int32_t op_ret, int32_t op_errno, struct iatt *buf,                           struct iatt *preoldparent, struct iatt *postoldparent, -                         struct iatt *prenewparent, struct iatt *postnewparent) +                         struct iatt *prenewparent, struct iatt *postnewparent, +                         dict_t *xdata)  { -        trash_local_t   *local      = NULL; -        char            *tmp_str    = NULL; -        char            *dir_name   = NULL; -        char            *tmp_cookie = NULL; -        loc_t            tmp_loc    = {0,}; +        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,}; +        char               *tmp_stat           = NULL; +        char               real_path[PATH_MAX] = {0,}; +        int                ret                 = 0; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out);          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if ((op_ret == -1) && (op_errno == ENOENT)) { +                /* the file path doesnot exists we want to create path +                 * for the file +                 */                  tmp_str = gf_strdup (local->newpath);                  if (!tmp_str) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out;                  } -                dir_name = dirname (tmp_str); +                dir_name = dirname (tmp_str); /* stores directory name */ -                tmp_loc.path = dir_name; +                loc_copy (&tmp_loc, &local->loc); +                tmp_loc.path = gf_strdup (dir_name); +                if (!tmp_loc.path) { +                        gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                }                  tmp_cookie = gf_strdup (dir_name);                  if (!tmp_cookie) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out;                  } -                /* TODO: create the directory with proper permissions */ +                strcpy (real_path, priv->brick_path); +                remove_trash_path (tmp_str, (frame->root->pid < 0), tmp_stat); +                if (tmp_stat) +                        strcat (real_path, tmp_stat); +                /* 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, NULL); - -                GF_FREE (tmp_str); - -                return 0; +                                   &tmp_loc, get_permission(real_path), +                                   0022, xdata); +                loc_wipe (&tmp_loc); +                goto out;          }          if ((op_ret == -1) && (op_errno == ENOTDIR)) { - +                /* if entry is already present in trash directory, +                 * new one is not copied*/                  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); +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->unlink, +                            &local->loc, 0, xdata); -                return 0; +                goto out;          }          if ((op_ret == -1) && (op_errno == EISDIR)) { + +                /* if entry is directory,we remove directly */                  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; +                            FIRST_CHILD(this)->fops->unlink, +                            &local->loc, 0, xdata); +                goto out;          }          /* All other cases, unlink should return success */          TRASH_STACK_UNWIND (unlink, frame, 0, op_errno, &local->preparent, -                            &local->postparent); +                            &local->postparent, xdata); +out: +        if (tmp_str) +                GF_FREE (tmp_str); +        if (tmp_cookie) +                GF_FREE (tmp_cookie); -        return 0; +        return ret;  } - - +/** + * move backs from trash translator to truncate call + */  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 iatt *prebuf, struct iatt *postbuf) +                             struct iatt *prebuf, struct iatt *postbuf, +                             dict_t *xdata)  { -        TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, prebuf, postbuf); +        TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, prebuf, +                            postbuf, xdata);          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 iatt *stbuf, -                         struct iatt *preoldparent, struct iatt *postoldparent, -                         struct iatt *prenewparent, struct iatt *postnewparent) -{ -        TRASH_STACK_UNWIND (rename, 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 iatt *buf) +                       int32_t op_ret, int32_t op_errno, struct iatt *buf, +                       dict_t *xdata)  { -        trash_private_t *priv    = NULL; -        trash_local_t   *local   = NULL; -        loc_t            new_loc = {0,}; +        trash_private_t     *priv        = NULL; +        trash_local_t       *local       = NULL; +        loc_t               new_loc      = {0,}; +        int                 ret          = 0;          priv  = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); +          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out); -        if (-1 == op_ret) { +        if (op_ret == -1) {                  gf_log (this->name, GF_LOG_DEBUG, "%s: %s",                          local->loc.path, strerror (op_errno)); -                goto fail; +                TRASH_STACK_UNWIND (unlink, frame, op_ret, op_errno, buf, +                            NULL, xdata); +                ret = -1; +                goto out;          } -        if ((buf->ia_size == 0) || -            (buf->ia_size > priv->max_trash_file_size)) { -                /* if the file is too big or zero, just unlink it */ +        /* if the file is too big  just unlink it */ -                if (buf->ia_size > priv->max_trash_file_size) { -                        gf_log (this->name, GF_LOG_DEBUG, +        if (buf->ia_size > (priv->max_trash_file_size)) { +                gf_log (this->name, GF_LOG_DEBUG,                                  "%s: file size too big (%"PRId64") to "                                  "move into trash directory",                                  local->loc.path, buf->ia_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 (unlink, frame, op_ret, op_errno, buf, -                            NULL); - -        return 0; - -} - -int32_t -trash_rename_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, -                         int32_t op_ret, int32_t op_errno, struct iatt *buf, -                         struct iatt *preoldparent, struct iatt *postoldparent, -                         struct iatt *prenewparent, struct iatt *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  = gf_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 = gf_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, NULL); - -                GF_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 iatt *stbuf, struct iatt *preparent, -                        struct iatt *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 = gf_strdup (local->newpath); -        if (!tmp_str) { -                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->unlink, &local->loc, +                            0, xdata);                  goto out;          } -        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 = memdup (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, NULL); -                } - +        /* Copies new path for renaming */ +        loc_copy (&new_loc, &local->loc); +        new_loc.path = gf_strdup (local->newpath); +        if (!new_loc.path) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM;                  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); -        } +        STACK_WIND (frame, trash_unlink_rename_cbk, +                    FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->rename, +                    &local->loc, &new_loc, xdata);  out: -        GF_FREE (cookie); /* strdup (dir_name) was sent here :) */ -        GF_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 iatt *buf, dict_t *xattr, -                         struct iatt *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->ia_size == 0) || -            (buf->ia_size > priv->max_trash_file_size)) { -                /* if the file is too big or zero, just unlink it */ - -                if (buf->ia_size > priv->max_trash_file_size) { -                        gf_log (this->name, GF_LOG_DEBUG, -                                "%s: file size too big (%"PRId64") to " -                                "move into trash directory", -                                local->newloc.path, buf->ia_size); -                } - -                STACK_WIND (frame, trash_common_rename_cbk, -                            this->children->xlator, -                            this->children->xlator->fops->rename, -                            &local->loc, &local->newloc); -                return 0; -        } +        loc_wipe (&new_loc); -        tmp_loc.path = local->newpath; +        return ret; -        STACK_WIND (frame, trash_rename_rename_cbk, -                    this->children->xlator, -                    this->children->xlator->fops->rename, -                    &local->newloc, &tmp_loc); - -        return 0;  } - +/** + * Unlink is called internally by rm system call and also + * by internal operations of gluster such as self-heal + */  int32_t -trash_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, -              loc_t *newloc) +trash_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags, +              dict_t *xdata)  { -        trash_elim_pattern_t  *trav  = NULL; -        trash_private_t *priv = NULL; -        trash_local_t   *local = NULL; -        char             timestr[64] = {0,}; -        int32_t          match = 0; +        trash_private_t         *priv           = NULL; +        trash_local_t           *local          = NULL;/* files inside trash */ +        int32_t                 match           = 0; +        char                    *pathbuf        = NULL; +        int                     ret             = 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); +        GF_VALIDATE_OR_GOTO ("trash", priv, out); -                return 0; -        } - -        local = mem_get0 (this->local_pool); -        if (!local) { -                gf_log (this->name, GF_LOG_ERROR, "out of memory"); -                TRASH_STACK_UNWIND (rename, frame, -1, ENOMEM, -                                    NULL, NULL, NULL, NULL, NULL); -                return 0; +        /* If trash is not active or not enabled through cli, then +         *  we bypass and wind back +         */ +        if (!priv->state) { +                STACK_WIND (frame, trash_common_unwind_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->unlink, loc, 0, +                            xdata); +                goto out;          } -        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? */ -                gf_time_ftm (timestr, sizeof timestr, time (NULL), -                             gf_timefmt_F_HMS); -                strcat (local->newpath, timestr); +        /* The files removed by gluster internal operations such as self-heal, +         * should moved to trash directory , but files by client should not +         * moved +         */ +        if ((frame->root->pid < 0) && !priv->internal) { +                STACK_WIND (frame, trash_common_unwind_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->unlink, loc, 0, +                            xdata); +                goto out;          } +        /* loc need some gfid which will be present in inode */ +        uuid_copy (loc->gfid, loc->inode->gfid); -        /* 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) -{ -        trash_elim_pattern_t  *trav  = NULL; -        trash_private_t *priv = NULL; -        trash_local_t   *local = NULL; -        char             timestr[64] = {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; -                } +        /* Checking for valid location */ +        if (uuid_is_null (loc->gfid) && uuid_is_null (loc->inode->gfid)) { +                gf_log (this->name, GF_LOG_DEBUG, "Bad address"); +                STACK_WIND (frame, trash_common_unwind_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->unlink, loc, 0, +                            xdata); +                ret = EFAULT; +                goto out;          } -        if ((strncmp (loc->path, priv->trash_dir, -                      strlen (priv->trash_dir)) == 0) || (match)) { +        /* This will be more accurate */ +        inode_path (loc->inode, NULL, &pathbuf); +        /* Check whether the file is present under eliminate paths or +         * inside trash directory. In both cases we don't need to move the +         * file to trash directory. Instead delete it permanently +         */ +        match = check_whether_eliminate_path (priv->eliminate, pathbuf); +        if ((strncmp (pathbuf, priv->newtrash_dir, +                      strlen (priv->newtrash_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 */ -                        ; +                                "%s is a file comes under an eliminate path, " +                                "so it is not moved to trash", loc->name);                  } +                /* Trying to unlink from the trash-dir. So do the +                 * actual unlink without moving to trash-dir. +                 */                  STACK_WIND (frame, trash_common_unwind_cbk, -                            this->children->xlator, -                            this->children->xlator->fops->unlink, loc); -                return 0; +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->unlink, loc, 0, +                            xdata); +                goto out;          }          local = mem_get0 (this->local_pool);          if (!local) {                  gf_log (this->name, GF_LOG_DEBUG, "out of memory"); -                TRASH_STACK_UNWIND (unlink, frame, -1, ENOMEM, NULL, NULL); -                return 0; +                TRASH_STACK_UNWIND (unlink, frame, -1, ENOMEM, NULL, NULL, +                                    xdata); +                ret = ENOMEM; +                goto out;          }          frame->local = local;          loc_copy (&local->loc, loc); -        strcpy (local->origpath, loc->path); -        strcpy (local->newpath, priv->trash_dir); -        strcat (local->newpath, loc->path); +        /* rename new location of file as starting from trash directory */ +        strcpy (local->origpath, pathbuf); +        copy_trash_path (priv->newtrash_dir, (frame->root->pid < 0), +                                                        local->newpath); +        strcat (local->newpath, pathbuf); -        { -                /* append timestamp to file name */ -                /* TODO: can we make it optional? */ -                gf_time_fmt (timestr, sizeof timestr, time (NULL), -                             gf_timefmt_F_HMS); -                strcat (local->newpath, timestr); -        } +        /* append timestamp to file name so that we can avoid +         * name collisions inside trash +         */ +        append_time_stamp (local->newpath);          LOCK_INIT (&frame->lock);          STACK_WIND (frame, trash_unlink_stat_cbk, -                    this->children->xlator, -                    this->children->xlator->fops->stat, loc); - -        return 0; +                    FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->stat, loc, xdata); +out: +        return ret;  } +/** + * Use this when a failure occurs, and delete the newly created file + */  int32_t  trash_truncate_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                             int32_t op_ret, int32_t op_errno, -                           struct iatt *preparent, struct iatt *postparent) +                           struct iatt *preparent, struct iatt *postparent, +                           dict_t *xdata)  { -        /* use this Function when a failure occurs, and -           delete the newly created file. */ -        trash_local_t *local = NULL; +        trash_local_t     *local  = NULL;          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if (op_ret == -1) {                  gf_log (this->name, GF_LOG_DEBUG, @@ -641,20 +1046,26 @@ trash_truncate_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          STACK_WIND (frame, trash_common_unwind_buf_cbk,                      FIRST_CHILD(this), FIRST_CHILD(this)->fops->truncate, -                    &local->loc, local->fop_offset); - +                    &local->loc, local->fop_offset, xdata); +out:          return 0;  } +/** + * Read from source file + */  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 iatt *stbuf, struct iobref *iobuf) +                          struct iatt *stbuf, struct iobref *iobuf, +                          dict_t *xdata)  { -        trash_local_t *local = NULL; + +        trash_local_t    *local  = NULL;          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if (op_ret == -1) {                  gf_log (this->name, GF_LOG_DEBUG, @@ -663,28 +1074,34 @@ trash_truncate_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  STACK_WIND (frame, trash_truncate_unlink_cbk,                              FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink, -                            &local->newloc); +                            &local->newloc, 0, xdata);                  goto out;          }          local->fsize = stbuf->ia_size;          STACK_WIND (frame, trash_truncate_writev_cbk, FIRST_CHILD(this),                      FIRST_CHILD(this)->fops->writev, -                    local->newfd, vector, count, local->cur_offset, 0, iobuf); +                    local->newfd, vector, count, local->cur_offset, 0, iobuf, +                    xdata);  out:          return 0;  } +/** + * Write to file created in trash directory + */  int32_t  trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                             int32_t op_ret, int32_t op_errno, -                           struct iatt *prebuf, struct iatt *postbuf) +                           struct iatt *prebuf, struct iatt *postbuf, +                           dict_t *xdata)  { -        trash_local_t *local = NULL; +        trash_local_t    *local  = NULL;          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if (op_ret == -1) {                  /* Let truncate work, but previous copy is not preserved. */ @@ -693,7 +1110,8 @@ trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                          strerror (op_errno));                  STACK_WIND (frame, trash_truncate_unlink_cbk, FIRST_CHILD(this), -                            FIRST_CHILD(this)->fops->unlink, &local->newloc); +                            FIRST_CHILD(this)->fops->unlink, &local->newloc, 0, +                            xdata);                  goto out;          } @@ -703,7 +1121,7 @@ trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  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, 0); +                            local->cur_offset, 0, xdata);                  goto out;          } @@ -711,86 +1129,115 @@ trash_truncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          /* 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); +                    local->fop_offset, xdata);  out:          return 0;  } - - +/** + * The source file is opened for reading and writing + */  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) +                         int32_t op_ret, int32_t op_errno, fd_t *fd, +                         dict_t *xdata)  { -        trash_local_t *local = NULL; +        trash_local_t    *local  = NULL;          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if (op_ret == -1) { -                //Let truncate work, but previous copy is not preserved. +                /* 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); +                            &local->newloc, 0, xdata);                  goto out;          } -        local->cur_offset = local->fop_offset; +        local->cur_offset = 0;          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, 0); +                    local->fd, (size_t)GF_BLOCK_READV_SIZE, local->cur_offset, +                    0, xdata);  out:          return 0;  } - +/** + * Creates new file descriptor for read and write operations, + * if the path is present in trash directory + */  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 iatt *buf, -                           struct iatt *preparent, struct iatt *postparent) +                           struct iatt *preparent, struct iatt *postparent, +                           dict_t *xdata)  { -        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,}; +        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,}; +        char                 *tmp_stat               = NULL; +        char                 real_path[PATH_MAX]     = {0,}; +        trash_private_t     *priv               = NULL; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out);          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out); + +        /* Checks whether path is present in trash directory or not */          if ((op_ret == -1) && (op_errno == ENOENT)) { -                //Creating the directory structure here. +                /* Creating the directory structure here. */                  tmp_str = gf_strdup (local->newpath);                  if (!tmp_str) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out;                  }                  dir_name = dirname (tmp_str);                  tmp_path = gf_strdup (dir_name);                  if (!tmp_path) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out;                  } -                tmp_loc.path = tmp_path; - -                /* TODO: create the directory with proper permissions */ +                loc_copy (&tmp_loc, &local->newloc); +                tmp_loc.path = gf_strdup (tmp_path); +                if (!tmp_loc.path) { +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out; +                } +                strcpy (real_path, priv->brick_path); +                remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +                if (tmp_stat) +                        strcat (real_path, tmp_stat); +                /* 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, NULL); -                GF_FREE (tmp_str); +                                   &tmp_loc, get_permission(real_path), +                                   0022, xdata); +                loc_wipe (&tmp_loc);                  goto out;          }          if (op_ret == -1) { -                //Let truncate work, but previous copy is not preserved. -                //Deleting the newly created copy. +                /* 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)); @@ -798,47 +1245,66 @@ trash_truncate_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  STACK_WIND (frame, trash_common_unwind_buf_cbk,                              FIRST_CHILD(this),                              FIRST_CHILD(this)->fops->truncate, &local->loc, -                            local->fop_offset); +                            local->fop_offset, xdata);                  goto out;          }          flags = O_RDONLY; +        /* fd which represents source file for reading and writing from it */ +          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: +        if (tmp_str) +                GF_FREE (tmp_str); +        if (tmp_path) +                GF_FREE (tmp_path); +          return 0;  } +/** + * If the path is not present in the trash directory,it will recursively call + * this call-back and one by one directories will be created from the + * beginning + */  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 iatt *stbuf, struct iatt *preparent, -                          struct iatt *postparent) +                          struct iatt *postparent, dict_t *xdata)  { -        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,}; +        trash_local_t        *local              = NULL; +        trash_private_t      *priv               = NULL; +        char                 *tmp_str            = NULL; +        char                 *tmp_path           = NULL; +        char                 *tmp_dirname        = NULL; +        char                 *dir_name           = NULL; +        char                 *tmp_stat           = NULL; +        char                 real_path[PATH_MAX] = {0,}; +        size_t               count               = 0; +        int32_t              flags               = 0; +        int32_t              loop_count          = 0; +        int                  i                   = 0; +        loc_t                tmp_loc             = {0,}; +        int                  ret                 = 0; -        local   = frame->local; -        if (!local) -                goto out; +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          loop_count = local->loop_count;          tmp_str = gf_strdup (local->newpath);          if (!tmp_str) {                  gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM;                  goto out;          } @@ -853,16 +1319,39 @@ trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                  break;                          tmp_dirname = strchr (tmp_str + count + 1, '/');                  } -                tmp_path = memdup (local->newpath, count); +                tmp_path = gf_memdup (local->newpath, count + 1);                  if (!tmp_path) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out;                  } -                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, NULL); +                tmp_path[count] = '\0'; +                loc_copy (&tmp_loc, &local->newloc); +                tmp_loc.path = gf_strdup (tmp_path); +                if (!tmp_loc.path) { +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } + +                /* Stores the the name of directory to be created */ +                tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1); +                if (!tmp_loc.name) { +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } +                strcpy (real_path, priv->brick_path); +                remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +                if (tmp_stat) +                        strcat (real_path, tmp_stat); +                STACK_WIND_COOKIE (frame, trash_truncate_mkdir_cbk, +                                   tmp_path, FIRST_CHILD(this), +                                   FIRST_CHILD(this)->fops->mkdir, +                                   &tmp_loc, get_permission(real_path), +                                   0022, xdata); +                loc_wipe (&tmp_loc);                  goto out;          } @@ -870,14 +1359,16 @@ trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  dir_name = dirname (tmp_str);                  if (strcmp ((char*)cookie, dir_name) == 0) {                          flags = O_CREAT|O_EXCL|O_WRONLY; -                        ia_prot_t prot = {0, }; - -                        //Call create again once directory structure is created. +                        strcpy (real_path, priv->brick_path); +                        strcat (real_path, local->origpath); +                        /* Call create again once directory structure +                           is created. */                          STACK_WIND (frame, trash_truncate_create_cbk, -                                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->create, +                                    FIRST_CHILD(this), +                                    FIRST_CHILD(this)->fops->create,                                      &local->newloc, flags, -                                    st_mode_from_ia (prot, local->loc.inode->ia_type), -                                    local->newfd, NULL); +                                    get_permission (real_path), +                                    0022, local->newfd, xdata);                          goto out;                  }          } @@ -893,82 +1384,147 @@ trash_truncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  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 = memdup (local->newpath, count); +        tmp_path = gf_memdup (local->newpath, count + 1);          if (!tmp_path) {                  gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM; +                goto out;          } -        tmp_loc.path = tmp_path; +        tmp_path[count] = '\0'; + +        loc_copy (&tmp_loc, &local->newloc); +        tmp_loc.path = gf_strdup (tmp_path); +        if (!tmp_loc.path) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM; +                goto out; +        } + +        /* Stores the the name of directory to be created */ +        tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1); +        if (!tmp_loc.name) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                goto out; +        } + +        strcpy (real_path, priv->brick_path); +        remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +        if (tmp_stat) +                strcat (real_path, tmp_stat);          STACK_WIND_COOKIE (frame, trash_truncate_mkdir_cbk, tmp_path, -                           this->children->xlator, -                           this->children->xlator->fops->mkdir, -                           &tmp_loc, 0755, NULL); +                           FIRST_CHILD(this), +                           FIRST_CHILD(this)->fops->mkdir, &tmp_loc, +                           get_permission(real_path), +                           0022, xdata);  out: -        GF_FREE (cookie); /* strdup (dir_name) was sent here :) */ -        GF_FREE (tmp_str); +        if (tmp_str) +                GF_FREE (tmp_str); +        if (tmp_path) +                GF_FREE (tmp_path); -        return 0; +        return ret;  }  int32_t  trash_truncate_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, -                         int32_t op_ret, int32_t op_errno, struct iatt *buf) +                         int32_t op_ret, int32_t op_errno, struct iatt *buf, +                         dict_t *xdata)  { -        trash_private_t     *priv  = NULL; -        trash_local_t       *local = NULL; -        char                 timestr[64] = {0,}; -        char                 loc_newname[PATH_MAX] = {0,}; -        int32_t              flags = 0; +        trash_private_t       *priv                   = NULL; +        trash_local_t         *local                  = NULL; +        char                  loc_newname[PATH_MAX]   = {0,}; +        int32_t               flags                   = 0; +        dentry_t              *dir_entry              = NULL; +        inode_table_t         *table                  = NULL; +        int                   ret                     = 0;          priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); +          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out); + +        table = local->loc.inode->table; + +        pthread_mutex_lock (&table->lock); +        { +                dir_entry = __dentry_search_arbit (local->loc.inode); +        } +        pthread_mutex_unlock (&table->lock);          if (op_ret == -1) {                  gf_log (this->name, GF_LOG_DEBUG,                          "fstat on the file failed: %s",                          strerror (op_errno)); -                TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, buf, NULL); -                return 0; +                TRASH_STACK_UNWIND (truncate, frame, op_ret, op_errno, buf, +                                NULL, xdata); +                goto out;          } - -        if ((buf->ia_size == 0) || (buf->ia_size > priv->max_trash_file_size)) { -                // If the file is too big, just unlink it. -                if (buf->ia_size > priv->max_trash_file_size) -                        gf_log (this->name, GF_LOG_DEBUG, "%s: file too big, " +        /* If the file is too big, just unlink it. */ +        if (buf->ia_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; +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->truncate, +                            &local->loc, local->fop_offset, xdata); +                goto out;          } -        strcpy (local->newpath, priv->trash_dir); +        /* Retrives the name of file from path */ +        local->loc.name = gf_strdup (strrchr (local->loc.path, '/')); +        if (!local->loc.name) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                goto out; +        } + +        /* Stores new path for source file */ +        copy_trash_path (priv->newtrash_dir, (frame->root->pid < 0), +                                                        local->newpath);          strcat (local->newpath, local->loc.path); -        { -                gf_time_fmt (timestr, sizeof timestr, time (NULL), -                             gf_timefmt_F_HMS); -                strcat (local->newpath, timestr); -        } -        strcpy (loc_newname,local->loc.name); -        strcat (loc_newname,timestr); +        /* append timestamp to file name so that we can avoid +           name collisions inside trash */ +        append_time_stamp (local->newpath); +        strcpy (loc_newname, local->loc.name); +        append_time_stamp (loc_newname); +        /* local->newloc represents old file(file inside trash), +           where as local->loc represents truncated file. We need +           to create new inode and fd for new file*/          local->newloc.name = gf_strdup (loc_newname); +        if (!local->newloc.name) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM; +                goto out; +        }          local->newloc.path = gf_strdup (local->newpath); +        if (!local->newloc.path) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM; +                goto out; +        }          local->newloc.inode = inode_new (local->loc.inode->table);          local->newfd = fd_create (local->newloc.inode, frame->root->pid); +        /* Creating vaild parent and pargfids for both files */ + +        local->loc.parent = inode_ref (dir_entry->parent); +        uuid_copy (local->loc.pargfid, dir_entry->parent->gfid); + +        local->newloc.parent = inode_ref (dir_entry->parent); +        uuid_copy (local->newloc.pargfid, dir_entry->parent->gfid); +          flags = O_CREAT|O_EXCL|O_WRONLY;          STACK_WIND (frame, trash_truncate_create_cbk, @@ -976,45 +1532,73 @@ trash_truncate_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                      FIRST_CHILD(this)->fops->create,                      &local->newloc, flags,                      st_mode_from_ia (buf->ia_prot, local->loc.inode->ia_type), -                    local->newfd, NULL); +                    0022, local->newfd, xdata); -        return 0; +out: +        return ret;  } +/** + * Truncate can be explicitly called or implicitly by some other applications + * like text editors etc.. + */  int32_t  trash_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, -                off_t offset) +                off_t offset, dict_t *xdata)  { -        trash_elim_pattern_t *trav = NULL; -        trash_private_t      *priv = NULL; -        trash_local_t        *local = NULL; -        int32_t               match = 0; +        trash_private_t        *priv           = NULL; +        trash_local_t          *local          = NULL; +        int32_t                match           = 0; +        char                   *pathbuf        = NULL; +        int                    ret             = 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; -                } +        GF_VALIDATE_OR_GOTO ("trash", priv, out); +        /* If trash is not active or not enabled through cli, then +         * we bypass and wind back +         */ +        if (!priv->state) { +                STACK_WIND (frame, trash_common_unwind_buf_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->truncate, loc, +                            offset, xdata); +                goto out; +        } + +        /* The files removed by gluster operations such as self-heal, +           should moved to trash directory, but files by client should +           not moved */ +        if ((frame->root->pid < 0) && !priv->internal) { +                STACK_WIND (frame, trash_common_unwind_buf_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->truncate, loc, +                            offset, xdata); +                goto out;          } +        /* This will be more accurate */ +        inode_path(loc->inode, NULL, &pathbuf); -        if ((strncmp (loc->path, priv->trash_dir, -                      strlen (priv->trash_dir)) == 0) || (offset) || (match)) { +        /* Checks whether file is in trash directory or eliminate path. +         * In all such cases it does not move to trash directory, +         * truncate will be performed +         */ +        match = check_whether_eliminate_path (priv->eliminate, pathbuf); + +        if ((strncmp (pathbuf, priv->newtrash_dir, +                      strlen (priv->newtrash_dir)) == 0) || (match)) {                  if (match) {                          gf_log (this->name, GF_LOG_DEBUG,                                  "%s: file not moved to trash as per option " -                                "'eliminate'", loc->path); +                                "'eliminate path'", loc->path);                  } -                // Trying to truncate from the trash can dir, -                //   do the actual truncate without moving to trash-dir. +                /* Trying to truncate from the trash-dir. So 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); +                            FIRST_CHILD(this)->fops->truncate, loc, offset, +                            xdata);                  goto out;          } @@ -1023,60 +1607,66 @@ trash_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc,          local = mem_get0 (this->local_pool);          if (!local) {                  gf_log (this->name, GF_LOG_DEBUG, "out of memory"); -                TRASH_STACK_UNWIND (truncate, frame, -1, ENOMEM, NULL, NULL); -                return 0; +                TRASH_STACK_UNWIND (truncate, frame, -1, ENOMEM, NULL, NULL, +                                    xdata); +                ret = ENOMEM; +                goto out;          }          loc_copy (&local->loc, loc); - +        local->loc.path = pathbuf;          local->fop_offset = offset;          frame->local = local;          STACK_WIND (frame, trash_truncate_stat_cbk, -                    this->children->xlator, -                    this->children->xlator->fops->stat, loc); +                    FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->stat, loc, +                    xdata);  out: -        return 0; +        return ret;  }  int32_t  trash_ftruncate_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                              int32_t op_ret, int32_t op_errno, -                            struct iatt *preparent, struct iatt *postparent) +                            struct iatt *preparent, struct iatt *postparent, +                            dict_t *xdata)  { -        trash_local_t *local = NULL; +        trash_local_t    *local  = NULL;          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if (op_ret == -1) {                  gf_log (this->name, GF_LOG_DEBUG,                          "%s: failed to unlink new file: %s",                          local->newloc.path, strerror(op_errno)); -          }          STACK_WIND (frame, trash_common_unwind_buf_cbk,                      FIRST_CHILD(this), FIRST_CHILD(this)->fops->ftruncate, -                    local->fd, local->fop_offset); - +                    local->fd, local->fop_offset, xdata); +out:          return 0;  }  int32_t  trash_ftruncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                              int32_t op_ret, int32_t op_errno, -                            struct iatt *prebuf, struct iatt *postbuf) +                            struct iatt *prebuf, struct iatt *postbuf, +                            dict_t *xdata)  { -        trash_local_t *local = NULL; +        trash_local_t    *local  = NULL;          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if (op_ret == -1) {                  STACK_WIND (frame, trash_ftruncate_unlink_cbk,                              FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink, -                            &local->newloc); +                            &local->newloc, 0, xdata);                  return 0;          } @@ -1085,14 +1675,14 @@ trash_ftruncate_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  STACK_WIND (frame, trash_ftruncate_readv_cbk,                              FIRST_CHILD(this), FIRST_CHILD(this)->fops->readv,                              local->fd, (size_t)GF_BLOCK_READV_SIZE, -                            local->cur_offset, 0); +                            local->cur_offset, 0, xdata);                  return 0;          }          STACK_WIND (frame, trash_common_unwind_buf_cbk, FIRST_CHILD(this),                      FIRST_CHILD(this)->fops->ftruncate, local->fd, -                    local->fop_offset); - +                    local->fop_offset, xdata); +out:          return 0;  } @@ -1101,24 +1691,28 @@ int32_t  trash_ftruncate_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 iatt *stbuf, struct iobref *iobuf) +                           struct iatt *stbuf, struct iobref *iobuf, +                           dict_t *xdata)  { -        trash_local_t *local = NULL; +        trash_local_t   *local  = NULL;          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out); +          local->fsize = stbuf->ia_size;          if (op_ret == -1) {                  STACK_WIND (frame, trash_ftruncate_unlink_cbk,                              FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink, -                            &local->newloc); +                            &local->newloc, 0, xdata);                  return 0;          }          STACK_WIND (frame, trash_ftruncate_writev_cbk,                      FIRST_CHILD(this), FIRST_CHILD(this)->fops->writev, -                    local->newfd, vector, count, local->cur_offset, 0, NULL); - +                    local->newfd, vector, count, local->cur_offset, 0, +                    NULL, xdata); +out:          return 0;  } @@ -1127,49 +1721,77 @@ int32_t  trash_ftruncate_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 iatt *buf, -                            struct iatt *preparent, struct iatt *postparent) +                            struct iatt *preparent, struct iatt *postparent, +                            dict_t *xdata)  { -        trash_local_t *local = NULL; -        char          *tmp_str = NULL; -        char          *dir_name = NULL; -        char          *tmp_path = NULL; -        loc_t          tmp_loc = {0,}; +        trash_local_t   *local              = NULL; +        char            *tmp_str            = NULL; +        char            *dir_name           = NULL; +        char            *tmp_path           = NULL; +        loc_t           tmp_loc             = {0,}; +        char            *pathbuf            = NULL; +        char            *tmp_stat           = NULL; +        char            real_path[PATH_MAX] = {0,}; +        trash_private_t *priv               = NULL; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out);          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out); + +        /* This will be more accurate */ +        inode_path (fd->inode, NULL, &pathbuf);          if ((op_ret == -1) && (op_errno == ENOENT)) {                  tmp_str = gf_strdup (local->newpath);                  if (!tmp_str) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out;                  }                  dir_name = dirname (tmp_str);                  tmp_path = gf_strdup (dir_name);                  if (!tmp_path) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out;                  } -                tmp_loc.path = tmp_path; - -                /* TODO: create the directory with proper permissions */ +                loc_copy (&tmp_loc, &local->newloc); +                tmp_loc.path = gf_strdup (tmp_path); +                if (!tmp_loc.path) { +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out; +                } +                strcpy (real_path, priv->brick_path); +                remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +                if (tmp_stat) +                        strcat (real_path, tmp_stat); +                /* 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, NULL); -                GF_FREE (tmp_str); -                return 0; +                                   &tmp_loc, get_permission(real_path), +                                   0022, xdata); +                loc_wipe (&tmp_loc); +                goto out;          }          if (op_ret == -1) {                  STACK_WIND (frame, trash_common_unwind_buf_cbk,                              FIRST_CHILD(this),                              FIRST_CHILD(this)->fops->ftruncate, -                            local->fd, local->fop_offset); -                return 0; +                            local->fd, local->fop_offset, xdata); +                goto out;          }          STACK_WIND (frame, trash_ftruncate_readv_cbk, FIRST_CHILD(this),                      FIRST_CHILD(this)->fops->readv, local->fd, -                    (size_t)GF_BLOCK_READV_SIZE, local->cur_offset, 0); +                    (size_t)GF_BLOCK_READV_SIZE, local->cur_offset, 0, xdata); +out: +        if (tmp_str) +                GF_FREE (tmp_str); +        if (tmp_path) +                GF_FREE (tmp_path);          return 0;  } @@ -1179,28 +1801,35 @@ int32_t  trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                             int32_t op_ret, int32_t op_errno, inode_t *inode,                             struct iatt *stbuf, struct iatt *preparent, -                           struct iatt *postparent) +                           struct iatt *postparent, dict_t *xdata)  { -        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,}; +        trash_local_t        *local              = NULL; +        trash_private_t      *priv               = NULL; +        char                 *tmp_str            = NULL; +        char                 *tmp_path           = NULL; +        char                 *tmp_dirname        = NULL; +        char                 *dir_name           = NULL; +        char                 *tmp_stat           = NULL; +        char                 real_path[PATH_MAX] = {0,}; +        size_t               count               = 0; +        int32_t              flags               = 0; +        int32_t              loop_count          = 0; +        int                  i                   = 0; +        loc_t                tmp_loc             = {0,}; +        int                  ret                 = 0; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out);          local   = frame->local; -        if (!local) -                goto out; +        GF_VALIDATE_OR_GOTO ("trash", priv, out);          loop_count = local->loop_count;          tmp_str = gf_strdup (local->newpath);          if (!tmp_str) {                  gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM;                  goto out;          } @@ -1215,32 +1844,48 @@ trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                  break;                          tmp_dirname = strchr (tmp_str + count + 1, '/');                  } -                tmp_path = memdup (local->newpath, count); +                tmp_path = gf_memdup (local->newpath, count + 1);                  if (!tmp_path) {                          gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } +                tmp_path[count] = '\0'; + +                loc_copy (&tmp_loc, &local->newloc); +                tmp_loc.path = gf_strdup (tmp_path); +                if (!tmp_loc.path) { +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out;                  } -                tmp_loc.path = tmp_path; +                strcpy (real_path, priv->brick_path); +                remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +                if (tmp_stat) +                        strcat (real_path, tmp_stat);                  STACK_WIND_COOKIE (frame, trash_ftruncate_mkdir_cbk, -                                   tmp_path, this->children->xlator, -                                   this->children->xlator->fops->mkdir, -                                   &tmp_loc, 0755, NULL); - +                                   tmp_path, FIRST_CHILD(this), +                                   FIRST_CHILD(this)->fops->mkdir, +                                   &tmp_loc, get_permission(real_path), +                                   0022, xdata); +                loc_wipe (&tmp_loc);                  goto out;          }          if (op_ret == 0) {                  dir_name = dirname (tmp_str); -                if (strcmp ((char*)cookie, dir_name) == 0) { -                        ia_prot_t prot = {0, }; +                if (strcmp ((char *)cookie, dir_name) == 0) {                          flags = O_CREAT|O_EXCL|O_WRONLY; - -                        //Call create again once directory structure is created. +                        strcpy (real_path, priv->brick_path); +                        strcat (real_path, local->origpath); +                        /* Call create again once directory structure +                           is created. */                          STACK_WIND (frame, trash_ftruncate_create_cbk,                                      FIRST_CHILD(this),                                      FIRST_CHILD(this)->fops->create,                                      &local->newloc, flags, -                                    st_mode_from_ia (prot, local->loc.inode->ia_type), -                                    local->newfd, NULL); +                                    get_permission (real_path), +                                    0022, local->newfd, xdata);                          goto out;                  }          } @@ -1250,288 +1895,864 @@ trash_ftruncate_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  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 = memdup (local->newpath, count); +        tmp_path = gf_memdup (local->newpath, count + 1);          if (!tmp_path) {                  gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM; +                goto out;          } -        tmp_loc.path = tmp_path; +        tmp_path[count] = '\0'; -        STACK_WIND_COOKIE (frame, trash_ftruncate_mkdir_cbk, tmp_path, -                           this->children->xlator, -                           this->children->xlator->fops->mkdir, -                           &tmp_loc, 0755, NULL); +        loc_copy (&tmp_loc, &local->newloc); +        tmp_loc.path = gf_strdup (tmp_path); +        if (!tmp_loc.path) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM; +                goto out; +        } + +        /* Stores the the name of directory to be created */ +        tmp_loc.name = gf_strdup (strrchr(tmp_path, '/') + 1); +        if (!tmp_loc.name) { +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                ret = ENOMEM; +                goto out; +        } +        strcpy (real_path, priv->brick_path); +        remove_trash_path (tmp_path, (frame->root->pid < 0), tmp_stat); +        if (tmp_stat) +                strcat (real_path, tmp_stat); +        STACK_WIND_COOKIE (frame, trash_ftruncate_mkdir_cbk, tmp_path, +                           FIRST_CHILD(this), +                           FIRST_CHILD(this)->fops->mkdir, &tmp_loc, +                           get_permission(real_path), +                           0022, xdata);  out: -        GF_FREE (cookie); /* strdup (dir_name) was sent here :) */ -        GF_FREE (tmp_str); +        if (tmp_str) +                GF_FREE (tmp_str); +        if (tmp_path) +                GF_FREE (tmp_path); -        return 0; +        return ret;  }  int32_t  trash_ftruncate_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, -                           int32_t op_ret, int32_t op_errno, struct iatt *buf) +                           int32_t op_ret, int32_t op_errno, struct iatt *buf, +                           dict_t *xdata)  {          trash_private_t *priv  = NULL;          trash_local_t   *local = NULL;          priv  = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); +          local = frame->local; +        GF_VALIDATE_OR_GOTO ("trash", local, out);          if (op_ret == -1) {                  gf_log (this->name, GF_LOG_DEBUG,                          "%s: %s",local->newloc.path, strerror(op_errno)); -                TRASH_STACK_UNWIND (ftruncate, frame, -1, op_errno, buf, NULL); -                return 0; +                TRASH_STACK_UNWIND (ftruncate, frame, -1, op_errno, buf, +                                    NULL, xdata); +                goto out;          } -        if ((buf->ia_size == 0) || (buf->ia_size > priv->max_trash_file_size)) +        if ((buf->ia_size > (priv->max_trash_file_size)))          {                  STACK_WIND (frame, trash_common_unwind_buf_cbk, -                            this->children->xlator, -                            this->children->xlator->fops->ftruncate, -                            local->fd, local->fop_offset); -                return 0; +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->ftruncate, +                            local->fd, local->fop_offset, xdata); +                goto out;          } -        STACK_WIND (frame, trash_ftruncate_create_cbk, FIRST_CHILD(this), +        STACK_WIND (frame, trash_truncate_create_cbk, FIRST_CHILD(this),                      FIRST_CHILD(this)->fops->create, &local->newloc,                      ( O_CREAT | O_EXCL | O_WRONLY ),                      st_mode_from_ia (buf->ia_prot, local->loc.inode->ia_type), -                    local->newfd, NULL); +                    0022, local->newfd, xdata); +out:          return 0;  } +/** + * When we call truncate from terminal it comes to ftruncate of trash-xlator. + * Since truncate internally calls ftruncate and we receive fd of the file, + * other than that it also called by Rebalance operation + */  int32_t -trash_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset) +trash_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, +                 dict_t *xdata)  { -        trash_elim_pattern_t  *trav = NULL; -        trash_private_t       *priv = NULL; -        trash_local_t         *local = NULL; -        dentry_t              *dir_entry = NULL; -        char                  *pathbuf = NULL; -        inode_t               *newinode = NULL; -        char                   timestr[64]; -        int32_t                retval = 0; -        int32_t                match = 0; +        trash_private_t      *priv           = NULL; +        trash_local_t        *local          = NULL;/* file inside trash */ +        char                 *pathbuf        = NULL;/* path of file from fd */ +        int32_t              retval          = 0; +        int32_t              match           = 0; +        int                  ret             = 0;          priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); +        /* If trash is not active or not enabled through cli, then +         * we bypass and wind back +         */ +        if (!priv->state) { +                STACK_WIND (frame, trash_common_unwind_buf_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->ftruncate, fd, +                            offset, xdata); +                goto out; +        } -        dir_entry = __dentry_search_arbit (fd->inode); +        /* The files removed by gluster operations such as self-heal, +         * should moved to trash directory, but files by client +         * should not moved +         */ +        if ((frame->root->pid < 0) && !priv->internal) { +                STACK_WIND (frame, trash_common_unwind_buf_cbk, +                            FIRST_CHILD(this), +                            FIRST_CHILD(this)->fops->ftruncate, fd, +                            offset, xdata); +                goto out; +        } +        /* This will be more accurate */          retval = inode_path (fd->inode, NULL, &pathbuf); -        if (priv->eliminate) { -                trav = priv->eliminate; -                while (trav) { -                        if (fnmatch(trav->pattern, dir_entry->name, 0) == 0) { -                                match++; -                                break; -                        } -                        trav = trav->next; +        /* Checking  the eliminate path */ + +        /* Checks whether file is trash directory or eliminate path or +         * invalid fd. In all such cases it does not move to trash directory, +         * ftruncate will be performed +         */ +        match = check_whether_eliminate_path (priv->eliminate, pathbuf); +        if ((strncmp (pathbuf, priv->newtrash_dir, +                      strlen (priv->newtrash_dir)) == 0) || match || +                      !retval) { + +                if (match) { +                        gf_log (this->name, GF_LOG_DEBUG, +                                "%s: file matches eliminate path, " +                                "not moved to trash", pathbuf);                  } -        } -        if ((strncmp (pathbuf, priv->trash_dir, -                      strlen (priv->trash_dir)) == 0) || -            (offset >= priv->max_trash_file_size) || -            (!retval) || -            match) { +                /* Trying to ftruncate from the trash-dir. So do the +                 * actual ftruncate without moving to trash-dir +                 */                  STACK_WIND (frame, trash_common_unwind_buf_cbk,                              FIRST_CHILD(this),                              FIRST_CHILD(this)->fops->ftruncate, -                            fd, offset); -                return 0; +                            fd, offset, xdata); +                goto out;          }          local = mem_get0 (this->local_pool);          if (!local) {                  gf_log (this->name, GF_LOG_DEBUG, "out of memory"); -                TRASH_STACK_UNWIND (ftruncate, frame, -1, ENOMEM, NULL, NULL); -                return 0; +                TRASH_STACK_UNWIND (ftruncate, frame, -1, ENOMEM, NULL, +                                    NULL, xdata); +                ret     = -1; +                goto out;          } -        gf_time_fmt (timestr, sizeof timestr, time (NULL), gf_timefmt_F_HMS); -        strcpy (local->newpath, priv->trash_dir); -        strcat (local->newpath, pathbuf); -        strcat (local->newpath, timestr); - -        local->fd = fd_ref (fd); -        newinode = inode_new (fd->inode->table); -        local->newfd = fd_create (newinode, frame->root->pid); +        /* To convert fd to location */          frame->local=local; -        local->newloc.inode = newinode; -        local->newloc.path = local->newpath; - -        local->loc.inode = inode_ref (fd->inode);          local->loc.path  = pathbuf; +        local->loc.inode = inode_ref (fd->inode); +        uuid_copy (local->loc.gfid, local->loc.inode->gfid);          local->fop_offset = offset; -        local->cur_offset = offset; -        STACK_WIND (frame, trash_ftruncate_fstat_cbk, this->children->xlator, -                    this->children->xlator->fops->fstat, fd); +        /* Else remains same to truncate code, so from here flow goes +         * to truncate_stat +         */ +        STACK_WIND (frame, trash_truncate_stat_cbk, FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->fstat, fd, xdata); +out: +        return ret; +} + +/** + * The mkdir call is intercepted to avoid creation of + * trash directory in the mount by the user + */ +int32_t +trash_mkdir (call_frame_t *frame, xlator_t *this, +             loc_t *loc, mode_t mode, mode_t umask, dict_t *xdata) +{ +        int32_t               op_ret      = 0; +        int32_t               op_errno    = 0; +        trash_private_t       *priv       = NULL; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        if (!check_whether_trash_directory (loc->path, priv->newtrash_dir)) { +                gf_log (this->name, GF_LOG_WARNING, +                        "mkdir issued on %s, which is not permitted", +                        priv->newtrash_dir); +                op_errno = EPERM; +                op_ret = -1; +                STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno, +                             NULL, NULL, NULL, NULL, xdata); +        } else { +                STACK_WIND (frame, trash_common_mkdir_cbk, FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->mkdir, loc, mode, umask, xdata); +        } +out:          return 0;  }  /** - * trash_init - + * The rename call is intercepted to avoid renaming + * of trash directory in the mount by the user + */ +int +trash_rename (call_frame_t *frame, xlator_t *this, +              loc_t *oldloc, loc_t *newloc, dict_t *xdata) +{ +        int32_t               op_ret      = 0; +        int32_t               op_errno    = 0; +        trash_private_t       *priv       = NULL; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        if (!check_whether_trash_directory (oldloc->path, priv->newtrash_dir)) { +                gf_log (this->name, GF_LOG_WARNING, +                        "rename issued on %s, which is not permitted", +                        priv->newtrash_dir); +                op_errno = EPERM; +                op_ret = -1; + +                STACK_UNWIND_STRICT (rename, frame, op_ret, op_errno, NULL, +                                     NULL, NULL, NULL, NULL, xdata); +        } else { +                STACK_WIND (frame, trash_common_rename_cbk, FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->rename, oldloc, newloc, xdata); +        } +out: +        return 0; +} + +/** + * The rmdir call is intercepted to avoid deletion of + * trash directory in the mount by the user + */ +int32_t +trash_rmdir (call_frame_t *frame, xlator_t *this, +             loc_t *loc, int flags, dict_t *xdata) +{ +        int32_t               op_ret      = 0; +        int32_t               op_errno    = 0; +        trash_private_t       *priv       = NULL; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        if (!check_whether_trash_directory (loc->path, priv->newtrash_dir)) { +                gf_log (this->name, GF_LOG_WARNING, +                        "rmdir issued on %s, which is not permitted", +                        priv->newtrash_dir); +                op_errno = EPERM; +                op_ret = -1; + +                STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno, +                             NULL, NULL, xdata); +        } else { +                STACK_WIND (frame, trash_common_rmdir_cbk, FIRST_CHILD(this), +                    FIRST_CHILD(this)->fops->rmdir, loc, flags, xdata); +        } +out: +        return 0; +} + +/** + * Volume set option is handled by the reconfigure funtion. + * Here we checks whether each option is set or not ,if it + * sets then corresponding modifciations will be made + */ +int +reconfigure (xlator_t *this, dict_t *options) +{ +        uint64_t              max_fsize           = 0; +        int                   ret                 = 0; +        char                  *tmp                = NULL; +        char                  *tmp_str            = NULL; +        trash_private_t       *priv               = NULL; +        loc_t                 old_loc             = {0, }; +        loc_t                 new_loc             = {0, }; +        call_frame_t          *frame              = NULL; +        char                  trash_dir[PATH_MAX] = {0,}; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        GF_OPTION_RECONF ("trash", priv->state, options, bool, out); + +        GF_OPTION_RECONF ("trash-dir", tmp, options, str, out); +        if (tmp) { +                sprintf(trash_dir, "/%s/", tmp); +                if (strcmp(priv->newtrash_dir, trash_dir) != 0) { + +                        /* When user set a new name for trash directory, trash +                        * xlator will perform a rename operation on old trash +                        * directory to the new one using a STACK_WIND from here. +                        * This option can be configured only when volume is in +                        * started state +                        */ + +                        GF_FREE (priv->newtrash_dir); + +                        priv->newtrash_dir = gf_strdup (trash_dir); +                        if (!priv->newtrash_dir) { +                                ret = ENOMEM; +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } +                        gf_log (this->name, GF_LOG_DEBUG, +                                "Renaming %s -> %s from reconfigure", +                                priv->oldtrash_dir, priv->newtrash_dir); + +                        if (!priv->newtrash_dir) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                ret = ENOMEM; +                                goto out; +                        } +                        frame = create_frame (this, this->ctx->pool); + +                        /* assign new location values to new_loc members */ +                        uuid_copy (new_loc.gfid, trash_gfid); +                        uuid_copy (new_loc.pargfid, root_gfid); +                        ret = extract_trash_directory (priv->newtrash_dir, +                                                                &new_loc.name); +                        if (ret) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } +                        new_loc.path = gf_strdup (priv->newtrash_dir); +                        if (!new_loc.path) { +                                ret = ENOMEM; +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } + +                        /* assign old location values to old_loc members */ +                        uuid_copy (old_loc.gfid, trash_gfid); +                        uuid_copy (old_loc.pargfid, root_gfid); +                        ret = extract_trash_directory (priv->oldtrash_dir, +                                                                &old_loc.name); +                        if (ret) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } +                        old_loc.path = gf_strdup (priv->oldtrash_dir); +                        if (!old_loc.path) { +                                ret = ENOMEM; +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } + +                        old_loc.inode = inode_ref (priv->trash_inode); +                        uuid_copy(old_loc.inode->gfid, old_loc.gfid); + +                        STACK_WIND (frame, trash_reconf_rename_cbk, +                                    FIRST_CHILD(this), +                                    FIRST_CHILD(this)->fops->rename, +                                    &old_loc, &new_loc, options); +                        if (priv->oldtrash_dir) +                                GF_FREE (priv->oldtrash_dir); + +                        priv->oldtrash_dir = gf_strdup(priv->newtrash_dir); +                        if (!priv->oldtrash_dir) { +                                ret = ENOMEM; +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } +                } +        } +        tmp = NULL; + +        GF_OPTION_RECONF ("trash-internal-op", priv->internal, options, +                                               bool, out); + +        GF_OPTION_RECONF ("trash-max-filesize", max_fsize, options, +                                                size_uint64, out); +        if (max_fsize) { +                if (max_fsize > GF_ALLOWED_MAX_FILE_SIZE) { +                        gf_log (this->name, GF_LOG_DEBUG, +                                "Size specified for max-size(in MB) is too " +                                "large so using 1GB as max-size (NOT IDEAL)"); +                        priv->max_trash_file_size = GF_ALLOWED_MAX_FILE_SIZE; +                } else +                        priv->max_trash_file_size = max_fsize; +                gf_log (this->name, GF_LOG_DEBUG, "%"GF_PRI_SIZET" max-size", +                        priv->max_trash_file_size); +        } +        GF_OPTION_RECONF ("trash-eliminate-path", tmp, options, str, out); +        if (!tmp) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "no option specified for 'eliminate', using NULL"); +        } else { +                if (priv->eliminate) +                        wipe_eliminate_path (priv->eliminate); + +                tmp_str = gf_strdup (tmp); +                if (!tmp_str) { +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        ret = ENOMEM; +                        goto out; +                } +                ret = store_eliminate_path (tmp_str, priv->eliminate); + +        } + +out: +        if (tmp_str) +                GF_FREE (tmp_str); +        loc_wipe (&new_loc); +        loc_wipe (&old_loc); + +        return ret; +} + +/** + * Notify is used to create the trash directory with fixed gfid + * using STACK_WIND only when posix xlator is up + */ +int +notify (xlator_t *this, int event, void *data, ...) +{ +        trash_private_t       *priv      = NULL; +        dict_t                *dict      = NULL; +        int                   ret        = 0; +        uuid_t                *tgfid_ptr = NULL; +        loc_t                 loc        = {0, }; +        loc_t                 old_loc    = {0, }; +        call_frame_t          *frame     = NULL; + +        priv = this->private; +        GF_VALIDATE_OR_GOTO ("trash", priv, out); + +        /* Check whether posix is up not */ +        if (event == GF_EVENT_CHILD_UP) { +                frame = create_frame(this, this->ctx->pool); +                dict = dict_new (); +                if (!dict) { +                        ret = ENOMEM; +                        goto out; +                } +                priv->trash_itable = inode_table_new (0, this); + +                /* Here there is two possiblities ,if trash directory already +                 * exist ,then we need to perform a rename operation on the +                 * old one. Otherwise, we need to create the trash directory +                 * For both, we need to pass location variable, gfid of parent +                 * and a frame for calling STACK_WIND.The location variable +                 * requires name,path,gfid and inode +                 */ +                if (!priv->oldtrash_dir) { +                        loc.inode = inode_new (priv->trash_itable); +                        uuid_copy (loc.gfid, trash_gfid); + +                        gf_log (this->name, GF_LOG_DEBUG, "nameless lookup for" +                                           "old trash directory"); +                        STACK_WIND (frame, trash_notify_lookup_cbk, +                                    FIRST_CHILD(this), +                                    FIRST_CHILD(this)->fops->lookup, +                                    &loc, dict); +                        gf_log (this->name, GF_LOG_DEBUG, "old_trash_dir %s", +                                        priv->oldtrash_dir); +                        loc_wipe (&loc); +                } + +                if (strcmp (priv->oldtrash_dir, priv->newtrash_dir) == 0) { +                        gf_log (this->name, GF_LOG_DEBUG, "Creating trash " +                                           "directory %s from notify", +                                           priv->newtrash_dir); + +                        tgfid_ptr = GF_CALLOC (1, sizeof(uuid_t), +                                                  gf_common_mt_uuid_t); +                        if (!tgfid_ptr) { +                                ret = ENOMEM; +                                goto out; +                        } +                        uuid_copy (*tgfid_ptr, trash_gfid); + +                        uuid_copy (loc.gfid, trash_gfid); +                        uuid_copy (loc.pargfid, root_gfid); +                        ret = extract_trash_directory (priv->newtrash_dir, +                                                                &loc.name); +                        if (ret) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } +                        loc.path = gf_strdup (priv->newtrash_dir); +                        if (!loc.path) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                ret = ENOMEM; +                                goto out; +                        } + +                        priv->trash_inode = inode_new (priv->trash_itable); +                        priv->trash_inode->ia_type = IA_IFDIR; +                        loc.inode = inode_ref (priv->trash_inode); + +                        /* Fixed gfid is set for trash directory with +                         * this function +                         */ +                        ret = dict_set_dynptr (dict, "gfid-req", tgfid_ptr, +                                              sizeof (uuid_t)); +                        if (ret) { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "setting key gfid-req failed"); +                                goto out; +                        } + +                        /* The mkdir call for creating trash directory */ +                        STACK_WIND (frame, trash_notify_mkdir_cbk, +                                    FIRST_CHILD(this), +                                    FIRST_CHILD(this)->fops->mkdir, &loc, 0755, +                                    0022, dict); +                } else { +                        /* assign new location values to new_loc members */ +                        gf_log (this->name, GF_LOG_DEBUG, "Renaming %s -> %s" +                                        " from notify", priv->oldtrash_dir, +                                        priv->newtrash_dir); +                        uuid_copy (loc.gfid, trash_gfid); +                        uuid_copy (loc.pargfid, root_gfid); +                        ret = extract_trash_directory (priv->newtrash_dir, +                                                                &loc.name); +                        if (ret) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } +                        loc.path = gf_strdup (priv->newtrash_dir); +                        if (!loc.path) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                ret = ENOMEM; +                                goto out; +                        } +                        /* assign old location values to old_loc members */ +                        uuid_copy (old_loc.gfid, trash_gfid); +                        uuid_copy (old_loc.pargfid, root_gfid); +                        ret = extract_trash_directory (priv->oldtrash_dir, +                                                                &old_loc.name); +                        if (ret) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                goto out; +                        } +                        old_loc.path = gf_strdup (priv->oldtrash_dir); +                        if (!old_loc.path) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                ret = ENOMEM; +                                goto out; +                        } + +                        old_loc.inode = inode_ref (priv->trash_inode); +                        uuid_copy(old_loc.inode->gfid, old_loc.gfid); + +                        STACK_WIND (frame, trash_notify_rename_cbk, +                                    FIRST_CHILD(this), +                                    FIRST_CHILD(this)->fops->rename, +                                    &old_loc, &loc, dict); +                        if (priv->oldtrash_dir) +                                GF_FREE (priv->oldtrash_dir); + +                        priv->oldtrash_dir = gf_strdup(priv->newtrash_dir); +                        if (!priv->oldtrash_dir) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                                "out of memory"); +                                ret = ENOMEM; +                                goto out; +                        } +                } +        } else { +                ret = default_notify (this, event, data); +                if (ret) +                        gf_log (this->name, GF_LOG_INFO, +                                "default notify event failed"); +        } + +out: +        if (ret && tgfid_ptr) +                GF_FREE (tgfid_ptr); +        if (dict) +                dict_unref (dict); +        loc_wipe (&loc); +        loc_wipe (&old_loc); + +        return ret; +} + +int32_t +mem_acct_init (xlator_t *this) +{ +        int         ret          = -1; + +        GF_VALIDATE_OR_GOTO ("trash", this, out); + +        ret = xlator_mem_acct_init (this, gf_trash_mt_end + 1); +        if (ret != 0) { +                gf_log(this->name, GF_LOG_ERROR, "Memory accounting init" +                       "failed"); +                return ret; +        } +out: +        return ret; +} + +/** + * trash_init   */  int32_t  init (xlator_t *this)  { -        data_t                *data  = NULL; -        trash_private_t       *_priv = NULL; -        trash_elim_pattern_t  *trav  = NULL; -        char                  *tmp_str = NULL; -        char                  *strtokptr = NULL; -        char                  *component = NULL; -        char                   trash_dir[PATH_MAX] = {0,}; -        uint64_t               max_trash_file_size64 = 0; - -        /* Create .trashcan directory in init */ +        trash_private_t        *priv                   = NULL; +        int                    ret                     = -1; +        char                   *tmp                    = NULL; +        char                   *tmp_str                = NULL; +        char                   trash_dir[PATH_MAX]     = {0,}; +        uint64_t               max_trash_file_size64   = 0; +        data_t                *data                    = NULL; + +        GF_VALIDATE_OR_GOTO ("trash", this, out); +          if (!this->children || this->children->next) {                  gf_log (this->name, GF_LOG_ERROR,                          "not configured with exactly one child. exiting"); -                return -1; +                ret = -1; +                goto out;          }          if (!this->parents) {                  gf_log (this->name, GF_LOG_WARNING, -                        "dangling volume. check volfile "); +                        "dangling volume. check volfile");          } -        _priv = GF_CALLOC (1, sizeof (*_priv), gf_trash_mt_trash_private_t); -        if (!_priv) { +        priv = GF_CALLOC (1, sizeof (*priv), gf_trash_mt_trash_private_t); +        if (!priv) {                  gf_log (this->name, GF_LOG_ERROR, "out of memory"); -                return -1; +                ret = ENOMEM; +                goto out;          } -        data = dict_get (this->options, "trash-dir"); -        if (!data) { +        /* Trash priv data members are initialized through the following +         * set of statements +         */ +        GF_OPTION_INIT ("trash", priv->state, bool, out); + +        GF_OPTION_INIT ("trash-dir", tmp, str, out); + +        /* We store trash dir value as path for easier manipulation*/ +        if (!tmp) {                  gf_log (this->name, GF_LOG_INFO,                          "no option specified for 'trash-dir', "                          "using \"/.trashcan/\""); -                _priv->trash_dir = gf_strdup ("/.trashcan"); +                priv->newtrash_dir = gf_strdup ("/.trashcan/"); +                if (!priv->newtrash_dir) { +                        ret = ENOMEM; +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out; +                }          } else { -                /* Need a path with '/' as the first char, if not -                   given, append it */ -                if (data->data[0] == '/') { -                        _priv->trash_dir = gf_strdup (data->data); -                } else { -                        /* TODO: Make sure there is no ".." in the path */ -                        strcpy (trash_dir, "/"); -                        strcat (trash_dir, data->data); -                        _priv->trash_dir = gf_strdup (trash_dir); +                sprintf(trash_dir, "/%s/", tmp); +                priv->newtrash_dir = gf_strdup (trash_dir); +                if (!priv->newtrash_dir) { +                        ret = ENOMEM; +                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        goto out;                  }          } +        tmp = NULL; -        data = dict_get (this->options, "eliminate-pattern"); -        if (!data) { -                gf_log (this->name, GF_LOG_TRACE, +        GF_OPTION_INIT ("trash-eliminate-path", tmp, str, out); +        if (!tmp) { +                gf_log (this->name, GF_LOG_INFO,                          "no option specified for 'eliminate', using NULL");          } else { -                tmp_str = gf_strdup (data->data); +                tmp_str = gf_strdup (tmp);                  if (!tmp_str) { -                        gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                        gf_log (this->name, GF_LOG_ERROR, +                                        "out of memory"); +                        ret = ENOMEM; +                        goto out;                  } +                ret = store_eliminate_path (tmp_str, priv->eliminate); -                /*  Match Filename to option specified in eliminate. */ -                component = strtok_r (tmp_str, "|", &strtokptr); -                while (component) { -                        trav = GF_CALLOC (1, sizeof (*trav), -                                          gf_trash_mt_trash_elim_pattern_t); -                        if (!trav) { -                                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); -                                break; -                        } -                        trav->pattern = component; -                        trav->next = _priv->eliminate; -                        _priv->eliminate = trav; - -                        component = strtok_r (NULL, "|", &strtokptr); -                }          } +        tmp = NULL; -        /* TODO: do gf_string2sizet () */ -        data = dict_get (this->options, "max-trashable-file-size"); -        if (!data) { -                gf_log (this->name, GF_LOG_DEBUG, +        GF_OPTION_INIT ("trash-max-filesize", max_trash_file_size64, +                        size_uint64, out); +        if (!max_trash_file_size64) { +                gf_log (this->name, GF_LOG_ERROR,                          "no option specified for 'max-trashable-file-size', "                          "using default = %lld MB",                          GF_DEFAULT_MAX_FILE_SIZE / GF_UNIT_MB); -                _priv->max_trash_file_size = GF_DEFAULT_MAX_FILE_SIZE; +                priv->max_trash_file_size = GF_DEFAULT_MAX_FILE_SIZE;          } else { -                (void)gf_string2bytesize (data->data, -                                          &max_trash_file_size64);                  if( max_trash_file_size64 > GF_ALLOWED_MAX_FILE_SIZE ) {                          gf_log (this->name, GF_LOG_DEBUG,                                  "Size specified for max-size(in MB) is too "                                  "large so using 1GB as max-size (NOT IDEAL)"); -                        _priv->max_trash_file_size = GF_ALLOWED_MAX_FILE_SIZE; +                        priv->max_trash_file_size = GF_ALLOWED_MAX_FILE_SIZE;                  } else -                        _priv->max_trash_file_size = max_trash_file_size64; +                        priv->max_trash_file_size = max_trash_file_size64;                  gf_log (this->name, GF_LOG_DEBUG, "%"GF_PRI_SIZET" max-size", -                        _priv->max_trash_file_size); +                        priv->max_trash_file_size);          } +        GF_OPTION_INIT ("trash-internal-op", priv->internal, bool, out); +          this->local_pool = mem_pool_new (trash_local_t, 64);          if (!this->local_pool) {                  gf_log (this->name, GF_LOG_ERROR,                          "failed to create local_t's memory pool"); -                return -1; +                ret = ENOMEM; +                goto out; +        } + +        /* For creating directories inside trash with proper permissions, +         * we need to perform stat on that directories, for this we use +         * brick path +         */ +        data = dict_get (this->options, "brick-path"); +        if (!data) { +                gf_log (this->name, GF_LOG_ERROR, +                        "no option specified for 'brick-path'"); +                ret = ENOMEM; +                goto out; +        } +        priv->brick_path = gf_strdup (data->data); +        if (!priv->brick_path) { +                ret = ENOMEM; +                gf_log (this->name, GF_LOG_DEBUG, "out of memory"); +                goto out;          } +        gf_log (this->name, GF_LOG_DEBUG, "brick path is%s", priv->brick_path); -        this->private = (void *)_priv; -        return 0; +        this->private = (void *)priv; +        ret = 0; + +out: +        if (tmp_str) +                GF_FREE (tmp_str); +        if (ret) { +                if (priv) { +                        if (priv->newtrash_dir) +                                GF_FREE (priv->newtrash_dir); +                        if (priv->oldtrash_dir) +                                GF_FREE (priv->oldtrash_dir); +                        if (priv->brick_path) +                                GF_FREE (priv->brick_path); +                        if (priv->eliminate) +                                wipe_eliminate_path (priv->eliminate); +                        GF_FREE (priv); +                } +                mem_pool_destroy (this->local_pool); +        } +        return ret;  } +/** + * trash_fini + */  void  fini (xlator_t *this)  {          trash_private_t *priv = NULL; +        GF_VALIDATE_OR_GOTO ("trash", this, out);          priv = this->private; -        GF_FREE (priv); +        if (priv) { +                if (priv->newtrash_dir) +                        GF_FREE (priv->newtrash_dir); +                if (priv->oldtrash_dir) +                        GF_FREE (priv->oldtrash_dir); +                if (priv->brick_path) +                        GF_FREE (priv->brick_path); +                if (priv->eliminate) +                        wipe_eliminate_path (priv->eliminate); +                GF_FREE (priv); +        } +        mem_pool_destroy (this->local_pool); +        this->private = NULL; +out:          return;  }  struct xlator_fops fops = { -        .unlink    = trash_unlink, -        .rename    = trash_rename, -        .truncate  = trash_truncate, -        .ftruncate = trash_ftruncate, +        .unlink          = trash_unlink, +        .truncate        = trash_truncate, +        .ftruncate       = trash_ftruncate, +        .rmdir           = trash_rmdir, +        .mkdir           = trash_mkdir, +        .rename          = trash_rename,  };  struct xlator_cbks cbks = {  };  struct volume_options options[] = { -        { .key  = { "trash-directory" }, -          .type = GF_OPTION_TYPE_PATH, +        { .key           = { "trash" }, +          .type          = GF_OPTION_TYPE_BOOL, +          .default_value = "off", +          .description   = "Enable/disable trash translator", +        }, +        { .key           = { "trash-dir" }, +          .type          = GF_OPTION_TYPE_STR, +          .default_value = ".trashcan", +          .description   = "Directory for trash files", +        }, +        { .key           = { "trash-eliminate-path" }, +          .type          = GF_OPTION_TYPE_STR, +          .description   = "Eliminate paths to be excluded " +                           "from trashing",          }, -        { .key  = { "eliminate-pattern" }, -          .type = GF_OPTION_TYPE_STR, +        { .key           = { "trash-max-filesize" }, +          .type          = GF_OPTION_TYPE_SIZET, +          .default_value = "5MB", +          .description   = "Maximum size of file that can be " +                           "moved to trash",          }, -        { .key  = { "max-trashable-file-size" }, -          .type = GF_OPTION_TYPE_SIZET, +        { .key           = { "trash-internal-op" }, +          .type          = GF_OPTION_TYPE_BOOL, +          .default_value = "off", +          .description   = "Enable/disable trash translator for " +                           "internal operations",          }, -        { .key  = {NULL} }, +        { .key           = {NULL} },  }; diff --git a/xlators/features/trash/src/trash.h b/xlators/features/trash/src/trash.h index 9a7c033617d..3e03edf5474 100644 --- a/xlators/features/trash/src/trash.h +++ b/xlators/features/trash/src/trash.h @@ -37,7 +37,6 @@  #define GF_ALLOWED_MAX_FILE_SIZE (1 * GF_UNIT_GB)  #endif -  struct trash_struct {          fd_t    *fd;         /* for the fd of existing file */          fd_t    *newfd;      /* for the newly created file */ @@ -54,26 +53,31 @@ struct trash_struct {  };  typedef struct trash_struct trash_local_t; -struct _trash_elim_pattern; -typedef struct _trash_elim_pattern { -        struct _trash_elim_pattern *next; -        char                       *pattern; -} trash_elim_pattern_t; +struct _trash_elim_path { +        struct _trash_elim_path    *next; +        char                       *path; +}; +typedef struct _trash_elim_path trash_elim_path;  struct trash_priv { -        char                 *trash_dir; -        trash_elim_pattern_t *eliminate; +        char                 *oldtrash_dir; +        char                 *newtrash_dir; +        char                 *brick_path; +        trash_elim_path      *eliminate;          size_t                max_trash_file_size; +        gf_boolean_t          state; +        gf_boolean_t          internal; +        inode_t              *trash_inode; +        inode_table_t        *trash_itable;  };  typedef struct trash_priv trash_private_t; -#define TRASH_STACK_UNWIND(op, frame, params ...) do {     \ -		trash_local_t *__local = NULL;         \ -		__local = frame->local;                \ -		frame->local = NULL;		       \ -		STACK_UNWIND_STRICT (op, frame, params);          \ -		trash_local_wipe (__local);	       \ -	} while (0) - +#define TRASH_STACK_UNWIND(op, frame, params ...) do {    \ +                trash_local_t *__local = NULL;            \ +                __local = frame->local;                   \ +                frame->local = NULL;                      \ +                STACK_UNWIND_STRICT (op, frame, params);  \ +                trash_local_wipe (__local);               \ +        } while (0)  #endif /* __TRASH_H__ */  | 
