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);
}
}
+/*
+ * 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,
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;
+ revs->diffopt.exit_with_status = 1;
+ }
else if (!strcmp(argv[1], "-q"))
*silent = 1;
else
return 0;
}
+static int is_outside_repo(const char *path, int nongit, const char *prefix)
+{
+ int i;
+ if (nongit || !strcmp(path, "-") || path[0] == '/')
+ return 1;
+ if (prefixcmp(path, "../"))
+ return 0;
+ if (!prefix)
+ return 1;
+ for (i = strlen(prefix); !prefixcmp(path, "../"); ) {
+ while (i > 0 && prefix[i - 1] != '/')
+ i--;
+ if (--i < 0)
+ return 1;
+ path += 3;
+ }
+ return 0;
+}
+
+int setup_diff_no_index(struct rev_info *revs,
+ int argc, const char ** argv, int nongit, const char *prefix)
+{
+ int i;
+ for (i = 1; i < argc; i++)
+ 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;
+ revs->diffopt.exit_with_status = 1;
+ break;
+ }
+ if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
+ !is_outside_repo(argv[i], nongit, prefix)))
+ return -1;
+
+ diff_setup(&revs->diffopt);
+ for (i = 1; i < argc - 2; )
+ if (!strcmp(argv[i], "--no-index"))
+ i++;
+ else {
+ int j = diff_opt_parse(&revs->diffopt,
+ argv + i, argc - i);
+ if (!j)
+ die("invalid diff option/value: %s", argv[i]);
+ i += j;
+ }
+
+ if (prefix) {
+ int len = strlen(prefix);
+
+ revs->diffopt.paths = xcalloc(2, sizeof(char*));
+ for (i = 0; i < 2; i++) {
+ 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;
+ revs->max_count = -2;
+ return 0;
+}
+
int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
{
int silent_on_removed;
struct cache_entry *ce = active_cache[i];
int changed;
+ if (revs->diffopt.quiet && 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;
}
if (!changed && !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);
struct cache_entry *ce = *ac;
int same = (entries > 1) && ce_same_name(ce, ac[1]);
+ if (revs->diffopt.quiet && revs->diffopt.has_changes)
+ break;
+
if (!ce_path_match(ce, pathspec))
goto skip_entry;