Code

combined diff: correctly handle truncated file
[git.git] / t / t4100 / t-apply-3.patch
1 6af1f0192ff8740fe77db7cf02c739ccfbdf119c (from 2bc2564145835996734d6ed5d1880f85b17233d6)
2 diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
3 --- a/Documentation/git-ls-tree.txt
4 +++ b/Documentation/git-ls-tree.txt
5 @@ -4,23 +4,26 @@ v0.1, May 2005
6  
7  NAME
8  ----
9 -git-ls-tree - Displays a tree object in human readable form
10 +git-ls-tree - Lists the contents of a tree object.
11  
12  
13  SYNOPSIS
14  --------
15 -'git-ls-tree' [-r] [-z] <tree-ish> [paths...]
16 +'git-ls-tree' [-d] [-r] [-z] <tree-ish> [paths...]
17  
18  DESCRIPTION
19  -----------
20 -Converts the tree object to a human readable (and script processable)
21 -form.
22 +Lists the contents of a tree object, like what "/bin/ls -a" does
23 +in the current working directory.
24  
25  OPTIONS
26  -------
27  <tree-ish>::
28         Id of a tree.
29  
30 +-d::
31 +       show only the named tree entry itself, not its children
32 +
33  -r::
34         recurse into sub-trees
35  
36 @@ -28,18 +31,19 @@ OPTIONS
37         \0 line termination on output
38  
39  paths::
40 -       Optionally, restrict the output of git-ls-tree to specific
41 -       paths. Directories will only list their tree blob ids.
42 -       Implies -r.
43 +       When paths are given, shows them.  Otherwise implicitly
44 +       uses the root level of the tree as the sole path argument.
45 +
46  
47  Output Format
48  -------------
49 -        <mode>\t       <type>\t        <object>\t      <file>
50 +        <mode> SP <type> SP <object> TAB <file>
51  
52  
53  Author
54  ------
55  Written by Linus Torvalds <torvalds@osdl.org>
56 +Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>
57  
58  Documentation
59  --------------
60 diff --git a/ls-tree.c b/ls-tree.c
61 dissimilarity index 82%
62 --- ls-tree.c
63 +++ ls-tree.c
64 @@ -1,212 +1,247 @@
65 -/*
66 - * GIT - The information manager from hell
67 - *
68 - * Copyright (C) Linus Torvalds, 2005
69 - */
70 -#include "cache.h"
71 -
72 -static int line_termination = '\n';
73 -static int recursive = 0;
74 -
75 -struct path_prefix {
76 -       struct path_prefix *prev;
77 -       const char *name;
78 -};
79 -
80 -#define DEBUG(fmt, ...)        
81 -
82 -static int string_path_prefix(char *buff, size_t blen, struct path_prefix *prefix)
83 -{
84 -       int len = 0;
85 -       if (prefix) {
86 -               if (prefix->prev) {
87 -                       len = string_path_prefix(buff,blen,prefix->prev);
88 -                       buff += len;
89 -                       blen -= len;
90 -                       if (blen > 0) {
91 -                               *buff = '/';
92 -                               len++;
93 -                               buff++;
94 -                               blen--;
95 -                       }
96 -               }
97 -               strncpy(buff,prefix->name,blen);
98 -               return len + strlen(prefix->name);
99 -       }
101 -       return 0;
102 -}
104 -static void print_path_prefix(struct path_prefix *prefix)
105 -{
106 -       if (prefix) {
107 -               if (prefix->prev) {
108 -                       print_path_prefix(prefix->prev);
109 -                       putchar('/');
110 -               }
111 -               fputs(prefix->name, stdout);
112 -       }
113 -}
115 -/*
116 - * return:
117 - *     -1 if prefix is *not* a subset of path
118 - *      0 if prefix == path
119 - *      1 if prefix is a subset of path
120 - */
121 -static int pathcmp(const char *path, struct path_prefix *prefix)
122 -{
123 -       char buff[PATH_MAX];
124 -       int len,slen;
126 -       if (prefix == NULL)
127 -               return 1;
129 -       len = string_path_prefix(buff, sizeof buff, prefix);
130 -       slen = strlen(path);
132 -       if (slen < len)
133 -               return -1;
135 -       if (strncmp(path,buff,len) == 0) {
136 -               if (slen == len)
137 -                       return 0;
138 -               else
139 -                       return 1;
140 -       }
142 -       return -1;
143 -}      
145 -/*
146 - * match may be NULL, or a *sorted* list of paths
147 - */
148 -static void list_recursive(void *buffer,
149 -                          const char *type,
150 -                          unsigned long size,
151 -                          struct path_prefix *prefix,
152 -                          char **match, int matches)
153 -{
154 -       struct path_prefix this_prefix;
155 -       this_prefix.prev = prefix;
157 -       if (strcmp(type, "tree"))
158 -               die("expected a 'tree' node");
160 -       if (matches)
161 -               recursive = 1;
163 -       while (size) {
164 -               int namelen = strlen(buffer)+1;
165 -               void *eltbuf = NULL;
166 -               char elttype[20];
167 -               unsigned long eltsize;
168 -               unsigned char *sha1 = buffer + namelen;
169 -               char *path = strchr(buffer, ' ') + 1;
170 -               unsigned int mode;
171 -               const char *matched = NULL;
172 -               int mtype = -1;
173 -               int mindex;
175 -               if (size < namelen + 20 || sscanf(buffer, "%o", &mode) != 1)
176 -                       die("corrupt 'tree' file");
177 -               buffer = sha1 + 20;
178 -               size -= namelen + 20;
180 -               this_prefix.name = path;
181 -               for ( mindex = 0; mindex < matches; mindex++) {
182 -                       mtype = pathcmp(match[mindex],&this_prefix);
183 -                       if (mtype >= 0) {
184 -                               matched = match[mindex];
185 -                               break;
186 -                       }
187 -               }
189 -               /*
190 -                * If we're not matching, or if this is an exact match,
191 -                * print out the info
192 -                */
193 -               if (!matches || (matched != NULL && mtype == 0)) {
194 -                       printf("%06o %s %s\t", mode,
195 -                              S_ISDIR(mode) ? "tree" : "blob",
196 -                              sha1_to_hex(sha1));
197 -                       print_path_prefix(&this_prefix);
198 -                       putchar(line_termination);
199 -               }
201 -               if (! recursive || ! S_ISDIR(mode))
202 -                       continue;
204 -               if (matches && ! matched)
205 -                       continue;
207 -               if (! (eltbuf = read_sha1_file(sha1, elttype, &eltsize)) ) {
208 -                       error("cannot read %s", sha1_to_hex(sha1));
209 -                       continue;
210 -               }
212 -               /* If this is an exact directory match, we may have
213 -                * directory files following this path. Match on them.
214 -                * Otherwise, we're at a pach subcomponent, and we need
215 -                * to try to match again.
216 -                */
217 -               if (mtype == 0)
218 -                       mindex++;
220 -               list_recursive(eltbuf, elttype, eltsize, &this_prefix, &match[mindex], matches-mindex);
221 -               free(eltbuf);
222 -       }
223 -}
225 -static int qcmp(const void *a, const void *b)
226 -{
227 -       return strcmp(*(char **)a, *(char **)b);
228 -}
230 -static int list(unsigned char *sha1,char **path)
231 -{
232 -       void *buffer;
233 -       unsigned long size;
234 -       int npaths;
236 -       for (npaths = 0; path[npaths] != NULL; npaths++)
237 -               ;
239 -       qsort(path,npaths,sizeof(char *),qcmp);
241 -       buffer = read_object_with_reference(sha1, "tree", &size, NULL);
242 -       if (!buffer)
243 -               die("unable to read sha1 file");
244 -       list_recursive(buffer, "tree", size, NULL, path, npaths);
245 -       free(buffer);
246 -       return 0;
247 -}
249 -static const char *ls_tree_usage = "git-ls-tree [-r] [-z] <key> [paths...]";
251 -int main(int argc, char **argv)
252 -{
253 -       unsigned char sha1[20];
255 -       while (1 < argc && argv[1][0] == '-') {
256 -               switch (argv[1][1]) {
257 -               case 'z':
258 -                       line_termination = 0;
259 -                       break;
260 -               case 'r':
261 -                       recursive = 1;
262 -                       break;
263 -               default:
264 -                       usage(ls_tree_usage);
265 -               }
266 -               argc--; argv++;
267 -       }
269 -       if (argc < 2)
270 -               usage(ls_tree_usage);
271 -       if (get_sha1(argv[1], sha1) < 0)
272 -               usage(ls_tree_usage);
273 -       if (list(sha1, &argv[2]) < 0)
274 -               die("list failed");
275 -       return 0;
276 -}
277 +/*
278 + * GIT - The information manager from hell
279 + *
280 + * Copyright (C) Linus Torvalds, 2005
281 + */
282 +#include "cache.h"
283 +#include "blob.h"
284 +#include "tree.h"
286 +static int line_termination = '\n';
287 +#define LS_RECURSIVE 1
288 +#define LS_TREE_ONLY 2
289 +static int ls_options = 0;
291 +static struct tree_entry_list root_entry;
293 +static void prepare_root(unsigned char *sha1)
294 +{
295 +       unsigned char rsha[20];
296 +       unsigned long size;
297 +       void *buf;
298 +       struct tree *root_tree;
300 +       buf = read_object_with_reference(sha1, "tree", &size, rsha);
301 +       free(buf);
302 +       if (!buf)
303 +               die("Could not read %s", sha1_to_hex(sha1));
305 +       root_tree = lookup_tree(rsha);
306 +       if (!root_tree)
307 +               die("Could not read %s", sha1_to_hex(sha1));
309 +       /* Prepare a fake entry */
310 +       root_entry.directory = 1;
311 +       root_entry.executable = root_entry.symlink = 0;
312 +       root_entry.mode = S_IFDIR;
313 +       root_entry.name = "";
314 +       root_entry.item.tree = root_tree;
315 +       root_entry.parent = NULL;
316 +}
318 +static int prepare_children(struct tree_entry_list *elem)
319 +{
320 +       if (!elem->directory)
321 +               return -1;
322 +       if (!elem->item.tree->object.parsed) {
323 +               struct tree_entry_list *e;
324 +               if (parse_tree(elem->item.tree))
325 +                       return -1;
326 +               /* Set up the parent link */
327 +               for (e = elem->item.tree->entries; e; e = e->next)
328 +                       e->parent = elem;
329 +       }
330 +       return 0;
331 +}
333 +static struct tree_entry_list *find_entry_0(struct tree_entry_list *elem,
334 +                                           const char *path,
335 +                                           const char *path_end)
336 +{
337 +       const char *ep;
338 +       int len;
340 +       while (path < path_end) {
341 +               if (prepare_children(elem))
342 +                       return NULL;
344 +               /* In elem->tree->entries, find the one that has name
345 +                * that matches what is between path and ep.
346 +                */
347 +               elem = elem->item.tree->entries;
349 +               ep = strchr(path, '/');
350 +               if (!ep || path_end <= ep)
351 +                       ep = path_end;
352 +               len = ep - path;
354 +               while (elem) {
355 +                       if ((strlen(elem->name) == len) &&
356 +                           !strncmp(elem->name, path, len))
357 +                               break;
358 +                       elem = elem->next;
359 +               }
360 +               if (path_end <= ep || !elem)
361 +                       return elem;
362 +               while (*ep == '/' && ep < path_end)
363 +                       ep++;
364 +               path = ep;
365 +       }
366 +       return NULL;
367 +}
369 +static struct tree_entry_list *find_entry(const char *path,
370 +                                         const char *path_end)
371 +{
372 +       /* Find tree element, descending from root, that
373 +        * corresponds to the named path, lazily expanding
374 +        * the tree if possible.
375 +        */
376 +       if (path == path_end) {
377 +               /* Special.  This is the root level */
378 +               return &root_entry;
379 +       }
380 +       return find_entry_0(&root_entry, path, path_end);
381 +}
383 +static void show_entry_name(struct tree_entry_list *e)
384 +{
385 +       /* This is yucky.  The root level is there for
386 +        * our convenience but we really want to do a
387 +        * forest.
388 +        */
389 +       if (e->parent && e->parent != &root_entry) {
390 +               show_entry_name(e->parent);
391 +               putchar('/');
392 +       }
393 +       printf("%s", e->name);
394 +}
396 +static const char *entry_type(struct tree_entry_list *e)
397 +{
398 +       return (e->directory ? "tree" : "blob");
399 +}
401 +static const char *entry_hex(struct tree_entry_list *e)
402 +{
403 +       return sha1_to_hex(e->directory
404 +                          ? e->item.tree->object.sha1
405 +                          : e->item.blob->object.sha1);
406 +}
408 +/* forward declaration for mutually recursive routines */
409 +static int show_entry(struct tree_entry_list *, int);
411 +static int show_children(struct tree_entry_list *e, int level)
412 +{
413 +       if (prepare_children(e))
414 +               die("internal error: ls-tree show_children called with non tree");
415 +       e = e->item.tree->entries;
416 +       while (e) {
417 +               show_entry(e, level);
418 +               e = e->next;
419 +       }
420 +       return 0;
421 +}
423 +static int show_entry(struct tree_entry_list *e, int level)
424 +{
425 +       int err = 0; 
427 +       if (e != &root_entry) {
428 +               printf("%06o %s %s      ", e->mode, entry_type(e),
429 +                      entry_hex(e));
430 +               show_entry_name(e);
431 +               putchar(line_termination);
432 +       }
434 +       if (e->directory) {
435 +               /* If this is a directory, we have the following cases:
436 +                * (1) This is the top-level request (explicit path from the
437 +                *     command line, or "root" if there is no command line).
438 +                *  a. Without any flag.  We show direct children.  We do not 
439 +                *     recurse into them.
440 +                *  b. With -r.  We do recurse into children.
441 +                *  c. With -d.  We do not recurse into children.
442 +                * (2) We came here because our caller is either (1-a) or
443 +                *     (1-b).
444 +                *  a. Without any flag.  We do not show our children (which
445 +                *     are grandchildren for the original request).
446 +                *  b. With -r.  We continue to recurse into our children.
447 +                *  c. With -d.  We should not have come here to begin with.
448 +                */
449 +               if (level == 0 && !(ls_options & LS_TREE_ONLY))
450 +                       /* case (1)-a and (1)-b */
451 +                       err = err | show_children(e, level+1);
452 +               else if (level && ls_options & LS_RECURSIVE)
453 +                       /* case (2)-b */
454 +                       err = err | show_children(e, level+1);
455 +       }
456 +       return err;
457 +}
459 +static int list_one(const char *path, const char *path_end)
460 +{
461 +       int err = 0;
462 +       struct tree_entry_list *e = find_entry(path, path_end);
463 +       if (!e) {
464 +               /* traditionally ls-tree does not complain about
465 +                * missing path.  We may change this later to match
466 +                * what "/bin/ls -a" does, which is to complain.
467 +                */
468 +               return err;
469 +       }
470 +       err = err | show_entry(e, 0);
471 +       return err;
472 +}
474 +static int list(char **path)
475 +{
476 +       int i;
477 +       int err = 0;
478 +       for (i = 0; path[i]; i++) {
479 +               int len = strlen(path[i]);
480 +               while (0 <= len && path[i][len] == '/')
481 +                       len--;
482 +               err = err | list_one(path[i], path[i] + len);
483 +       }
484 +       return err;
485 +}
487 +static const char *ls_tree_usage =
488 +       "git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
490 +int main(int argc, char **argv)
491 +{
492 +       static char *path0[] = { "", NULL };
493 +       char **path;
494 +       unsigned char sha1[20];
496 +       while (1 < argc && argv[1][0] == '-') {
497 +               switch (argv[1][1]) {
498 +               case 'z':
499 +                       line_termination = 0;
500 +                       break;
501 +               case 'r':
502 +                       ls_options |= LS_RECURSIVE;
503 +                       break;
504 +               case 'd':
505 +                       ls_options |= LS_TREE_ONLY;
506 +                       break;
507 +               default:
508 +                       usage(ls_tree_usage);
509 +               }
510 +               argc--; argv++;
511 +       }
513 +       if (argc < 2)
514 +               usage(ls_tree_usage);
515 +       if (get_sha1(argv[1], sha1) < 0)
516 +               usage(ls_tree_usage);
518 +       path = (argc == 2) ? path0 : (argv + 2);
519 +       prepare_root(sha1);
520 +       if (list(path) < 0)
521 +               die("list failed");
522 +       return 0;
523 +}
524 diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh
525 --- a/t/t3100-ls-tree-restrict.sh
526 +++ b/t/t3100-ls-tree-restrict.sh
527 @@ -74,8 +74,8 @@ test_expect_success \
528      'ls-tree filtered' \
529      'git-ls-tree $tree path1 path0 >current &&
530       cat >expected <<\EOF &&
531 -100644 blob X  path0
532  120000 blob X  path1
533 +100644 blob X  path0
534  EOF
535       test_output'
536  
537 @@ -85,7 +85,6 @@ test_expect_success \
538       cat >expected <<\EOF &&
539  040000 tree X  path2
540  040000 tree X  path2/baz
541 -100644 blob X  path2/baz/b
542  120000 blob X  path2/bazbo
543  100644 blob X  path2/foo
544  EOF
545 diff --git a/tree.c b/tree.c
546 --- a/tree.c
547 +++ b/tree.c
548 @@ -133,7 +133,7 @@ int parse_tree_buffer(struct tree *item,
549                 }
550                 if (obj)
551                         add_ref(&item->object, obj);
553 +               entry->parent = NULL; /* needs to be filled by the user */
554                 *list_p = entry;
555                 list_p = &entry->next;
556         }
557 diff --git a/tree.h b/tree.h
558 --- a/tree.h
559 +++ b/tree.h
560 @@ -16,6 +16,7 @@ struct tree_entry_list {
561                 struct tree *tree;
562                 struct blob *blob;
563         } item;
564 +       struct tree_entry_list *parent;
565  };
566  
567  struct tree {