From: Junio C Hamano Date: Fri, 4 Sep 2015 17:43:23 +0000 (-0700) Subject: Sync with 2.4.9 X-Git-Tag: v2.5.2~1 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/3d3caf0b78106c390fc5daceb95ee968312765dd?ds=inline;hp=-c Sync with 2.4.9 --- 3d3caf0b78106c390fc5daceb95ee968312765dd diff --combined Documentation/git.txt index 5a78d77533,97d9fb41b2..3b5573d191 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@@ -43,15 -43,10 +43,16 @@@ unreleased) version of Git, that is ava branch of the `git.git` repository. Documentation for older releases are available here: +* link:v2.5.1/git.html[documentation for release 2.5.1] + +* release notes for + link:RelNotes/2.5.1.txt[2.5.1], + link:RelNotes/2.5.0.txt[2.5]. + - * link:v2.4.8/git.html[documentation for release 2.4.8] + * link:v2.4.9/git.html[documentation for release 2.4.9] * release notes for + link:RelNotes/2.4.9.txt[2.4.9], link:RelNotes/2.4.8.txt[2.4.8], link:RelNotes/2.4.7.txt[2.4.7], link:RelNotes/2.4.6.txt[2.4.6], @@@ -62,9 -57,10 +63,10 @@@ link:RelNotes/2.4.1.txt[2.4.1], link:RelNotes/2.4.0.txt[2.4]. - * link:v2.3.8/git.html[documentation for release 2.3.8] + * link:v2.3.9/git.html[documentation for release 2.3.9] * release notes for + link:RelNotes/2.3.9.txt[2.3.9], link:RelNotes/2.3.8.txt[2.3.8], link:RelNotes/2.3.7.txt[2.3.7], link:RelNotes/2.3.6.txt[2.3.6], @@@ -75,9 -71,10 +77,10 @@@ link:RelNotes/2.3.1.txt[2.3.1], link:RelNotes/2.3.0.txt[2.3]. - * link:v2.2.2/git.html[documentation for release 2.2.2] + * link:v2.2.3/git.html[documentation for release 2.2.3] * release notes for + link:RelNotes/2.2.3.txt[2.2.3], link:RelNotes/2.2.2.txt[2.2.2], link:RelNotes/2.2.1.txt[2.2.1], link:RelNotes/2.2.0.txt[2.2]. @@@ -782,7 -779,7 +785,7 @@@ The Git Repositor ~~~~~~~~~~~~~~~~~~ These environment variables apply to 'all' core Git commands. Nb: it is worth noting that they may be used/overridden by SCMS sitting above -Git so take care if using Cogito etc. +Git so take care if using a foreign front-end. 'GIT_INDEX_FILE':: This environment allows the specification of an alternate @@@ -848,15 -845,6 +851,15 @@@ an explicit repository directory set via 'GIT_DIR' or on the command line. +'GIT_COMMON_DIR':: + If this variable is set to a path, non-worktree files that are + normally in $GIT_DIR will be taken from this path + instead. Worktree-specific files such as HEAD or index are + taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and + linkgit:git-worktree[1] for + details. This variable has lower precedence than other path + variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY... + Git Commits ~~~~~~~~~~~ 'GIT_AUTHOR_NAME':: diff --combined builtin/show-branch.c index 323f857463,9b0aba2acc..344ae4ce2a --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@@ -369,10 -369,10 +369,10 @@@ static void sort_ref_range(int bottom, compare_ref_name); } -static int append_ref(const char *refname, const unsigned char *sha1, +static int append_ref(const char *refname, const struct object_id *oid, int allow_dups) { - struct commit *commit = lookup_commit_reference_gently(sha1, 1); + struct commit *commit = lookup_commit_reference_gently(oid->hash, 1); int i; if (!commit) @@@ -394,42 -394,39 +394,42 @@@ return 0; } -static int append_head_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +static int append_head_ref(const char *refname, const struct object_id *oid, + int flag, void *cb_data) { - unsigned char tmp[20]; + struct object_id tmp; int ofs = 11; if (!starts_with(refname, "refs/heads/")) return 0; /* If both heads/foo and tags/foo exists, get_sha1 would * get confused. */ - if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1)) + if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid)) ofs = 5; - return append_ref(refname + ofs, sha1, 0); + return append_ref(refname + ofs, oid, 0); } -static int append_remote_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +static int append_remote_ref(const char *refname, const struct object_id *oid, + int flag, void *cb_data) { - unsigned char tmp[20]; + struct object_id tmp; int ofs = 13; if (!starts_with(refname, "refs/remotes/")) return 0; /* If both heads/foo and tags/foo exists, get_sha1 would * get confused. */ - if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1)) + if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid)) ofs = 5; - return append_ref(refname + ofs, sha1, 0); + return append_ref(refname + ofs, oid, 0); } -static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +static int append_tag_ref(const char *refname, const struct object_id *oid, + int flag, void *cb_data) { if (!starts_with(refname, "refs/tags/")) return 0; - return append_ref(refname + 5, sha1, 0); + return append_ref(refname + 5, oid, 0); } static const char *match_ref_pattern = NULL; @@@ -443,8 -440,7 +443,8 @@@ static int count_slash(const char *s return cnt; } -static int append_matching_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +static int append_matching_ref(const char *refname, const struct object_id *oid, + int flag, void *cb_data) { /* we want to allow pattern hold/ to show all * branches under refs/heads/hold/, and v0.99.9? to show @@@ -460,23 -456,21 +460,23 @@@ if (wildmatch(match_ref_pattern, tail, 0, NULL)) return 0; if (starts_with(refname, "refs/heads/")) - return append_head_ref(refname, sha1, flag, cb_data); + return append_head_ref(refname, oid, flag, cb_data); if (starts_with(refname, "refs/tags/")) - return append_tag_ref(refname, sha1, flag, cb_data); - return append_ref(refname, sha1, 0); + return append_tag_ref(refname, oid, flag, cb_data); + return append_ref(refname, oid, 0); } static void snarf_refs(int head, int remotes) { if (head) { int orig_cnt = ref_name_cnt; + for_each_ref(append_head_ref, NULL); sort_ref_range(orig_cnt, ref_name_cnt); } if (remotes) { int orig_cnt = ref_name_cnt; + for_each_ref(append_remote_ref, NULL); sort_ref_range(orig_cnt, ref_name_cnt); } @@@ -536,15 -530,14 +536,15 @@@ static int show_independent(struct comm static void append_one_rev(const char *av) { - unsigned char revkey[20]; - if (!get_sha1(av, revkey)) { - append_ref(av, revkey, 0); + struct object_id revkey; + if (!get_sha1(av, revkey.hash)) { + append_ref(av, &revkey, 0); return; } if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) { /* glob style match */ int saved_matches = ref_name_cnt; + match_ref_pattern = av; match_ref_slash = count_slash(av); for_each_ref(append_matching_ref, NULL); @@@ -643,7 -636,7 +643,7 @@@ int cmd_show_branch(int ac, const char char head[128]; const char *head_p; int head_len; - unsigned char head_sha1[20]; + struct object_id head_oid; int merge_base = 0; int independent = 0; int no_name = 0; @@@ -725,12 -718,11 +725,11 @@@ } /* If nothing is specified, show all branches by default */ - if (ac + all_heads + all_remotes == 0) + if (ac <= topics && all_heads + all_remotes == 0) all_heads = 1; if (reflog) { - unsigned char sha1[20]; + struct object_id oid; - char nth_desc[256]; char *ref; int base = 0; unsigned int flags = 0; @@@ -740,7 -732,7 +739,7 @@@ fake_av[0] = resolve_refdup("HEAD", RESOLVE_REF_READING, - sha1, NULL); + oid.hash, NULL); fake_av[1] = NULL; av = fake_av; ac = 1; @@@ -751,7 -743,7 +750,7 @@@ if (MAX_REVS < reflog) die("Only %d entries can be shown at one time.", MAX_REVS); - if (!dwim_ref(*av, strlen(*av), sha1, &ref)) + if (!dwim_ref(*av, strlen(*av), oid.hash, &ref)) die("No such ref %s", *av); /* Has the base been specified? */ @@@ -762,18 -754,19 +761,19 @@@ /* Ah, that is a date spec... */ unsigned long at; at = approxidate(reflog_base); - read_ref_at(ref, flags, at, -1, sha1, NULL, + read_ref_at(ref, flags, at, -1, oid.hash, NULL, NULL, NULL, &base); } } for (i = 0; i < reflog; i++) { char *logmsg; + char *nth_desc; const char *msg; unsigned long timestamp; int tz; - if (read_ref_at(ref, flags, 0, base+i, sha1, &logmsg, + if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg, ×tamp, &tz, NULL)) { reflog = i; break; @@@ -787,22 -780,24 +787,24 @@@ show_date(timestamp, tz, 1), msg); free(logmsg); - sprintf(nth_desc, "%s@{%d}", *av, base+i); + + nth_desc = xstrfmt("%s@{%d}", *av, base+i); - append_ref(nth_desc, sha1, 1); + append_ref(nth_desc, &oid, 1); + free(nth_desc); } free(ref); } - else if (all_heads + all_remotes) - snarf_refs(all_heads, all_remotes); else { while (0 < ac) { append_one_rev(*av); ac--; av++; } + if (all_heads + all_remotes) + snarf_refs(all_heads, all_remotes); } head_p = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, - head_sha1, NULL); + head_oid.hash, NULL); if (head_p) { head_len = strlen(head_p); memcpy(head, head_p, head_len + 1); @@@ -821,7 -816,7 +823,7 @@@ if (rev_is_head(head, head_len, ref_name[i], - head_sha1, NULL)) + head_oid.hash, NULL)) has_head++; } if (!has_head) { @@@ -836,17 -831,17 +838,17 @@@ } for (num_rev = 0; ref_name[num_rev]; num_rev++) { - unsigned char revkey[20]; + struct object_id revkey; unsigned int flag = 1u << (num_rev + REV_SHIFT); if (MAX_REVS <= num_rev) die("cannot handle more than %d revs.", MAX_REVS); - if (get_sha1(ref_name[num_rev], revkey)) + if (get_sha1(ref_name[num_rev], revkey.hash)) die("'%s' is not a valid ref.", ref_name[num_rev]); - commit = lookup_commit_reference(revkey); + commit = lookup_commit_reference(revkey.hash); if (!commit) die("cannot find commit %s (%s)", - ref_name[num_rev], revkey); + ref_name[num_rev], oid_to_hex(&revkey)); parse_commit(commit); mark_seen(commit, &seen); @@@ -880,7 -875,7 +882,7 @@@ int is_head = rev_is_head(head, head_len, ref_name[i], - head_sha1, + head_oid.hash, rev[i]->object.sha1); if (extra < 0) printf("%c [%s] ", diff --combined notes.c index df08209dee,d465200541..eacd2a61da --- a/notes.c +++ b/notes.c @@@ -362,13 -362,14 +362,14 @@@ static int non_note_cmp(const struct no return strcmp(a->path, b->path); } - static void add_non_note(struct notes_tree *t, const char *path, + /* note: takes ownership of path string */ + static void add_non_note(struct notes_tree *t, char *path, unsigned int mode, const unsigned char *sha1) { struct non_note *p = t->prev_non_note, *n; n = (struct non_note *) xmalloc(sizeof(struct non_note)); n->next = NULL; - n->path = xstrdup(path); + n->path = path; n->mode = mode; hashcpy(n->sha1, sha1); t->prev_non_note = n; @@@ -482,17 -483,17 +483,17 @@@ handle_non_note * component. */ { - char non_note_path[PATH_MAX]; - char *p = non_note_path; + struct strbuf non_note_path = STRBUF_INIT; const char *q = sha1_to_hex(subtree->key_sha1); int i; for (i = 0; i < prefix_len; i++) { - *p++ = *q++; - *p++ = *q++; - *p++ = '/'; + strbuf_addch(&non_note_path, *q++); + strbuf_addch(&non_note_path, *q++); + strbuf_addch(&non_note_path, '/'); } - strcpy(p, entry.path); - add_non_note(t, non_note_path, entry.mode, entry.sha1); + strbuf_addstr(&non_note_path, entry.path); + add_non_note(t, strbuf_detach(&non_note_path, NULL), + entry.mode, entry.sha1); } } free(buf); @@@ -918,7 -919,7 +919,7 @@@ out return ret; } -static int string_list_add_one_ref(const char *refname, const unsigned char *sha1, +static int string_list_add_one_ref(const char *refname, const struct object_id *oid, int flag, void *cb) { struct string_list *refs = cb; diff --combined sha1_file.c index f2e993e0b8,99155c0d6b..17262e1826 --- a/sha1_file.c +++ b/sha1_file.c @@@ -377,15 -377,12 +377,12 @@@ void read_info_alternates(const char * char *map; size_t mapsz; struct stat st; - const char alt_file_name[] = "info/alternates"; - /* Given that relative_base is no longer than PATH_MAX, - ensure that "path" has enough space to append "/", the - file name, "info/alternates", and a trailing NUL. */ - char path[PATH_MAX + 1 + sizeof alt_file_name]; + char *path; int fd; - sprintf(path, "%s/%s", relative_base, alt_file_name); + path = xstrfmt("%s/info/alternates", relative_base); fd = git_open_noatime(path); + free(path); if (fd < 0) return; if (fstat(fd, &st) || (st.st_size == 0)) { @@@ -405,7 -402,7 +402,7 @@@ void add_to_alternates_file(const char { struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int fd = hold_lock_file_for_append(lock, git_path("objects/info/alternates"), LOCK_DIE_ON_ERROR); - char *alt = mkpath("%s\n", reference); + const char *alt = mkpath("%s\n", reference); write_or_die(fd, alt, strlen(alt)); if (commit_lock_file(lock)) die("could not close alternates file"); @@@ -1461,10 -1458,7 +1458,10 @@@ int git_open_noatime(const char *name static int sha1_file_open_flag = O_NOATIME; for (;;) { - int fd = open(name, O_RDONLY | sha1_file_open_flag); + int fd; + + errno = 0; + fd = open(name, O_RDONLY | sha1_file_open_flag); if (fd >= 0) return fd; @@@ -1582,40 -1576,6 +1579,40 @@@ int unpack_sha1_header(git_zstream *str return git_inflate(stream, 0); } +static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map, + unsigned long mapsize, void *buffer, + unsigned long bufsiz, struct strbuf *header) +{ + int status; + + status = unpack_sha1_header(stream, map, mapsize, buffer, bufsiz); + + /* + * Check if entire header is unpacked in the first iteration. + */ + if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer)) + return 0; + + /* + * buffer[0..bufsiz] was not large enough. Copy the partial + * result out to header, and then append the result of further + * reading the stream. + */ + strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer); + stream->next_out = buffer; + stream->avail_out = bufsiz; + + do { + status = git_inflate(stream, 0); + strbuf_add(header, buffer, stream->next_out - (unsigned char *)buffer); + if (memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer)) + return 0; + stream->next_out = buffer; + stream->avail_out = bufsiz; + } while (status != Z_STREAM_END); + return -1; +} + static void *unpack_sha1_rest(git_zstream *stream, void *buffer, unsigned long size, const unsigned char *sha1) { int bytes = strlen(buffer) + 1; @@@ -1666,38 -1626,27 +1663,38 @@@ * too permissive for what we want to check. So do an anal * object header parse by hand. */ -int parse_sha1_header(const char *hdr, unsigned long *sizep) +static int parse_sha1_header_extended(const char *hdr, struct object_info *oi, + unsigned int flags) { - char type[10]; - int i; + const char *type_buf = hdr; unsigned long size; + int type, type_len = 0; /* - * The type can be at most ten bytes (including the - * terminating '\0' that we add), and is followed by + * The type can be of any size but is followed by * a space. */ - i = 0; for (;;) { char c = *hdr++; if (c == ' ') break; - type[i++] = c; - if (i >= sizeof(type)) - return -1; + type_len++; } - type[i] = 0; + + type = type_from_string_gently(type_buf, type_len, 1); + if (oi->typename) + strbuf_add(oi->typename, type_buf, type_len); + /* + * Set type to 0 if its an unknown object and + * we're obtaining the type using '--allow-unkown-type' + * option. + */ + if ((flags & LOOKUP_UNKNOWN_OBJECT) && (type < 0)) + type = 0; + else if (type < 0) + die("invalid object type"); + if (oi->typep) + *oi->typep = type; /* * The length must follow immediately, and be in canonical @@@ -1715,24 -1664,12 +1712,24 @@@ size = size * 10 + c; } } - *sizep = size; + + if (oi->sizep) + *oi->sizep = size; /* * The length must be followed by a zero byte */ - return *hdr ? -1 : type_from_string(type); + return *hdr ? -1 : type; +} + +int parse_sha1_header(const char *hdr, unsigned long *sizep) +{ + struct object_info oi; + + oi.sizep = sizep; + oi.typename = NULL; + oi.typep = NULL; + return parse_sha1_header_extended(hdr, &oi, LOOKUP_REPLACE_OBJECT); } static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1) @@@ -2597,15 -2534,13 +2594,15 @@@ struct packed_git *find_sha1_pack(cons } static int sha1_loose_object_info(const unsigned char *sha1, - struct object_info *oi) + struct object_info *oi, + int flags) { - int status; - unsigned long mapsize, size; + int status = 0; + unsigned long mapsize; void *map; git_zstream stream; char hdr[32]; + struct strbuf hdrbuf = STRBUF_INIT; if (oi->delta_base_sha1) hashclr(oi->delta_base_sha1); @@@ -2618,7 -2553,7 +2615,7 @@@ * return value implicitly indicates whether the * object even exists. */ - if (!oi->typep && !oi->sizep) { + if (!oi->typep && !oi->typename && !oi->sizep) { struct stat st; if (stat_sha1_file(sha1, &st) < 0) return -1; @@@ -2632,26 -2567,17 +2629,26 @@@ return -1; if (oi->disk_sizep) *oi->disk_sizep = mapsize; - if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) + if ((flags & LOOKUP_UNKNOWN_OBJECT)) { + if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0) + status = error("unable to unpack %s header with --allow-unknown-type", + sha1_to_hex(sha1)); + } else if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0) status = error("unable to unpack %s header", sha1_to_hex(sha1)); - else if ((status = parse_sha1_header(hdr, &size)) < 0) + if (status < 0) + ; /* Do nothing */ + else if (hdrbuf.len) { + if ((status = parse_sha1_header_extended(hdrbuf.buf, oi, flags)) < 0) + status = error("unable to parse %s header with --allow-unknown-type", + sha1_to_hex(sha1)); + } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0) status = error("unable to parse %s header", sha1_to_hex(sha1)); - else if (oi->sizep) - *oi->sizep = size; git_inflate_end(&stream); munmap(map, mapsize); - if (oi->typep) + if (status && oi->typep) *oi->typep = status; + strbuf_release(&hdrbuf); return 0; } @@@ -2660,7 -2586,6 +2657,7 @@@ int sha1_object_info_extended(const uns struct cached_object *co; struct pack_entry e; int rtype; + enum object_type real_type; const unsigned char *real = lookup_replace_object_extended(sha1, flags); co = find_cached_object(real); @@@ -2673,15 -2598,13 +2670,15 @@@ *(oi->disk_sizep) = 0; if (oi->delta_base_sha1) hashclr(oi->delta_base_sha1); + if (oi->typename) + strbuf_addstr(oi->typename, typename(co->type)); oi->whence = OI_CACHED; return 0; } if (!find_pack_entry(real, &e)) { /* Most likely it's a loose object. */ - if (!sha1_loose_object_info(real, oi)) { + if (!sha1_loose_object_info(real, oi, flags)) { oi->whence = OI_LOOSE; return 0; } @@@ -2692,18 -2615,9 +2689,18 @@@ return -1; } + /* + * packed_object_info() does not follow the delta chain to + * find out the real type, unless it is given oi->typep. + */ + if (oi->typename && !oi->typep) + oi->typep = &real_type; + rtype = packed_object_info(e.p, e.offset, oi); if (rtype < 0) { mark_bad_packed_object(e.p, real); + if (oi->typep == &real_type) + oi->typep = NULL; return sha1_object_info_extended(real, oi, 0); } else if (in_delta_base_cache(e.p, e.offset)) { oi->whence = OI_DBCACHED; @@@ -2714,10 -2628,6 +2711,10 @@@ oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA || rtype == OBJ_OFS_DELTA); } + if (oi->typename) + strbuf_addstr(oi->typename, typename(*oi->typep)); + if (oi->typep == &real_type) + oi->typep = NULL; return 0; } @@@ -3586,19 -3496,14 +3583,19 @@@ int for_each_packed_object(each_packed_ { struct packed_git *p; int r = 0; + int pack_errors = 0; prepare_packed_git(); for (p = packed_git; p; p = p->next) { if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local) continue; + if (open_pack_index(p)) { + pack_errors = 1; + continue; + } r = for_each_object_in_pack(p, cb, data); if (r) break; } - return r; + return r ? r : pack_errors; } diff --combined unpack-trees.c index d6cf84904f,17a5eeb6cd..6e9f75549d --- a/unpack-trees.c +++ b/unpack-trees.c @@@ -9,7 -9,6 +9,7 @@@ #include "refs.h" #include "attr.h" #include "split-index.h" +#include "dir.h" /* * Error messages expected by scripts out of plumbing commands such as @@@ -224,9 -223,6 +224,9 @@@ static int check_updates(struct unpack_ struct cache_entry *ce = index->cache[i]; if (ce->ce_flags & CE_UPDATE) { + if (ce->ce_flags & CE_WT_REMOVE) + die("BUG: both update and delete flags are set on %s", + ce->name); display_progress(progress, ++cnt); ce->ce_flags &= ~CE_UPDATE; if (o->update && !o->dry_run) { @@@ -296,7 -292,6 +296,7 @@@ static int apply_sparse_checkout(struc if (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o)) return -1; ce->ce_flags |= CE_WT_REMOVE; + ce->ce_flags &= ~CE_UPDATE; } if (was_skip_worktree && !ce_skip_worktree(ce)) { if (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) @@@ -1264,10 -1259,8 +1264,10 @@@ static int verify_uptodate_sparse(cons static void invalidate_ce_path(const struct cache_entry *ce, struct unpack_trees_options *o) { - if (ce) - cache_tree_invalidate_path(o->src_index, ce->name); + if (!ce) + return; + cache_tree_invalidate_path(o->src_index, ce->name); + untracked_cache_invalidate_path(o->src_index, ce->name); } /* @@@ -1441,15 -1434,18 +1441,18 @@@ static int verify_absent_1(const struc if (!len) return 0; else if (len > 0) { - char path[PATH_MAX + 1]; - memcpy(path, ce->name, len); - path[len] = 0; + char *path; + int ret; + + path = xmemdupz(ce->name, len); if (lstat(path, &st)) - return error("cannot stat '%s': %s", path, + ret = error("cannot stat '%s': %s", path, strerror(errno)); - - return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st, - error_type, o); + else + ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL, + &st, error_type, o); + free(path); + return ret; } else if (lstat(ce->name, &st)) { if (errno != ENOENT) return error("cannot stat '%s': %s", ce->name,