/* tla-project-tree.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2005 Canonical Limited * Authors: Robert Collins * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/bugs/panic.h" #include "hackerlab/bugs/exception.h" #include "hackerlab/vu/safe.h" #include "hackerlab/fs/cwd.h" #include "hackerlab/fs/file-names.h" #include "hackerlab/os/errno.h" #include "hackerlab/char/str.h" #include "hackerlab/vu/vu.h" #include "hackerlab/os/errno-to-string.h" #include "libfsutils/file-contents.h" #include "libawk/trim.h" #include "libarch/ancestry.h" #include "libarch/namespace.h" #include "libarch/patch-id.h" #include "libarch/patch-logs.h" #include "libarch/changelogs.h" #include "libarch/inv-ids.h" #include "libarch/invent.h" #include "libarch/project-tree.h" #include "libarch/null-project-tree.h" typedef arch_project_tree_t null_project_tree_t; static int null_project_tree_destructor (void * data); /* methods */ static void null_init (arch_project_tree_t * tree); static enum arch_id_tagging_method null_id_tagging_method (arch_project_tree_t * tree, enum arch_inventory_category * cat_var, int strict); static inventory_entry_t * null_path_id (arch_project_tree_t * tree, int * errn, t_uchar const * const path, struct stat * known_lstat); static void null_changeset_inventory_traveral (arch_project_tree_t * tree, struct arch_inventory_options * options, inv_callback callback, void * closure); arch_project_tree_vtable null_project_tree_vtable = { null_init, null_id_tagging_method, null_path_id, null_changeset_inventory_traveral, NULL, arch_project_tree_vtable_end }; /** * \brief is dir the root of a null project tree? * \return non zero on true. */ int null_project_tree_dir_is_root (void * context, t_uchar const * dir, arch_project_tree_t **out) { if (!safe_access ((t_uchar *)dir, F_OK)) { if (out) { *out = talloc (context, null_project_tree_t); talloc_set_destructor (*out, null_project_tree_destructor); (*out)->vtable = &null_project_tree_vtable; } return -1; } /* incompatible tree */ safe_printfmt (2, "null_project_tree_dir_is_root: inaccessible path: '%s'\n", dir); exit (2); } /** * \brief free a null project tree */ int null_project_tree_destructor (void * data) { arch_project_tree_t * tree = talloc_get_type (data, null_project_tree_t); if (!tree) Throw (exception (EINVAL, "invalid tree in null_project_tree_destructor")); arch_project_tree_finalise (tree); return 0; } /** * \brief find the id tagging method for a tree */ enum arch_id_tagging_method null_id_tagging_method (arch_project_tree_t * tree, enum arch_inventory_category * cat_var, int strict) { if (cat_var) { *cat_var = arch_inventory_source; } return arch_names_id_tagging; } /** * \brief see arch_project_tree_init */ void null_init (arch_project_tree_t * tree) { tree->untagged_is_source = 1; tree->tag_method = arch_names_id_tagging; /* no ids in real fs's */ } /** * \brief see arch_inventory_id */ inventory_entry_t * null_path_id (arch_project_tree_t * tree, int * errn, t_uchar const * const path, struct stat * known_lstat) { t_uchar * as_file = file_name_from_directory (0, (t_uchar *)path); t_uchar * answer_id = NULL; t_uchar * as_file_tail = NULL; inventory_entry_t * answer = NULL; t_uchar * fq_path = NULL; if (!as_file) goto enomem; as_file_tail = file_name_tail (0, as_file); if (!as_file_tail) goto enomem; fq_path = file_name_in_vicinity (0, tree->root, as_file); if (!fq_path) goto enomem; answer_id = str_alloc_cat (0, "?", as_file); if (!answer_id) { enomem: *errn = ENOMEM; error: lim_free (0, fq_path); lim_free (0, as_file); lim_free (0, as_file_tail); lim_free (0, answer_id); return 0; } /* FIXME RBC 20050331 make this cleaner and only-called once */ { struct stat stat_buf; struct stat *thestat; if (known_lstat) thestat = known_lstat; else { thestat = &stat_buf; if (vu_lstat (errn, fq_path, thestat)) { goto error; } } if (S_ISDIR (thestat->st_mode)) answer = inventory_dir_new (NULL, as_file_tail, answer_id); else if (S_ISLNK (thestat->st_mode)) answer = inventory_link_new (NULL, as_file_tail, answer_id); else answer = inventory_file_new (NULL, as_file_tail, answer_id); } lim_free (0, fq_path); lim_free (0, answer_id); lim_free (0, as_file_tail); return answer; } /** * \brief see arch_project_tree_changeset_inventory_traversal */ void null_changeset_inventory_traveral (arch_project_tree_t * tree, struct arch_inventory_options * options, inv_callback callback, void * closure) { arch_inventory_traversal (options, tree, callback, closure); }