Skip to content

Commit 86c108a

Browse files
committed
Merge branch 'vd/scalar-generalize-diagnose'
Portability fix. * vd/scalar-generalize-diagnose: builtin/diagnose.c: don't translate the two mode values diagnose.c: refactor to safely use 'd_type'
2 parents 370d3a0 + d956fa8 commit 86c108a

File tree

3 files changed

+69
-15
lines changed

3 files changed

+69
-15
lines changed

builtin/diagnose.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ int cmd_diagnose(int argc, const char **argv, const char *prefix)
2222
N_("specify a destination for the diagnostics archive")),
2323
OPT_STRING('s', "suffix", &option_suffix, N_("format"),
2424
N_("specify a strftime format suffix for the filename")),
25-
OPT_CALLBACK_F(0, "mode", &mode, N_("(stats|all)"),
25+
OPT_CALLBACK_F(0, "mode", &mode, "(stats|all)",
2626
N_("specify the content of the diagnostic archive"),
2727
PARSE_OPT_NONEG, option_parse_diagnose),
2828
OPT_END()

diagnose.c

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,53 @@ static int dir_file_stats(struct object_directory *object_dir, void *data)
6666
return 0;
6767
}
6868

69-
static int count_files(char *path)
69+
/*
70+
* Get the d_type of a dirent. If the d_type is unknown, derive it from
71+
* stat.st_mode.
72+
*
73+
* Note that 'path' is assumed to have a trailing slash. It is also modified
74+
* in-place during the execution of the function, but is then reverted to its
75+
* original value before returning.
76+
*/
77+
static unsigned char get_dtype(struct dirent *e, struct strbuf *path)
7078
{
71-
DIR *dir = opendir(path);
79+
struct stat st;
80+
unsigned char dtype = DTYPE(e);
81+
size_t base_path_len;
82+
83+
if (dtype != DT_UNKNOWN)
84+
return dtype;
85+
86+
/* d_type unknown in dirent, try to fall back on lstat results */
87+
base_path_len = path->len;
88+
strbuf_addstr(path, e->d_name);
89+
if (lstat(path->buf, &st))
90+
goto cleanup;
91+
92+
/* determine d_type from st_mode */
93+
if (S_ISREG(st.st_mode))
94+
dtype = DT_REG;
95+
else if (S_ISDIR(st.st_mode))
96+
dtype = DT_DIR;
97+
else if (S_ISLNK(st.st_mode))
98+
dtype = DT_LNK;
99+
100+
cleanup:
101+
strbuf_setlen(path, base_path_len);
102+
return dtype;
103+
}
104+
105+
static int count_files(struct strbuf *path)
106+
{
107+
DIR *dir = opendir(path->buf);
72108
struct dirent *e;
73109
int count = 0;
74110

75111
if (!dir)
76112
return 0;
77113

78-
while ((e = readdir(dir)) != NULL)
79-
if (!is_dot_or_dotdot(e->d_name) && e->d_type == DT_REG)
114+
while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
115+
if (get_dtype(e, path) == DT_REG)
80116
count++;
81117

82118
closedir(dir);
@@ -104,13 +140,13 @@ static void loose_objs_stats(struct strbuf *buf, const char *path)
104140
strbuf_addch(&count_path, '/');
105141
base_path_len = count_path.len;
106142

107-
while ((e = readdir(dir)) != NULL)
108-
if (!is_dot_or_dotdot(e->d_name) &&
109-
e->d_type == DT_DIR && strlen(e->d_name) == 2 &&
143+
while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
144+
if (get_dtype(e, &count_path) == DT_DIR &&
145+
strlen(e->d_name) == 2 &&
110146
!hex_to_bytes(&c, e->d_name, 1)) {
111147
strbuf_setlen(&count_path, base_path_len);
112-
strbuf_addstr(&count_path, e->d_name);
113-
total += (count = count_files(count_path.buf));
148+
strbuf_addf(&count_path, "%s/", e->d_name);
149+
total += (count = count_files(&count_path));
114150
strbuf_addf(buf, "%s : %7d files\n", e->d_name, count);
115151
}
116152

@@ -144,22 +180,28 @@ static int add_directory_to_archiver(struct strvec *archiver_args,
144180
len = buf.len;
145181
strvec_pushf(archiver_args, "--prefix=%s", buf.buf);
146182

147-
while (!res && (e = readdir(dir))) {
148-
if (!strcmp(".", e->d_name) || !strcmp("..", e->d_name))
149-
continue;
183+
while (!res && (e = readdir_skip_dot_and_dotdot(dir))) {
184+
struct strbuf abspath = STRBUF_INIT;
185+
unsigned char dtype;
186+
187+
strbuf_add_absolute_path(&abspath, at_root ? "." : path);
188+
strbuf_addch(&abspath, '/');
189+
dtype = get_dtype(e, &abspath);
150190

151191
strbuf_setlen(&buf, len);
152192
strbuf_addstr(&buf, e->d_name);
153193

154-
if (e->d_type == DT_REG)
194+
if (dtype == DT_REG)
155195
strvec_pushf(archiver_args, "--add-file=%s", buf.buf);
156-
else if (e->d_type != DT_DIR)
196+
else if (dtype != DT_DIR)
157197
warning(_("skipping '%s', which is neither file nor "
158198
"directory"), buf.buf);
159199
else if (recurse &&
160200
add_directory_to_archiver(archiver_args,
161201
buf.buf, recurse) < 0)
162202
res = -1;
203+
204+
strbuf_release(&abspath);
163205
}
164206

165207
closedir(dir);

t/t0092-diagnose.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,23 @@ test_expect_success UNZIP 'creates diagnostics zip archive' '
2828
! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
2929
'
3030

31+
test_expect_success UNZIP 'counts loose objects' '
32+
test_commit A &&
33+
34+
# After committing, should have non-zero loose objects
35+
git diagnose -o test-count -s 1 >out &&
36+
zip_path=test-count/git-diagnostics-1.zip &&
37+
"$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
38+
grep "^Total: [1-9][0-9]* loose objects" out
39+
'
40+
3141
test_expect_success UNZIP '--mode=stats excludes .git dir contents' '
3242
test_when_finished rm -rf report &&
3343
3444
git diagnose -o report -s test --mode=stats >out &&
3545
3646
# Includes pack quantity/size info
47+
zip_path=report/git-diagnostics-test.zip &&
3748
"$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
3849
grep ".git/objects" out &&
3950
@@ -47,6 +58,7 @@ test_expect_success UNZIP '--mode=all includes .git dir contents' '
4758
git diagnose -o report -s test --mode=all >out &&
4859
4960
# Includes pack quantity/size info
61+
zip_path=report/git-diagnostics-test.zip &&
5062
"$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
5163
grep ".git/objects" out &&
5264

0 commit comments

Comments
 (0)