Add `get_tree_entry_gently()`, `find_tree_entry_gently()`
and `get_tree_entry_follow_symlinks_gently()`, which will
make `get_oid()` to be more gently.

Since `get_tree_entry()` is used in more than 20 places,
adding a new parameter will make this commit harder to read.
In every place it is called there will need to be an additional
0 parameter at the end of the call. The solution to avoid this is
to rename the function in `get_tree_entry_gently()` which gets
an additional `flags` variable. A new `get_tree_entry()`
will call `get_tree_entry_gently()` with `flags` being 0.
This way, no additional changes will be needed.

Signed-off-by: Paul-Sebastian Ungureanu <[email protected]>
---
 sha1-name.c |   2 +-
 tree-walk.c | 108 +++++++++++++++++++++++++++++++++++++++++++---------
 tree-walk.h |   3 +-
 3 files changed, 94 insertions(+), 19 deletions(-)

diff --git a/sha1-name.c b/sha1-name.c
index 60d9ef3c7..d741e1129 100644
--- a/sha1-name.c
+++ b/sha1-name.c
@@ -1721,7 +1721,7 @@ static int get_oid_with_context_1(const char *name,
                        if (flags & GET_OID_FOLLOW_SYMLINKS) {
                                ret = get_tree_entry_follow_symlinks(&tree_oid,
                                        filename, oid, &oc->symlink_path,
-                                       &oc->mode);
+                                       &oc->mode, flags);
                        } else {
                                ret = get_tree_entry(&tree_oid, filename, oid,
                                                     &oc->mode);
diff --git a/tree-walk.c b/tree-walk.c
index 8f5090862..2925eaec2 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -491,7 +491,9 @@ struct dir_state {
        struct object_id oid;
 };
 
-static int find_tree_entry(struct tree_desc *t, const char *name, struct 
object_id *result, unsigned *mode)
+static int find_tree_entry(struct tree_desc *t, const char *name,
+                                 struct object_id *result, unsigned *mode,
+                                 int flags)
 {
        int namelen = strlen(name);
        while (t->size) {
@@ -501,7 +503,11 @@ static int find_tree_entry(struct tree_desc *t, const char 
*name, struct object_
 
                oid = tree_entry_extract(t, &entry, mode);
                entrylen = tree_entry_len(&t->entry);
-               update_tree_entry(t);
+
+               if (!(flags & GET_OID_GENTLY))
+                       update_tree_entry(t);
+               else if (update_tree_entry_gently(t))
+                       return -1;
                if (entrylen > namelen)
                        continue;
                cmp = memcmp(name, entry, entrylen);
@@ -521,19 +527,28 @@ static int find_tree_entry(struct tree_desc *t, const 
char *name, struct object_
                        oidcpy(result, oid);
                        return 0;
                }
-               return get_tree_entry(oid, name + entrylen, result, mode);
+               return get_tree_entry_gently(oid, name + entrylen, result, 
mode, flags);
        }
        return -1;
 }
 
-int get_tree_entry(const struct object_id *tree_oid, const char *name, struct 
object_id *oid, unsigned *mode)
+int get_tree_entry_gently(const struct object_id *tree_oid, const char *name,
+                         struct object_id *oid, unsigned *mode, int flags)
 {
        int retval;
        void *tree;
        unsigned long size;
        struct object_id root;
 
-       tree = read_object_with_reference(tree_oid, tree_type, &size, &root);
+       if (!(flags & GET_OID_GENTLY)) {
+               tree = read_object_with_reference(tree_oid, tree_type, &size, 
&root);
+       } else {
+               struct object_info oi = OBJECT_INFO_INIT;
+
+               oi.contentp = tree;
+               if (oid_object_info_extended(the_repository, tree_oid, &oi, 0) 
< 0)
+                       return -1;
+       }
        if (!tree)
                return -1;
 
@@ -547,13 +562,27 @@ int get_tree_entry(const struct object_id *tree_oid, 
const char *name, struct ob
                retval = -1;
        } else {
                struct tree_desc t;
-               init_tree_desc(&t, tree, size);
-               retval = find_tree_entry(&t, name, oid, mode);
+               if (!(flags & GET_OID_GENTLY)) {
+                       init_tree_desc(&t, tree, size);
+               } else {
+                       if (init_tree_desc_gently(&t, tree, size)) {
+                               retval = -1;
+                               goto done;
+                       }
+               }
+               retval = find_tree_entry(&t, name, oid, mode, flags);
        }
+done:
        free(tree);
        return retval;
 }
 
+int get_tree_entry(const struct object_id *tree_oid, const char *name,
+                  struct object_id *oid, unsigned *mode)
+{
+       return get_tree_entry_gently(tree_oid, name, oid, mode, 0);
+}
+
 /*
  * This is Linux's built-in max for the number of symlinks to follow.
  * That limit, of course, does not affect git, but it's a reasonable
@@ -576,7 +605,7 @@ int get_tree_entry(const struct object_id *tree_oid, const 
char *name, struct ob
  * See the code for enum follow_symlink_result for a description of
  * the return values.
  */
-enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id 
*tree_oid, const char *name, struct object_id *result, struct strbuf 
*result_path, unsigned *mode)
+enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id 
*tree_oid, const char *name, struct object_id *result, struct strbuf 
*result_path, unsigned *mode, int flags)
 {
        int retval = MISSING_OBJECT;
        struct dir_state *parents = NULL;
@@ -600,9 +629,21 @@ enum follow_symlinks_result 
get_tree_entry_follow_symlinks(struct object_id *tre
                        void *tree;
                        struct object_id root;
                        unsigned long size;
-                       tree = read_object_with_reference(&current_tree_oid,
-                                                         tree_type, &size,
-                                                         &root);
+                       if (!(flags & GET_OID_GENTLY)) {
+                               tree = 
read_object_with_reference(&current_tree_oid,
+                                                                 tree_type, 
&size,
+                                                                 &root);
+                       } else {
+                               struct object_info oi = OBJECT_INFO_INIT;
+
+                               oi.contentp = tree;
+                               if (oid_object_info_extended(the_repository,
+                                   &current_tree_oid, &oi, 0) < 0) {
+                                       retval = MISSING_OBJECT;
+                                       goto done;
+                               }
+                       }
+
                        if (!tree)
                                goto done;
 
@@ -622,7 +663,14 @@ enum follow_symlinks_result 
get_tree_entry_follow_symlinks(struct object_id *tre
                                goto done;
 
                        /* descend */
-                       init_tree_desc(&t, tree, size);
+                       if (!(flags & GET_OID_GENTLY)) {
+                               init_tree_desc(&t, tree, size);
+                       } else {
+                               if (init_tree_desc_gently(&t, tree, size)) {
+                                       retval = MISSING_OBJECT;
+                                       goto done;
+                               }
+                       }
                }
 
                /* Handle symlinks to e.g. a//b by removing leading slashes */
@@ -656,7 +704,15 @@ enum follow_symlinks_result 
get_tree_entry_follow_symlinks(struct object_id *tre
                        free(parent->tree);
                        parents_nr--;
                        parent = &parents[parents_nr - 1];
-                       init_tree_desc(&t, parent->tree, parent->size);
+                       if (!(flags & GET_OID_GENTLY)) {
+                               init_tree_desc(&t, parent->tree, parent->size);
+                       } else {
+                               if (init_tree_desc_gently(&t, parent->tree,
+                                   parent->size)) {
+                                       retval = MISSING_OBJECT;
+                                       goto done;
+                               }
+                       }
                        strbuf_remove(&namebuf, 0, remainder ? 3 : 2);
                        continue;
                }
@@ -670,7 +726,7 @@ enum follow_symlinks_result 
get_tree_entry_follow_symlinks(struct object_id *tre
 
                /* Look up the first (or only) path component in the tree. */
                find_result = find_tree_entry(&t, namebuf.buf,
-                                             &current_tree_oid, mode);
+                                             &current_tree_oid, mode, flags);
                if (find_result) {
                        goto done;
                }
@@ -713,8 +769,19 @@ enum follow_symlinks_result 
get_tree_entry_follow_symlinks(struct object_id *tre
                         */
                        retval = DANGLING_SYMLINK;
 
-                       contents = read_object_file(&current_tree_oid, &type,
-                                                   &link_len);
+                       if (!(flags & GET_OID_GENTLY)) {
+                               contents = read_object_file(&current_tree_oid,
+                                                           &type, &link_len);
+                       } else {
+                               struct object_info oi = OBJECT_INFO_INIT;
+                               oi.contentp = (void*) contents;
+
+                               if (oid_object_info_extended(the_repository,
+                                   &current_tree_oid, &oi, 0) < 0) {
+                                       retval = MISSING_OBJECT;
+                                       goto done;
+                               }
+                       }
 
                        if (!contents)
                                goto done;
@@ -735,7 +802,14 @@ enum follow_symlinks_result 
get_tree_entry_follow_symlinks(struct object_id *tre
                        contents_start = contents;
 
                        parent = &parents[parents_nr - 1];
-                       init_tree_desc(&t, parent->tree, parent->size);
+                       if (!(flags & GET_OID_GENTLY)) {
+                               init_tree_desc(&t, parent->tree, parent->size);
+                       } else {
+                               if (init_tree_desc_gently(&t, parent->tree, 
parent->size)) {
+                                       retval = MISSING_OBJECT;
+                                       goto done;
+                               }
+                       }
                        strbuf_splice(&namebuf, 0, len,
                                      contents_start, link_len);
                        if (remainder)
diff --git a/tree-walk.h b/tree-walk.h
index 805f58f00..6f043af6e 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -64,7 +64,7 @@ enum follow_symlinks_result {
                       */
 };
 
-enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id 
*tree_oid, const char *name, struct object_id *result, struct strbuf 
*result_path, unsigned *mode);
+enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id 
*tree_oid, const char *name, struct object_id *result, struct strbuf 
*result_path, unsigned *mode, int flags);
 
 struct traverse_info {
        const char *traverse_path;
@@ -79,6 +79,7 @@ struct traverse_info {
        int show_all_errors;
 };
 
+int get_tree_entry_gently(const struct object_id *, const char *, struct 
object_id *, unsigned *, int);
 int get_tree_entry(const struct object_id *, const char *, struct object_id *, 
unsigned *);
 extern char *make_traverse_path(char *path, const struct traverse_info *info, 
const struct name_entry *n);
 extern void setup_traverse_info(struct traverse_info *info, const char *base);
-- 
2.18.0.rc2.184.ga79db55c2.dirty

Reply via email to