@@ -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 );
0 commit comments