5 static const char *get_mode(const char *str
, unsigned int *modep
)
13 while ((c
= *str
++) != ' ') {
14 if (c
< '0' || c
> '7')
16 mode
= (mode
<< 3) + (c
- '0');
22 static void decode_tree_entry(struct tree_desc
*desc
, const char *buf
, unsigned long size
)
25 unsigned int mode
, len
;
27 if (size
< 24 || buf
[size
- 21])
28 die("corrupt tree file");
30 path
= get_mode(buf
, &mode
);
32 die("corrupt tree file");
33 len
= strlen(path
) + 1;
35 /* Initialize the descriptor entry */
36 desc
->entry
.path
= path
;
37 desc
->entry
.mode
= mode
;
38 desc
->entry
.sha1
= (const unsigned char *)(path
+ len
);
41 void init_tree_desc(struct tree_desc
*desc
, const void *buffer
, unsigned long size
)
43 desc
->buffer
= buffer
;
46 decode_tree_entry(desc
, buffer
, size
);
49 void *fill_tree_descriptor(struct tree_desc
*desc
, const unsigned char *sha1
)
51 unsigned long size
= 0;
55 buf
= read_object_with_reference(sha1
, tree_type
, &size
, NULL
);
57 die("unable to read tree %s", sha1_to_hex(sha1
));
59 init_tree_desc(desc
, buf
, size
);
63 static int entry_compare(struct name_entry
*a
, struct name_entry
*b
)
65 return df_name_compare(
66 a
->path
, tree_entry_len(a
->path
, a
->sha1
), a
->mode
,
67 b
->path
, tree_entry_len(b
->path
, b
->sha1
), b
->mode
);
70 static void entry_clear(struct name_entry
*a
)
72 memset(a
, 0, sizeof(*a
));
75 static void entry_extract(struct tree_desc
*t
, struct name_entry
*a
)
80 void update_tree_entry(struct tree_desc
*desc
)
82 const void *buf
= desc
->buffer
;
83 const unsigned char *end
= desc
->entry
.sha1
+ 20;
84 unsigned long size
= desc
->size
;
85 unsigned long len
= end
- (const unsigned char *)buf
;
88 die("corrupt tree file");
94 decode_tree_entry(desc
, buf
, size
);
97 int tree_entry(struct tree_desc
*desc
, struct name_entry
*entry
)
102 *entry
= desc
->entry
;
103 update_tree_entry(desc
);
107 void setup_traverse_info(struct traverse_info
*info
, const char *base
)
109 int pathlen
= strlen(base
);
110 static struct traverse_info dummy
;
112 memset(info
, 0, sizeof(*info
));
113 if (pathlen
&& base
[pathlen
-1] == '/')
115 info
->pathlen
= pathlen
? pathlen
+ 1 : 0;
116 info
->name
.path
= base
;
117 info
->name
.sha1
= (void *)(base
+ pathlen
+ 1);
122 char *make_traverse_path(char *path
, const struct traverse_info
*info
, const struct name_entry
*n
)
124 int len
= tree_entry_len(n
->path
, n
->sha1
);
125 int pathlen
= info
->pathlen
;
127 path
[pathlen
+ len
] = 0;
129 memcpy(path
+ pathlen
, n
->path
, len
);
132 path
[--pathlen
] = '/';
134 len
= tree_entry_len(n
->path
, n
->sha1
);
141 int traverse_trees(int n
, struct tree_desc
*t
, struct traverse_info
*info
)
144 struct name_entry
*entry
= xmalloc(n
*sizeof(*entry
));
147 unsigned long mask
= 0;
148 unsigned long dirmask
= 0;
152 for (i
= 0; i
< n
; i
++) {
155 entry_extract(t
+i
, entry
+i
);
157 int cmp
= entry_compare(entry
+i
, entry
+last
);
160 * Is the new name bigger than the old one?
166 * Is the new name smaller than the old one?
167 * Ignore all old ones
173 if (S_ISDIR(entry
[i
].mode
))
182 * Clear all the unused name-entries.
184 for (i
= 0; i
< n
; i
++) {
185 if (mask
& (1ul << i
))
187 entry_clear(entry
+ i
);
189 ret
= info
->fn(n
, mask
, dirmask
, entry
, info
);
195 for (i
= 0; i
< n
; i
++) {
196 if (mask
& (1ul << i
))
197 update_tree_entry(t
+ i
);
204 static int find_tree_entry(struct tree_desc
*t
, const char *name
, unsigned char *result
, unsigned *mode
)
206 int namelen
= strlen(name
);
209 const unsigned char *sha1
;
212 sha1
= tree_entry_extract(t
, &entry
, mode
);
213 update_tree_entry(t
);
214 entrylen
= tree_entry_len(entry
, sha1
);
215 if (entrylen
> namelen
)
217 cmp
= memcmp(name
, entry
, entrylen
);
222 if (entrylen
== namelen
) {
223 hashcpy(result
, sha1
);
226 if (name
[entrylen
] != '/')
230 if (++entrylen
== namelen
) {
231 hashcpy(result
, sha1
);
234 return get_tree_entry(sha1
, name
+ entrylen
, result
, mode
);
239 int get_tree_entry(const unsigned char *tree_sha1
, const char *name
, unsigned char *sha1
, unsigned *mode
)
245 unsigned char root
[20];
247 tree
= read_object_with_reference(tree_sha1
, tree_type
, &size
, root
);
251 if (name
[0] == '\0') {
256 init_tree_desc(&t
, tree
, size
);
257 retval
= find_tree_entry(&t
, name
, sha1
, mode
);