/* changeset-utils.c: * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2003 Tom Lord * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/os/errno.h" #include "hackerlab/os/errno-to-string.h" #include "hackerlab/fmt/cvt.h" #include "hackerlab/mem/mem.h" #include "hackerlab/mem/talloc.h" #include "hackerlab/char/char-class.h" #include "hackerlab/char/str.h" #include "hackerlab/char/pika-escaping-utils.h" #include "hackerlab/fs/file-names.h" #include "hackerlab/vu/safe.h" #include "po/gettext.h" #include "libfsutils/read-line.h" #include "libfsutils/safety.h" #include "libarch/diffs.h" #include "libarch/invent.h" #include "libarch/changeset-utils.h" /* __STDC__ prototypes for static functions */ static void changeset_inv_callback (void * closure, invent_callback_data_t const * const data); static void cset_free (void *data); void arch_changeset_inventory (struct arch_changeset_inventory * inv_out, arch_project_tree_t *tree, enum arch_id_tagging_method method, enum arch_inventory_category untagged_source_category, int escape_classes) { int here_fd; struct arch_inventory_options options; here_fd = safe_open (".", O_RDONLY, 0); mem_set0 ((t_uchar *)&options, sizeof (options)); options.categories = arch_inventory_source; options.want_ids = 1; options.treat_unrecognized_source_as_source = 1; if (method != arch_unspecified_id_tagging) { options.method = method; options.untagged_source_category = untagged_source_category; options.override_method = 1; } options.nested = 0; options.include_excluded = 1; arch_get_inventory_naming_conventions (&options, tree); inv_out->method = options.method; inv_out->escape_classes = escape_classes; safe_chdir (tree->root); arch_project_tree_changeset_inventory_traversal (tree, &options, changeset_inv_callback, inv_out); arch_free_inventory_naming_conventions (&options); rel_sort_table_by_field (0, inv_out->dirs, 1); rel_sort_table_by_field (0, inv_out->files, 1); safe_fchdir (here_fd); safe_close (here_fd); } void arch_free_changeset_inventory_data (struct arch_changeset_inventory * i) { rel_free_table (i->dirs); i->dirs = 0; rel_free_table (i->files); i->files = 0; cset_map_free (i->entries); i->entries = NULL; } rel_table arch_read_changeset_index (t_uchar * path) { int in_fd; rel_table answer = 0; t_uchar * line; long len; in_fd = safe_open (path, O_RDONLY, 0); while (1) { t_uchar * loc; t_uchar * id; t_uchar * start; line = 0; len = 0; safe_next_line (&line, &len, in_fd); if (!len) break; while (len && char_is_space (*line)) { ++line; --len; } start = line; while (len && !char_is_space (*line)) { ++line; --len; } if (line == start) { syntax_error: safe_printfmt (2, "illegally formed changeset index (%s)\n", path); exit (2); } loc = pika_save_unescape_iso8859_1_n (0, 0, start, line - start ); while (len && char_is_space (*line)) { ++line; --len; } start = line; while (len && !char_is_space (*line)) { ++line; --len; } if (line == start) goto syntax_error; id = pika_save_unescape_iso8859_1_n (0, 0, start, line - start ); while (len && char_is_space (*line)) { ++line; --len; } if (len) goto syntax_error; if (!is_non_upwards_relative_path (loc)) { safe_printfmt (2, "illegal path in changeset: %s\n", loc); exit (2); } rel_add_records (&answer, rel_make_record (loc, id, 0), 0); lim_free (0, loc); lim_free (0, id); } safe_close (in_fd); return answer; } rel_table arch_read_changeset_dir_metadata (t_uchar * path) { int errn; int in_fd; rel_table answer = 0; in_fd = vu_open (&errn, path, O_RDONLY, 0); if (in_fd < 0) { if (errn == ENOENT) return 0; else { safe_printfmt (2, "arch_read_changeset_dir_metadata: unable to open file (%s)\n", path); safe_printfmt (2, " %s\n", errno_to_string (errn)); exit (2); } } while (1) { t_uchar * line; long len; t_uchar * start; t_uchar * perms = 0; t_uchar * loc = 0; line = 0; len = 0; safe_next_line (&line, &len, in_fd); if (!len) break; while (len && char_is_space (*line)) { ++line; --len; } if ((len < 13) || str_cmp_prefix ("--permissions", line)) { syntax_error: safe_printfmt (2, "illegal dir metadata file: %s\n", path); exit (2); } len -= 13; line += 13; while (len && char_is_space (*line)) { ++line; --len; } start = line; while (len && !char_is_space (*line)) { ++line; --len; } if (start == line) goto syntax_error; perms = pika_save_unescape_iso8859_1_n (0, 0, start, line - start ); while (len && char_is_space (*line)) { ++line; --len; } start = line; while (len && !char_is_space (*line)) { ++line; --len; } if (start == line) goto syntax_error; loc = pika_save_unescape_iso8859_1_n (0, 0, start, line - start ); if (!is_non_upwards_relative_path (loc)) { safe_printfmt (2, "illegal path in changeset: %s\n", loc); exit (2); } rel_add_records (&answer, rel_make_record (loc, perms, 0), 0); lim_free (0, perms); lim_free (0, loc); } safe_close (in_fd); rel_sort_table_by_field (0, answer, 0); return answer; } mode_t arch_read_permissions_patch (t_uchar * file) { int errn; t_uchar * line = 0; t_uchar * s; t_uchar * e; t_ulong answer; line = read_line_from_file (file); s = line; while (char_is_space (*s)) ++s; if (str_cmp_prefix ("--permissions", s)) { syntax_error: safe_printfmt (2, "illegal metadata patch file: %s\n", file); exit (2); } s += sizeof ("--permissions") - 1; while (char_is_space (*s)) ++s; for (e = s; char_is_odigit (*e); ++e) ; if (e == s) goto syntax_error; if (cvt_octal_to_ulong (&errn, &answer, s, e - s)) goto syntax_error; lim_free (0, line); return (mode_t)answer; } void changeset_inv_callback (void * closure, invent_callback_data_t const * const data) { struct arch_changeset_inventory * index; index = (struct arch_changeset_inventory *)closure; if (!data->id) { t_uchar * dir = 0; dir = file_name_directory_file (0, data->path); if (!arch_is_dont_care_explicit_dflt_dir (dir)) { t_uchar * e_path = 0; e_path = pika_save_escape_iso8859_1 (0, 0, index->escape_classes, data->path); safe_printfmt (2, _("missing explicit id for file (try status --lint)\n file:%s\n"), e_path); exit (2); } lim_free (0, dir); return; } if (S_ISDIR (data->stat_buf.st_mode)) rel_add_records (&index->dirs, rel_make_record (data->path, data->id, 0), 0); else rel_add_records (&index->files, rel_make_record (data->path, data->id, 0), 0); cset_map_insert (&index->entries, data->id, arch_changeset_inventory_entry_new (&data->stat_buf)); } char * no_dot (char *name) { if (name[0] == '.' && name[1] == '/') return name + 2; else return name; } arch_changeset_inventory_entry_t * arch_changeset_inventory_entry_new (struct stat const * const stat_buf) { arch_changeset_inventory_entry_t * result = talloc (NULL, arch_changeset_inventory_entry_t); result->stat_buf = *stat_buf; return result; } void cset_free (void *data) { talloc_free (data); } void cset_map_insert (cset_map * vtable, t_uchar const * key, arch_changeset_inventory_entry_t *entry) { pointer_map_insert ((pointer_map *)vtable, key, entry, cset_free); } void cset_map_free (cset_map vtable) { pointer_map_free ((pointer_map)vtable, cset_free); } arch_changeset_inventory_entry_t * cset_map_find (cset_map vtable, t_uchar const * key) { return pointer_map_find ((pointer_map) vtable, key); } /* tag: Tom Lord Thu May 15 13:00:33 2003 (changeset-utils.c) */