diff options
Diffstat (limited to 'common/treepathutils.c')
| -rw-r--r-- | common/treepathutils.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/common/treepathutils.c b/common/treepathutils.c new file mode 100644 index 0000000..301f173 --- /dev/null +++ b/common/treepathutils.c @@ -0,0 +1,313 @@ +/* Tux Commander VFS: String utilities + * Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net> + * Check for updates on tuxcmd.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <glib.h> + +#include "treepathutils.h" +#include "strutils.h" +#include "vfsutils.h" + + + + + + +struct PathTree* filelist_tree_new() +{ + struct PathTree *tree = (struct PathTree*)malloc(sizeof(struct PathTree)); + memset(tree, 0, sizeof(struct PathTree)); + log("filelist_tree_new()\n"); + tree->items = g_ptr_array_new(); + tree->data = NULL; + tree->index = 0; + tree->node = strdup("/"); + + // create placeholder data + tree->data = (struct TVFSItem*)malloc(sizeof(struct TVFSItem)); + memset(tree->data, 0, sizeof(struct TVFSItem)); + tree->data->sFileName = strdup(tree->node); + tree->data->ItemType = vDirectory; + tree->data->iMode = S_IRWXO + S_IRWXG + S_IRWXU; + tree->data->iUID = geteuid(); + tree->data->iGID = getegid(); + tree->data->m_time = time(NULL); + tree->data->c_time = tree->data->m_time; + tree->data->a_time = tree->data->m_time; + + return tree; +} + + +void filelist_tree_free(struct PathTree *tree) +{ + if (! tree) { + fprintf(stderr, "filelist_tree_free: tree == NULL !\n"); + return; + } + if (tree) + { + if ((tree->items) && (tree->items->len > 0)) { + unsigned int i; + for (i = 0; i < tree->items->len; i++) + filelist_tree_free((struct PathTree*)g_ptr_array_index(tree->items, i)); + } + if (tree->items) + g_ptr_array_free(tree->items, TRUE); + if (tree->data) { + if (tree->data->sFileName) free(tree->data->sFileName); + if (tree->data->sLinkTo) free(tree->data->sLinkTo); + free(tree->data); + } + if (tree->node) + free(tree->node); + free(tree); + } +} + + +void filelist_tree_print_recurr(struct PathTree *tree, int level) +{ + if (tree) { + char *fill = g_strnfill(level * 2, 32); + printf(" %s#%lu. %s\n", fill, tree->index, tree->node); + + if ((tree->items) && (tree->items->len > 0)) { + unsigned int i; + for (i = 0; i < tree->items->len; i++) + { + struct PathTree* t = (struct PathTree*)g_ptr_array_index(tree->items, i); + filelist_tree_print_recurr(t, level + 1); + } + } + + g_free(fill); + } +} + + +void filelist_tree_print(struct PathTree *tree) +{ + filelist_tree_print_recurr(tree, 0); +} + + +struct PathTree* filelist_tree_find_node_by_path(struct PathTree *tree, const char *path) +{ + char *p; + if (IS_DIR_SEP(*path)) p = exclude_trailing_path_sep(path + 1); + else p = exclude_trailing_path_sep(path); + + log(" filelist_tree_find_node_by_path: path = '%s', p = '%s'\n", path, p); +// log("xx: '%s', '%s'\n", tree->node, path); + + struct PathTree* node = NULL; + if ((tree) && (tree->node) && (strcmp(tree->node, "/") == 0) && (strcmp(path, "/") == 0)) { + log(" filelist_tree_find_node_by_path: matched root '/' element, returning.\n"); + node = tree; + } else + if ((tree) && (tree->items) && (tree->items->len > 0)) { + // split path + char *pos = strstr(p, "/"); + char *first_part; + char *last_part; + if (pos) { + first_part = strndup(p, pos - p); + if (strlen(pos + 1) > 0) last_part = strdup(pos + 1); + else last_part = NULL; + } else { + first_part = strdup(p); + last_part = NULL; + } + log(" filelist_tree_find_node_by_path: pos = '%s'\n", pos); + log(" filelist_tree_find_node_by_path: first_part = '%s'\n", first_part); + log(" filelist_tree_find_node_by_path: last_part = '%s'\n", last_part); + + // find existing node + unsigned int i; + for (i = 0; i < tree->items->len; i++) + { + struct PathTree* t = (struct PathTree*)g_ptr_array_index(tree->items, i); + if (strcmp(t->node, first_part) == 0) { + // this is the final station + if (! last_part) { + node = t; + log(" filelist_tree_find_node_by_path: found final node '%s', returning.\n", t->node); + } else + // recurse to child items + if ((t->items) && (last_part)) { + log(" filelist_tree_find_node_by_path: found node '%s', recursing in deep.\n", t->node); + node = filelist_tree_find_node_by_path(t, last_part); + } else { + // item found but no subitems + log(" filelist_tree_find_node_by_path: found node '%s', but no subitems found.\n", t->node); + } + + break; + } + } + free(first_part); + free(last_part); + } + free(p); + return node; +} + +unsigned long int filelist_find_index_by_path(struct PathTree *tree, const char *path) +{ + struct PathTree* node = filelist_tree_find_node_by_path(tree, path); + if (node) return node->index; + else return 0; +} + +void filelist_tree_add_item_recurr(struct PathTree *tree, const char *path, struct TVFSItem *item, unsigned long index) +{ + char *pos = strstr(path, "/"); + char *first_part; + char *last_part; + if (pos) { + first_part = strndup(path, pos - path); + if (strlen(pos + 1) > 0) last_part = strdup(pos + 1); + else last_part = NULL; + } else { + first_part = strdup(path); + last_part = NULL; + } + log(" filelist_tree_add_item_recur: pos = '%s'\n", pos); + log(" filelist_tree_add_item_recur: first_part = '%s'\n", first_part); + log(" filelist_tree_add_item_recur: last_part = '%s'\n", last_part); + + if (! last_part) + { // final destination, create new item here + log(" filelist_tree_add_item_recur: creating new item here.\n"); + struct PathTree *t = (struct PathTree*)malloc(sizeof(struct PathTree)); + memset(t, 0, sizeof(struct PathTree)); + t->items = NULL; + t->data = item; + t->index = index; + t->node = strdup(path); + if (t->data) t->data->sFileName = strdup(path); + // create new list of subitems and add new item + if (! tree->items) tree->items = g_ptr_array_new(); + g_ptr_array_add(tree->items, t); + } else + { // find parent node or create new one if doesn't exist + log(" filelist_tree_add_item_recur: node '%s', path '%s'\n", tree->node, path); + if (! tree->items) tree->items = g_ptr_array_new(); + + struct PathTree *node = NULL; + if (tree->items->len > 0) { + unsigned int i; + for (i = 0; i < tree->items->len; i++) + { + struct PathTree* t = (struct PathTree*)g_ptr_array_index(tree->items, i); + if (strcmp(t->node, first_part) == 0) { + log(" filelist_tree_add_item_recur: found node '%s'\n", t->node); + node = t; + break; + } + } + } + + // create new path holder node + if (! node) { + log(" filelist_tree_add_item_recur: parent node not found, creating new path holder\n"); + node = (struct PathTree*)malloc(sizeof(struct PathTree)); + memset(node, 0, sizeof(struct PathTree)); + node->items = g_ptr_array_new(); + node->index = 0; + node->node = strdup(first_part); + + // create placeholder data + node->data = (struct TVFSItem*)malloc(sizeof(struct TVFSItem)); + memset(node->data, 0, sizeof(struct TVFSItem)); + node->data->sFileName = strdup(node->node); + node->data->ItemType = vDirectory; + node->data->iMode = S_IRWXO + S_IRWXG + S_IRWXU; + node->data->iUID = geteuid(); + node->data->iGID = getegid(); + node->data->m_time = time(NULL); + node->data->c_time = node->data->m_time; + node->data->a_time = node->data->m_time; + + g_ptr_array_add(tree->items, node); + } + + // and recurse one level deeper + filelist_tree_add_item_recurr(node, last_part, item, index); + } + + free(first_part); + free(last_part); +} + + +gboolean filelist_tree_add_item(struct PathTree *tree, const char *path, struct TVFSItem *item, unsigned long index) +{ + if (! tree) { + fprintf(stderr, "filelist_tree_add_item: tree == NULL !\n"); + return FALSE; + } + if (! path) { + fprintf(stderr, "filelist_tree_add_item: path == NULL !\n"); + return FALSE; + } + + if ((strcmp(path, "/") == 0) || (strcmp(path, ".") == 0) || (strcmp(path, "..") == 0)) { + fprintf(stderr, "filelist_tree_add_item: path '%s' is not a valid path\n", path); + return FALSE; + } + + // remove leading and trailing '/' if present + char *p; + if (IS_DIR_SEP(*path)) p = exclude_trailing_path_sep(path + 1); + else p = exclude_trailing_path_sep(path); + log(" filelist_tree_add_item: p = '%s'\n", p); + + struct PathTree* found = filelist_tree_find_node_by_path(tree, p); + + if (found) + { // replace old data with current ones (record might have been created automatically during path building) + log(" filelist_tree_add_item: found old item, replacing data\n"); + found->index = index; + // free old data + if (found->data) free_vfs_item(found->data); + found->data = item; + if (found->data) found->data->sFileName = strdup(found->node); + } else + // create new item recursively + filelist_tree_add_item_recurr(tree, p, item, index); + + free(p); + return TRUE; +} + +struct PathTree* filelist_tree_get_item_by_index(struct PathTree *tree, unsigned long index) +{ + struct PathTree* t = NULL; + if ((tree) && (tree->items) && (tree->items->len > index)) { + t = (struct PathTree*)g_ptr_array_index(tree->items, index); + } + return t; +} + |
