static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) { struct tree_desc desc; struct name_entry entry; int cnt; hashcpy(it->sha1, tree->object.sha1); init_tree_desc(&desc, tree->buffer, tree->size); cnt = 0; while (tree_entry(&desc, &entry)) { if (!S_ISDIR(entry.mode)) cnt++; else { struct cache_tree_sub *sub; struct tree *subtree = lookup_tree(entry.sha1); if (!subtree->object.parsed) parse_tree(subtree); sub = cache_tree_sub(it, entry.path); sub->cache_tree = cache_tree(); prime_cache_tree_rec(sub->cache_tree, subtree); cnt += sub->cache_tree->entry_count; } } it->entry_count = cnt; }
static int process_tree(struct walker *walker, struct tree *tree) { struct tree_desc desc; struct name_entry entry; if (parse_tree(tree)) return -1; init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { struct object *obj = NULL; /* submodule commits are not stored in the superproject */ if (S_ISGITLINK(entry.mode)) continue; if (S_ISDIR(entry.mode)) { struct tree *tree = lookup_tree(entry.sha1); if (tree) obj = &tree->object; } else { struct blob *blob = lookup_blob(entry.sha1); if (blob) obj = &blob->object; } if (!obj || process(walker, obj)) return -1; } free(tree->buffer); tree->buffer = NULL; tree->size = 0; tree->object.parsed = 0; return 0; }
inline comm_tree_t* comm_tree_getComm(tree_node_t* node) { if(node == NULL) return NULL; return tree_entry(node, comm_tree_t, node); }
static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data) { struct tree_desc desc; struct name_entry entry; int res = 0; if (parse_tree(tree)) return -1; init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { int result; if (S_ISGITLINK(entry.mode)) continue; if (S_ISDIR(entry.mode)) result = walk(&lookup_tree(entry.sha1)->object, OBJ_TREE, data); else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) result = walk(&lookup_blob(entry.sha1)->object, OBJ_BLOB, data); else { result = error("in tree %s: entry %s has bad mode %.6o\n", sha1_to_hex(tree->object.sha1), entry.path, entry.mode); } if (result < 0) return result; if (!res) res = result; } return res; }
static int grep_tree(struct grep_opt *opt, const char **paths, struct tree_desc *tree, const char *tree_name, const char *base) { int len; int hit = 0; struct name_entry entry; char *down; int tn_len = strlen(tree_name); struct strbuf pathbuf; strbuf_init(&pathbuf, PATH_MAX + tn_len); if (tn_len) { strbuf_add(&pathbuf, tree_name, tn_len); strbuf_addch(&pathbuf, ':'); tn_len = pathbuf.len; } strbuf_addstr(&pathbuf, base); len = pathbuf.len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); pathbuf.len = len; strbuf_add(&pathbuf, entry.path, te_len); if (S_ISDIR(entry.mode)) /* Match "abc/" against pathspec to * decide if we want to descend into "abc" * directory. */ strbuf_addch(&pathbuf, '/'); down = pathbuf.buf + tn_len; if (!pathspec_matches(paths, down, opt->max_depth)) ; else if (S_ISREG(entry.mode)) hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; void *data; unsigned long size; data = lock_and_read_sha1_file(entry.sha1, &type, &size); if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); init_tree_desc(&sub, data, size); hit |= grep_tree(opt, paths, &sub, tree_name, down); free(data); } if (hit && opt->status_only) break; } strbuf_release(&pathbuf); return hit; }
static inline vres_event_t *vres_event_lookup(vres_event_group_t *group, vres_event_desc_t *desc) { rbtree_node_t *node = NULL; if (!rbtree_find(&group->tree, desc, &node)) return tree_entry(node, vres_event_t, node); else return NULL; }
/* * Inspect two trees, and give a score that tells how similar they are. */ static int score_trees(const unsigned char *hash1, const unsigned char *hash2) { struct tree_desc one; struct tree_desc two; void *one_buf = fill_tree_desc_strict(&one, hash1); void *two_buf = fill_tree_desc_strict(&two, hash2); int score = 0; for (;;) { struct name_entry e1, e2; int got_entry_from_one = tree_entry(&one, &e1); int got_entry_from_two = tree_entry(&two, &e2); int cmp; if (got_entry_from_one && got_entry_from_two) cmp = base_name_entries_compare(&e1, &e2); else if (got_entry_from_one) /* two lacks this entry */ cmp = -1; else if (got_entry_from_two) /* two has more entries */ cmp = 1; else break; if (cmp < 0) /* path1 does not appear in two */ score += score_missing(e1.mode, e1.path); else if (cmp > 0) /* path2 does not appear in one */ score += score_missing(e2.mode, e2.path); else if (hashcmp(e1.sha1, e2.sha1)) /* they are different */ score += score_differs(e1.mode, e2.mode, e1.path); else /* same subtree or blob */ score += score_matches(e1.mode, e2.mode, e1.path); } free(one_buf); free(two_buf); return score; }
static inline vres_file_t *vres_file_lookup_file(const char *path) { vres_file_t *file = NULL; rbtree_node_t *node = NULL; pthread_rwlock_rdlock(&vres_file_flock); if (!rbtree_find(&vres_file_ftree, path, &node)) file = tree_entry(node, vres_file_t, f_node); pthread_rwlock_unlock(&vres_file_flock); return file; }
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len, int check_attr) { int hit = 0; enum interesting match = entry_not_interesting; struct name_entry entry; int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(&entry); if (match != all_entries_interesting) { match = tree_entry_interesting(&entry, base, tn_len, pathspec); if (match == all_entries_not_interesting) break; if (match == entry_not_interesting) continue; } strbuf_add(base, entry.path, te_len); if (S_ISREG(entry.mode)) { hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len, check_attr ? base->buf + tn_len : NULL); } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; void *data; unsigned long size; data = lock_and_read_sha1_file(entry.sha1, &type, &size); if (!data) die(_("unable to read tree (%s)"), sha1_to_hex(entry.sha1)); strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); hit |= grep_tree(opt, pathspec, &sub, base, tn_len, check_attr); free(data); } strbuf_setlen(base, old_baselen); if (hit && opt->status_only) break; } return hit; }
static inline void vres_file_delete_file(const char *path) { vres_file_t *file = NULL; rbtree_node_t *node = NULL; pthread_rwlock_wrlock(&vres_file_flock); if (!rbtree_find(&vres_file_ftree, path, &node)) { file = tree_entry(node, vres_file_t, f_node); rbtree_remove_node(&vres_file_ftree, node); } pthread_rwlock_unlock(&vres_file_flock); if (file) free(file); log_file_delete_file(path); }
int vres_file_release_dir(vres_file_dir_t *dir) { int ret = 0; pthread_rwlock_wrlock(&dir->d_lock); while (dir->d_count > 0) { char *name; size_t len; rbtree_node_t *node; vres_file_name_t *ptr; char path[FILE_PATH_MAX]; node = dir->d_tree.root; if (!node) { log_err("invalid directory"); ret = -1; goto out; } name = (char *)node->key; len = strlen(name); if (!len || (len >= FILE_PATH_MAX)) { log_err("invalid path"); ret = -1; goto out; } ptr = tree_entry(node, vres_file_name_t, node); sprintf(path, "%s%s", dir->d_path, name); if (FILE_SEPARATOR == name[len - 1]) { if (vres_file_rmdir(path)) { log_err("failed to remove %s", path); ret = -1; goto out; } } else { vres_file_delete_file(path); rbtree_remove_node(&dir->d_tree, node); dir->d_count--; free(ptr); } } vres_file_delete_dir(dir->d_path); out: pthread_rwlock_unlock(&dir->d_lock); if (!ret) free(dir); return ret; }
int read_tree_recursive(struct tree *tree, const char *base, int baselen, int stage, const char **match, read_tree_fn_t fn) { struct tree_desc desc; struct name_entry entry; if (parse_tree(tree)) return -1; init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { if (!match_tree_entry(base, baselen, entry.path, entry.mode, match)) continue; switch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage)) { case 0: continue; case READ_TREE_RECURSIVE: break;; default: return -1; } if (S_ISDIR(entry.mode)) { int retval; char *newbase; unsigned int pathlen = tree_entry_len(entry.path, entry.sha1); newbase = xmalloc(baselen + 1 + pathlen); memcpy(newbase, base, baselen); memcpy(newbase + baselen, entry.path, pathlen); newbase[baselen + pathlen] = '/'; retval = read_tree_recursive(lookup_tree(entry.sha1), newbase, baselen + pathlen + 1, stage, match, fn); free(newbase); if (retval) return -1; continue; } } return 0; }
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len) { int hit = 0, matched = 0; struct name_entry entry; int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); if (matched != 2) { matched = tree_entry_interesting(&entry, base, tn_len, pathspec); if (matched == -1) break; /* no more matches */ if (!matched) continue; } strbuf_add(base, entry.path, te_len); if (S_ISREG(entry.mode)) { hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len); } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; void *data; unsigned long size; data = lock_and_read_sha1_file(entry.sha1, &type, &size); if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); hit |= grep_tree(opt, pathspec, &sub, base, tn_len); free(data); } strbuf_setlen(base, old_baselen); if (hit && opt->status_only) break; } return hit; }
static void process_tree(struct rev_info *revs, struct tree *tree, struct object_array *p, struct name_path *path, const char *name) { struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; struct name_path me; if (!revs->tree_objects) return; if (!obj) die("bad tree object"); if (obj->flags & (UNINTERESTING | SEEN)) return; if (parse_tree(tree) < 0) die("bad tree object %s", sha1_to_hex(obj->sha1)); obj->flags |= SEEN; name = xstrdup(name); add_object(obj, p, path, name); me.up = path; me.elem = name; me.elem_len = strlen(name); init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), p, &me, entry.path); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, p, &me, entry.path); else process_blob(revs, lookup_blob(entry.sha1), p, &me, entry.path); } free(tree->buffer); tree->buffer = NULL; }
static int tree_is_complete(const struct object_id *oid) { struct tree_desc desc; struct name_entry entry; int complete; struct tree *tree; tree = lookup_tree(the_repository, oid); if (!tree) return 0; if (tree->object.flags & SEEN) return 1; if (tree->object.flags & INCOMPLETE) return 0; if (!tree->buffer) { enum object_type type; unsigned long size; void *data = read_object_file(oid, &type, &size); if (!data) { tree->object.flags |= INCOMPLETE; return 0; } tree->buffer = data; tree->size = size; } init_tree_desc(&desc, tree->buffer, tree->size); complete = 1; while (tree_entry(&desc, &entry)) { if (!has_object_file(&entry.oid) || (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) { tree->object.flags |= INCOMPLETE; complete = 0; } } free_tree_buffer(tree); if (complete) tree->object.flags |= SEEN; return complete; }
int vres_event_do_handle(vres_t *resource, rbtree_node_t *node, vres_event_callback_t func) { int ret; vres_event_t *event; if (!node) return 0; if (node->right) { ret = vres_event_do_handle(resource, node->right, func); if (ret) return ret; } if (node->left) { ret = vres_event_do_handle(resource, node->left, func); if (ret) return ret; } event = tree_entry(node, vres_event_t, node); return func(resource, event); }
void mark_tree_uninteresting(struct tree *tree) { struct tree_desc desc; struct name_entry entry; struct object *obj = &tree->object; if (!tree) return; if (obj->flags & UNINTERESTING) return; obj->flags |= UNINTERESTING; if (!has_sha1_file(obj->sha1)) return; if (parse_tree(tree) < 0) die("bad tree %s", sha1_to_hex(obj->sha1)); init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { switch (object_type(entry.mode)) { case OBJ_TREE: mark_tree_uninteresting(lookup_tree(entry.sha1)); break; case OBJ_BLOB: mark_blob_uninteresting(lookup_blob(entry.sha1)); break; default: /* Subproject commit - not in this repository */ break; } } /* * We don't care about the tree any more * after it has been marked uninteresting. */ free(tree->buffer); tree->buffer = NULL; }
static inline int vres_file_pop(char *path) { size_t len; char *filename; char dirname[FILE_PATH_MAX]; if (vres_file_dirname(path, dirname)) { log_err("invalid path, path=%s", path); return -1; } filename = path + strlen(dirname); len = strlen(filename); if ((len > 0) && (len + filename - path < FILE_PATH_MAX)) { vres_file_dir_t *dir = vres_file_lookup_dir(dirname); if (!dir) return -1; pthread_rwlock_wrlock(&dir->d_lock); if (dir->d_count > 0) { rbtree_node_t *node = NULL; if (!rbtree_find(&dir->d_tree, filename, &node)) { vres_file_name_t *name = tree_entry(node, vres_file_name_t, node); rbtree_remove_node(&dir->d_tree, node); dir->d_count--; free(name); } } pthread_rwlock_unlock(&dir->d_lock); } else { log_err("invalid path, path=%s", path); return -1; } return 0; }
static inline vres_file_dir_t *vres_file_lookup_dir(const char *path) { void *key = NULL; size_t len = strlen(path); rbtree_node_t *node = NULL; vres_file_dir_t *dir = NULL; char dirname[FILE_PATH_MAX] = {0}; if (FILE_SEPARATOR == path[len - 1]) key = (void *)path; else { if (FILE_PATH_MAX - 1 == len) { log_err("invalid path"); return NULL; } sprintf(dirname, "%s%c", path, FILE_SEPARATOR); key = (void *)dirname; } pthread_rwlock_rdlock(&vres_file_dlock); if (!rbtree_find(&vres_file_dtree, key, &node)) dir = tree_entry(node, vres_file_dir_t, d_node); pthread_rwlock_unlock(&vres_file_dlock); return dir; }
static int read_tree_1(struct tree *tree, struct strbuf *base, int stage, const struct pathspec *pathspec, read_tree_fn_t fn, void *context) { struct tree_desc desc; struct name_entry entry; unsigned char sha1[20]; int len, oldlen = base->len; enum interesting retval = entry_not_interesting; if (parse_tree(tree)) return -1; init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { if (retval != all_entries_interesting) { retval = tree_entry_interesting(&entry, base, 0, pathspec); if (retval == all_entries_not_interesting) break; if (retval == entry_not_interesting) continue; } switch (fn(entry.sha1, base, entry.path, entry.mode, stage, context)) { case 0: continue; case READ_TREE_RECURSIVE: break; default: return -1; } if (S_ISDIR(entry.mode)) hashcpy(sha1, entry.sha1); else if (S_ISGITLINK(entry.mode)) { struct commit *commit; commit = lookup_commit(entry.sha1); if (!commit) die("Commit %s in submodule path %s%s not found", sha1_to_hex(entry.sha1), base->buf, entry.path); if (parse_commit(commit)) die("Invalid commit %s in submodule path %s%s", sha1_to_hex(entry.sha1), base->buf, entry.path); hashcpy(sha1, commit->tree->object.sha1); } else continue; len = tree_entry_len(&entry); strbuf_add(base, entry.path, len); strbuf_addch(base, '/'); retval = read_tree_1(lookup_tree(sha1), base, stage, pathspec, fn, context); strbuf_setlen(base, oldlen); if (retval) return -1; } return 0; }
static void load_subtree(struct notes_tree *t, struct leaf_node *subtree, struct int_node *node, unsigned int n) { unsigned char object_sha1[20]; unsigned int prefix_len; void *buf; struct tree_desc desc; struct name_entry entry; int len, path_len; unsigned char type; struct leaf_node *l; buf = fill_tree_descriptor(&desc, subtree->val_sha1); if (!buf) die("Could not read %s for notes-index", sha1_to_hex(subtree->val_sha1)); prefix_len = subtree->key_sha1[19]; assert(prefix_len * 2 >= n); memcpy(object_sha1, subtree->key_sha1, prefix_len); while (tree_entry(&desc, &entry)) { path_len = strlen(entry.path); len = get_sha1_hex_segment(entry.path, path_len, object_sha1 + prefix_len, 20 - prefix_len); if (len < 0) goto handle_non_note; /* entry.path is not a SHA1 */ len += prefix_len; /* * If object SHA1 is complete (len == 20), assume note object * If object SHA1 is incomplete (len < 20), and current * component consists of 2 hex chars, assume note subtree */ if (len <= 20) { type = PTR_TYPE_NOTE; l = (struct leaf_node *) xcalloc(sizeof(struct leaf_node), 1); hashcpy(l->key_sha1, object_sha1); hashcpy(l->val_sha1, entry.sha1); if (len < 20) { if (!S_ISDIR(entry.mode) || path_len != 2) goto handle_non_note; /* not subtree */ l->key_sha1[19] = (unsigned char) len; type = PTR_TYPE_SUBTREE; } note_tree_insert(t, node, n, l, type, combine_notes_concatenate); } continue; handle_non_note: /* * Determine full path for this non-note entry: * The filename is already found in entry.path, but the * directory part of the path must be deduced from the subtree * containing this entry. We assume here that the overall notes * tree follows a strict byte-based progressive fanout * structure (i.e. using 2/38, 2/2/36, etc. fanouts, and not * e.g. 4/36 fanout). This means that if a non-note is found at * path "dead/beef", the following code will register it as * being found on "de/ad/beef". * On the other hand, if you use such non-obvious non-note * paths in the middle of a notes tree, you deserve what's * coming to you ;). Note that for non-notes that are not * SHA1-like at the top level, there will be no problems. * * To conclude, it is strongly advised to make sure non-notes * have at least one non-hex character in the top-level path * component. */ { char non_note_path[PATH_MAX]; char *p = non_note_path; const char *q = sha1_to_hex(subtree->key_sha1); int i; for (i = 0; i < prefix_len; i++) { *p++ = *q++; *p++ = *q++; *p++ = '/'; } strcpy(p, entry.path); add_non_note(t, non_note_path, entry.mode, entry.sha1); } } free(buf); }
void resolve_tree_islands(struct repository *r, int progress, struct packing_data *to_pack) { struct progress *progress_state = NULL; struct tree_islands_todo *todo; int nr = 0; int i; if (!island_marks) return; /* * We process only trees, as commits and tags have already been handled * (and passed their marks on to root trees, as well. We must make sure * to process them in descending tree-depth order so that marks * propagate down the tree properly, even if a sub-tree is found in * multiple parent trees. */ ALLOC_ARRAY(todo, to_pack->nr_objects); for (i = 0; i < to_pack->nr_objects; i++) { if (oe_type(&to_pack->objects[i]) == OBJ_TREE) { todo[nr].entry = &to_pack->objects[i]; todo[nr].depth = oe_tree_depth(to_pack, &to_pack->objects[i]); nr++; } } QSORT(todo, nr, tree_depth_compare); if (progress) progress_state = start_progress(_("Propagating island marks"), nr); for (i = 0; i < nr; i++) { struct object_entry *ent = todo[i].entry; struct island_bitmap *root_marks; struct tree *tree; struct tree_desc desc; struct name_entry entry; khiter_t pos; pos = kh_get_sha1(island_marks, ent->idx.oid.hash); if (pos >= kh_end(island_marks)) continue; root_marks = kh_value(island_marks, pos); tree = lookup_tree(r, &ent->idx.oid); if (!tree || parse_tree(tree) < 0) die(_("bad tree object %s"), oid_to_hex(&ent->idx.oid)); init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { struct object *obj; if (S_ISGITLINK(entry.mode)) continue; obj = lookup_object(r, entry.oid->hash); if (!obj) continue; set_island_marks(obj, root_marks); } free_tree_buffer(tree); display_progress(progress_state, i+1); } stop_progress(&progress_state); free(todo); }
static void process_tree(struct rev_info *revs, struct tree *tree, show_object_fn show, struct name_path *path, struct strbuf *base, const char *name) { struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; struct name_path me; int all_interesting = (revs->diffopt.pathspec.nr == 0); int baselen = base->len; if (!revs->tree_objects) return; if (!obj) die("bad tree object"); if (obj->flags & (UNINTERESTING | SEEN)) return; if (parse_tree(tree) < 0) die("bad tree object %s", sha1_to_hex(obj->sha1)); obj->flags |= SEEN; show(obj, path, name); me.up = path; me.elem = name; me.elem_len = strlen(name); if (!all_interesting) { strbuf_addstr(base, name); if (base->len) strbuf_addch(base, '/'); } init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { if (!all_interesting) { int showit = tree_entry_interesting(&entry, base, 0, &revs->diffopt.pathspec); if (showit < 0) break; else if (!showit) continue; else if (showit == 2) all_interesting = 1; } if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), show, &me, base, entry.path); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, show, &me, entry.path); else process_blob(revs, lookup_blob(entry.sha1), show, &me, entry.path); } strbuf_setlen(base, baselen); free(tree->buffer); tree->buffer = NULL; }
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len, int check_attr) { int hit = 0; enum interesting match = entry_not_interesting; struct name_entry entry; int old_baselen = base->len; struct strbuf name = STRBUF_INIT; int name_base_len = 0; if (super_prefix) { strbuf_addstr(&name, super_prefix); name_base_len = name.len; } while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(&entry); if (match != all_entries_interesting) { strbuf_addstr(&name, base->buf + tn_len); match = tree_entry_interesting(&entry, &name, 0, pathspec); strbuf_setlen(&name, name_base_len); if (match == all_entries_not_interesting) break; if (match == entry_not_interesting) continue; } strbuf_add(base, entry.path, te_len); if (S_ISREG(entry.mode)) { hit |= grep_sha1(opt, entry.oid->hash, base->buf, tn_len, check_attr ? base->buf + tn_len : NULL); } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; void *data; unsigned long size; data = lock_and_read_sha1_file(entry.oid->hash, &type, &size); if (!data) die(_("unable to read tree (%s)"), oid_to_hex(entry.oid)); strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); hit |= grep_tree(opt, pathspec, &sub, base, tn_len, check_attr); free(data); } else if (recurse_submodules && S_ISGITLINK(entry.mode)) { hit |= grep_submodule(opt, entry.oid->hash, base->buf, base->buf + tn_len); } strbuf_setlen(base, old_baselen); if (hit && opt->status_only) break; } strbuf_release(&name); return hit; }
static bool tree_read(struct view *view, struct buffer *buf) { struct tree_state *state = view->private; struct tree_entry *data; struct line *entry, *line; enum line_type type; char *path; size_t size; if (state->read_date || !buf) return tree_read_date(view, buf, state); if (buf->size <= SIZEOF_TREE_ATTR) return FALSE; if (view->lines == 0 && !tree_entry(view, LINE_HEADER, view->env->directory, NULL, NULL, 0)) return FALSE; size = parse_size(buf->data + SIZEOF_TREE_ATTR); path = strchr(buf->data + SIZEOF_TREE_ATTR, '\t'); if (!path) return FALSE; path++; /* Strip the path part ... */ if (*view->env->directory) { size_t pathlen = strlen(path); size_t striplen = strlen(view->env->directory); if (pathlen > striplen) memmove(path, path + striplen, pathlen - striplen + 1); /* Insert "link" to parent directory. */ if (view->lines == 1 && !tree_entry(view, LINE_DIRECTORY, "..", "040000", view->ref, 0)) return FALSE; } type = buf->data[SIZEOF_TREE_MODE] == 't' ? LINE_DIRECTORY : LINE_FILE; entry = tree_entry(view, type, path, buf->data, buf->data + TREE_ID_OFFSET, size); if (!entry) return FALSE; data = entry->data; view_column_info_update(view, entry); /* Skip "Directory ..." and ".." line. */ for (line = &view->line[1 + !!*view->env->directory]; line < entry; line++) { if (tree_compare_entry(line, entry) <= 0) continue; memmove(line + 1, line, (entry - line) * sizeof(*entry)); line->data = data; line->type = type; line->dirty = line->cleareol = 1; for (line++; line <= entry; line++) { line->dirty = line->cleareol = 1; line->lineno++; } return TRUE; } /* Move the current line to the first tree entry. */ if (!check_position(&view->prev_pos) && !check_position(&view->pos)) goto_view_line(view, 0, 1); return TRUE; }
static bool tree_read_date(struct view *view, struct buffer *buf, struct tree_state *state) { char *text = buf ? buf->data : NULL; if (!text && state->read_date) { state->read_date = FALSE; return TRUE; } else if (!text) { /* Find next entry to process */ const char *log_file[] = { "git", "log", encoding_arg, "--no-color", "--pretty=raw", "--cc", "--raw", view->ops->id, "--", "%(directory)", NULL }; if (!view->lines) { tree_entry(view, LINE_HEADER, view->env->directory, NULL, NULL, 0); tree_entry(view, LINE_DIRECTORY, "..", "040000", view->ref, 0); report("Tree is empty"); return TRUE; } if (!begin_update(view, repo.cdup, log_file, OPEN_EXTRA)) { report("Failed to load tree data"); return TRUE; } state->read_date = TRUE; return FALSE; } else if (*text == 'c' && get_line_type(text) == LINE_COMMIT) { string_copy_rev_from_commit_line(state->commit, text); } else if (*text == 'a' && get_line_type(text) == LINE_AUTHOR) { parse_author_line(text + STRING_SIZE("author "), &state->author, &state->author_time); } else if (*text == ':') { char *pos; size_t annotated = 1; size_t i; pos = strrchr(text, '\t'); if (!pos) return TRUE; text = pos + 1; if (*view->env->directory && !strncmp(text, view->env->directory, strlen(view->env->directory))) text += strlen(view->env->directory); pos = strchr(text, '/'); if (pos) *pos = 0; for (i = 1; i < view->lines; i++) { struct line *line = &view->line[i]; struct tree_entry *entry = line->data; annotated += !!entry->author; if (entry->author || strcmp(entry->name, text)) continue; string_copy_rev(entry->commit, state->commit); entry->author = state->author; entry->time = state->author_time; line->dirty = 1; view_column_info_update(view, line); break; } if (annotated == view->lines) io_kill(view->pipe); } return TRUE; }
static void load_subtree(struct notes_tree *t, struct leaf_node *subtree, struct int_node *node, unsigned int n) { struct object_id object_oid; size_t prefix_len; void *buf; struct tree_desc desc; struct name_entry entry; buf = fill_tree_descriptor(&desc, &subtree->val_oid); if (!buf) die("Could not read %s for notes-index", oid_to_hex(&subtree->val_oid)); prefix_len = subtree->key_oid.hash[KEY_INDEX]; if (prefix_len >= GIT_SHA1_RAWSZ) BUG("prefix_len (%"PRIuMAX") is out of range", (uintmax_t)prefix_len); if (prefix_len * 2 < n) BUG("prefix_len (%"PRIuMAX") is too small", (uintmax_t)prefix_len); memcpy(object_oid.hash, subtree->key_oid.hash, prefix_len); while (tree_entry(&desc, &entry)) { unsigned char type; struct leaf_node *l; size_t path_len = strlen(entry.path); if (path_len == 2 * (GIT_SHA1_RAWSZ - prefix_len)) { /* This is potentially the remainder of the SHA-1 */ if (!S_ISREG(entry.mode)) /* notes must be blobs */ goto handle_non_note; if (hex_to_bytes(object_oid.hash + prefix_len, entry.path, GIT_SHA1_RAWSZ - prefix_len)) goto handle_non_note; /* entry.path is not a SHA1 */ type = PTR_TYPE_NOTE; } else if (path_len == 2) { /* This is potentially an internal node */ size_t len = prefix_len; if (!S_ISDIR(entry.mode)) /* internal nodes must be trees */ goto handle_non_note; if (hex_to_bytes(object_oid.hash + len++, entry.path, 1)) goto handle_non_note; /* entry.path is not a SHA1 */ /* * Pad the rest of the SHA-1 with zeros, * except for the last byte, where we write * the length: */ memset(object_oid.hash + len, 0, GIT_SHA1_RAWSZ - len - 1); object_oid.hash[KEY_INDEX] = (unsigned char)len; type = PTR_TYPE_SUBTREE; } else { /* This can't be part of a note */ goto handle_non_note; } l = xcalloc(1, sizeof(*l)); oidcpy(&l->key_oid, &object_oid); oidcpy(&l->val_oid, &entry.oid); if (note_tree_insert(t, node, n, l, type, combine_notes_concatenate)) die("Failed to load %s %s into notes tree " "from %s", type == PTR_TYPE_NOTE ? "note" : "subtree", oid_to_hex(&l->key_oid), t->ref); continue; handle_non_note: /* * Determine full path for this non-note entry. The * filename is already found in entry.path, but the * directory part of the path must be deduced from the * subtree containing this entry based on our * knowledge that the overall notes tree follows a * strict byte-based progressive fanout structure * (i.e. using 2/38, 2/2/36, etc. fanouts). */ { struct strbuf non_note_path = STRBUF_INIT; const char *q = oid_to_hex(&subtree->key_oid); size_t i; for (i = 0; i < prefix_len; i++) { strbuf_addch(&non_note_path, *q++); strbuf_addch(&non_note_path, *q++); strbuf_addch(&non_note_path, '/'); } strbuf_addstr(&non_note_path, entry.path); add_non_note(t, strbuf_detach(&non_note_path, NULL), entry.mode, entry.oid.hash); } } free(buf); }
static void process_tree(struct rev_info *revs, struct tree *tree, show_object_fn show, struct strbuf *base, const char *name, void *cb_data) { struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; enum interesting match = revs->diffopt.pathspec.nr == 0 ? all_entries_interesting: entry_not_interesting; int baselen = base->len; if (!revs->tree_objects) return; if (!obj) die("bad tree object"); if (obj->flags & (UNINTERESTING | SEEN)) return; if (parse_tree_gently(tree, revs->ignore_missing_links) < 0) { if (revs->ignore_missing_links) return; die("bad tree object %s", oid_to_hex(&obj->oid)); } obj->flags |= SEEN; strbuf_addstr(base, name); show(obj, base->buf, cb_data); if (base->len) strbuf_addch(base, '/'); init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { if (match != all_entries_interesting) { match = tree_entry_interesting(&entry, base, 0, &revs->diffopt.pathspec); if (match == all_entries_not_interesting) break; if (match == entry_not_interesting) continue; } if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), show, base, entry.path, cb_data); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, show, base, entry.path, cb_data); else process_blob(revs, lookup_blob(entry.sha1), show, base, entry.path, cb_data); } strbuf_setlen(base, baselen); free_tree_buffer(tree); }