@@ -66,17 +66,53 @@ static int dir_file_stats(struct object_directory *object_dir, void *data)
66
66
return 0 ;
67
67
}
68
68
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 )
70
78
{
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 );
72
108
struct dirent * e ;
73
109
int count = 0 ;
74
110
75
111
if (!dir )
76
112
return 0 ;
77
113
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 )
80
116
count ++ ;
81
117
82
118
closedir (dir );
@@ -104,13 +140,13 @@ static void loose_objs_stats(struct strbuf *buf, const char *path)
104
140
strbuf_addch (& count_path , '/' );
105
141
base_path_len = count_path .len ;
106
142
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 &&
110
146
!hex_to_bytes (& c , e -> d_name , 1 )) {
111
147
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 ));
114
150
strbuf_addf (buf , "%s : %7d files\n" , e -> d_name , count );
115
151
}
116
152
@@ -144,22 +180,28 @@ static int add_directory_to_archiver(struct strvec *archiver_args,
144
180
len = buf .len ;
145
181
strvec_pushf (archiver_args , "--prefix=%s" , buf .buf );
146
182
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 );
150
190
151
191
strbuf_setlen (& buf , len );
152
192
strbuf_addstr (& buf , e -> d_name );
153
193
154
- if (e -> d_type == DT_REG )
194
+ if (dtype == DT_REG )
155
195
strvec_pushf (archiver_args , "--add-file=%s" , buf .buf );
156
- else if (e -> d_type != DT_DIR )
196
+ else if (dtype != DT_DIR )
157
197
warning (_ ("skipping '%s', which is neither file nor "
158
198
"directory" ), buf .buf );
159
199
else if (recurse &&
160
200
add_directory_to_archiver (archiver_args ,
161
201
buf .buf , recurse ) < 0 )
162
202
res = -1 ;
203
+
204
+ strbuf_release (& abspath );
163
205
}
164
206
165
207
closedir (dir );
0 commit comments