while ((e = readdir(dir)))
if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
- path_list_insert(xstrdup(e->d_name), list);
+ path_list_insert(e->d_name, list);
closedir(dir);
return 0;
}
+static int get_mode(const char *path, int *mode)
+{
+ struct stat st;
+
+ if (!path || !strcmp(path, "/dev/null"))
+ *mode = 0;
+ else if (!strcmp(path, "-"))
+ *mode = ntohl(create_ce_mode(0666));
+ else if (stat(path, &st))
+ return error("Could not access '%s'", path);
+ else
+ *mode = st.st_mode;
+ return 0;
+}
+
static int queue_diff(struct diff_options *o,
const char *name1, const char *name2)
{
- struct stat st;
int mode1 = 0, mode2 = 0;
- if (name1) {
- if (stat(name1, &st))
- return error("Could not access '%s'", name1);
- mode1 = st.st_mode;
- }
- if (name2) {
- if (stat(name2, &st))
- return error("Could not access '%s'", name2);
- mode2 = st.st_mode;
- }
+ if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
+ return -1;
if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
return error("file/directory conflict: %s, %s", name1, name2);
} else {
struct diff_filespec *d1, *d2;
- if (o->reverse_diff) {
+ if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
unsigned tmp;
const char *tmp_c;
tmp = mode1; mode1 = mode2; mode2 = tmp;
}
}
+/*
+ * Does the path name a blob in the working tree, or a directory
+ * in the working tree?
+ */
static int is_in_index(const char *path)
{
- int len = strlen(path);
- int pos = cache_name_pos(path, len);
- char c;
-
- if (pos < 0)
- return 0;
- if (strncmp(active_cache[pos]->name, path, len))
- return 0;
- c = active_cache[pos]->name[len];
- return c == '\0' || c == '/';
+ int len, pos;
+ struct cache_entry *ce;
+
+ len = strlen(path);
+ while (path[len-1] == '/')
+ len--;
+ if (!len)
+ return 1; /* "." */
+ pos = cache_name_pos(path, len);
+ if (0 <= pos)
+ return 1;
+ pos = -1 - pos;
+ while (pos < active_nr) {
+ ce = active_cache[pos++];
+ if (ce_namelen(ce) <= len ||
+ strncmp(ce->name, path, len) ||
+ (ce->name[len] > '/'))
+ break; /* path cannot be a prefix */
+ if (ce->name[len] == '/')
+ return 1;
+ }
+ return 0;
}
static int handle_diff_files_args(struct rev_info *revs,
- int argc, const char **argv, int *silent)
+ int argc, const char **argv,
+ unsigned int *options)
{
- *silent = 0;
+ *options = 0;
/* revs->max_count == -2 means --no-index */
while (1 < argc && argv[1][0] == '-') {
else if (!strcmp(argv[1], "--theirs"))
revs->max_count = 3;
else if (!strcmp(argv[1], "-n") ||
- !strcmp(argv[1], "--no-index"))
+ !strcmp(argv[1], "--no-index")) {
revs->max_count = -2;
+ DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
+ DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
+ }
else if (!strcmp(argv[1], "-q"))
- *silent = 1;
+ *options |= DIFF_SILENT_ON_REMOVED;
else
return error("invalid option: %s", argv[1]);
argv++; argc--;
*/
read_cache();
if (!is_in_index(revs->diffopt.paths[0]) ||
- !is_in_index(revs->diffopt.paths[1]))
+ !is_in_index(revs->diffopt.paths[1])) {
revs->max_count = -2;
+ DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
+ }
}
/*
{
int i;
for (i = 1; i < argc; i++)
- if (argv[i][0] != '-')
+ if (argv[i][0] != '-' || argv[i][1] == '\0')
break;
else if (!strcmp(argv[i], "--")) {
i++;
break;
} else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {
i = argc - 3;
+ DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
break;
}
if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
revs->diffopt.paths = xcalloc(2, sizeof(char*));
for (i = 0; i < 2; i++) {
- const char *p;
- p = prefix_filename(prefix, len, argv[argc - 2 + i]);
- revs->diffopt.paths[i] = xstrdup(p);
+ const char *p = argv[argc - 2 + i];
+ /*
+ * stdin should be spelled as '-'; if you have
+ * path that is '-', spell it as ./-.
+ */
+ p = (strcmp(p, "-")
+ ? xstrdup(prefix_filename(prefix, len, p))
+ : p);
+ revs->diffopt.paths[i] = p;
}
}
else
revs->diffopt.paths = argv + argc - 2;
revs->diffopt.nr_paths = 2;
+ DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
revs->max_count = -2;
+ if (diff_setup_done(&revs->diffopt) < 0)
+ die("diff_setup_done failed");
return 0;
}
int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
{
- int silent_on_removed;
+ unsigned int options;
- if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
+ if (handle_diff_files_args(revs, argc, argv, &options))
return -1;
- if (revs->max_count == -2) {
+ if (DIFF_OPT_TST(&revs->diffopt, NO_INDEX)) {
if (revs->diffopt.nr_paths != 2)
return error("need two files/directories with --no-index");
if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
perror("read_cache");
return -1;
}
- return run_diff_files(revs, silent_on_removed);
+ return run_diff_files(revs, options);
}
-int run_diff_files(struct rev_info *revs, int silent_on_removed)
+int run_diff_files(struct rev_info *revs, unsigned int option)
{
int entries, i;
int diff_unmerged_stage = revs->max_count;
+ int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
+ unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
+ ? CE_MATCH_RACY_IS_DIRTY : 0);
if (diff_unmerged_stage < 0)
diff_unmerged_stage = 2;
struct cache_entry *ce = active_cache[i];
int changed;
+ if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
+ DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
+ break;
+
if (!ce_path_match(ce, revs->prune_data))
continue;
continue;
}
else
- dpath->mode = canon_mode(st.st_mode);
+ dpath->mode = ntohl(ce_mode_from_stat(ce, st.st_mode));
while (i < entries) {
struct cache_entry *nce = active_cache[i];
int mode = ntohl(nce->ce_mode);
num_compare_stages++;
hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
- dpath->parent[stage-2].mode =
- canon_mode(mode);
+ dpath->parent[stage-2].mode = ntohl(ce_mode_from_stat(nce, mode));
dpath->parent[stage-2].status =
DIFF_STATUS_MODIFIED;
}
ce->sha1, ce->name, NULL);
continue;
}
- changed = ce_match_stat(ce, &st, 0);
- if (!changed && !revs->diffopt.find_copies_harder)
+ changed = ce_match_stat(ce, &st, ce_option);
+ if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
continue;
oldmode = ntohl(ce->ce_mode);
-
- newmode = canon_mode(st.st_mode);
- if (!trust_executable_bit &&
- S_ISREG(newmode) && S_ISREG(oldmode) &&
- ((newmode ^ oldmode) == 0111))
- newmode = oldmode;
- else if (!has_symlinks &&
- S_ISREG(newmode) && S_ISLNK(oldmode))
- newmode = oldmode;
+ newmode = ntohl(ce_mode_from_stat(ce, st.st_mode));
diff_change(&revs->diffopt, oldmode, newmode,
ce->sha1, (changed ? null_sha1 : ce->sha1),
ce->name, NULL);
oldmode = old->ce_mode;
if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
- !revs->diffopt.find_copies_harder)
+ !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
return 0;
mode = ntohl(mode);
struct cache_entry *ce = *ac;
int same = (entries > 1) && ce_same_name(ce, ac[1]);
+ if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
+ DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
+ break;
+
if (!ce_path_match(ce, pathspec))
goto skip_entry;
const char *tree_name;
int match_missing = 0;
- /*
+ /*
* Backward compatibility wart - "diff-index -m" does
* not mean "do not ignore merges", but totally different.
*/