@@ -33,6 +33,7 @@ static int mark_valid_only;
33
33
static int mark_skip_worktree_only ;
34
34
#define MARK_FLAG 1
35
35
#define UNMARK_FLAG 2
36
+ static struct strbuf mtime_dir = STRBUF_INIT ;
36
37
37
38
__attribute__((format (printf , 1 , 2 )))
38
39
static void report (const char * fmt , ...)
@@ -48,6 +49,166 @@ static void report(const char *fmt, ...)
48
49
va_end (vp );
49
50
}
50
51
52
+ static void remove_test_directory (void )
53
+ {
54
+ if (mtime_dir .len )
55
+ remove_dir_recursively (& mtime_dir , 0 );
56
+ }
57
+
58
+ static const char * get_mtime_path (const char * path )
59
+ {
60
+ static struct strbuf sb = STRBUF_INIT ;
61
+ strbuf_reset (& sb );
62
+ strbuf_addf (& sb , "%s/%s" , mtime_dir .buf , path );
63
+ return sb .buf ;
64
+ }
65
+
66
+ static void xmkdir (const char * path )
67
+ {
68
+ path = get_mtime_path (path );
69
+ if (mkdir (path , 0700 ))
70
+ die_errno (_ ("failed to create directory %s" ), path );
71
+ }
72
+
73
+ static int xstat_mtime_dir (struct stat * st )
74
+ {
75
+ if (stat (mtime_dir .buf , st ))
76
+ die_errno (_ ("failed to stat %s" ), mtime_dir .buf );
77
+ return 0 ;
78
+ }
79
+
80
+ static int create_file (const char * path )
81
+ {
82
+ int fd ;
83
+ path = get_mtime_path (path );
84
+ fd = open (path , O_CREAT | O_RDWR , 0644 );
85
+ if (fd < 0 )
86
+ die_errno (_ ("failed to create file %s" ), path );
87
+ return fd ;
88
+ }
89
+
90
+ static void xunlink (const char * path )
91
+ {
92
+ path = get_mtime_path (path );
93
+ if (unlink (path ))
94
+ die_errno (_ ("failed to delete file %s" ), path );
95
+ }
96
+
97
+ static void xrmdir (const char * path )
98
+ {
99
+ path = get_mtime_path (path );
100
+ if (rmdir (path ))
101
+ die_errno (_ ("failed to delete directory %s" ), path );
102
+ }
103
+
104
+ static void avoid_racy (void )
105
+ {
106
+ /*
107
+ * not use if we could usleep(10) if USE_NSEC is defined. The
108
+ * field nsec could be there, but the OS could choose to
109
+ * ignore it?
110
+ */
111
+ sleep (1 );
112
+ }
113
+
114
+ static int test_if_untracked_cache_is_supported (void )
115
+ {
116
+ struct stat st ;
117
+ struct stat_data base ;
118
+ int fd , ret = 0 ;
119
+
120
+ strbuf_addstr (& mtime_dir , "mtime-test-XXXXXX" );
121
+ if (!mkdtemp (mtime_dir .buf ))
122
+ die_errno ("Could not make temporary directory" );
123
+
124
+ fprintf (stderr , _ ("Testing " ));
125
+ atexit (remove_test_directory );
126
+ xstat_mtime_dir (& st );
127
+ fill_stat_data (& base , & st );
128
+ fputc ('.' , stderr );
129
+
130
+ avoid_racy ();
131
+ fd = create_file ("newfile" );
132
+ xstat_mtime_dir (& st );
133
+ if (!match_stat_data (& base , & st )) {
134
+ close (fd );
135
+ fputc ('\n' , stderr );
136
+ fprintf_ln (stderr ,_ ("directory stat info does not "
137
+ "change after adding a new file" ));
138
+ goto done ;
139
+ }
140
+ fill_stat_data (& base , & st );
141
+ fputc ('.' , stderr );
142
+
143
+ avoid_racy ();
144
+ xmkdir ("new-dir" );
145
+ xstat_mtime_dir (& st );
146
+ if (!match_stat_data (& base , & st )) {
147
+ close (fd );
148
+ fputc ('\n' , stderr );
149
+ fprintf_ln (stderr , _ ("directory stat info does not change "
150
+ "after adding a new directory" ));
151
+ goto done ;
152
+ }
153
+ fill_stat_data (& base , & st );
154
+ fputc ('.' , stderr );
155
+
156
+ avoid_racy ();
157
+ write_or_die (fd , "data" , 4 );
158
+ close (fd );
159
+ xstat_mtime_dir (& st );
160
+ if (match_stat_data (& base , & st )) {
161
+ fputc ('\n' , stderr );
162
+ fprintf_ln (stderr , _ ("directory stat info changes "
163
+ "after updating a file" ));
164
+ goto done ;
165
+ }
166
+ fputc ('.' , stderr );
167
+
168
+ avoid_racy ();
169
+ close (create_file ("new-dir/new" ));
170
+ xstat_mtime_dir (& st );
171
+ if (match_stat_data (& base , & st )) {
172
+ fputc ('\n' , stderr );
173
+ fprintf_ln (stderr , _ ("directory stat info changes after "
174
+ "adding a file inside subdirectory" ));
175
+ goto done ;
176
+ }
177
+ fputc ('.' , stderr );
178
+
179
+ avoid_racy ();
180
+ xunlink ("newfile" );
181
+ xstat_mtime_dir (& st );
182
+ if (!match_stat_data (& base , & st )) {
183
+ fputc ('\n' , stderr );
184
+ fprintf_ln (stderr , _ ("directory stat info does not "
185
+ "change after deleting a file" ));
186
+ goto done ;
187
+ }
188
+ fill_stat_data (& base , & st );
189
+ fputc ('.' , stderr );
190
+
191
+ avoid_racy ();
192
+ xunlink ("new-dir/new" );
193
+ xrmdir ("new-dir" );
194
+ xstat_mtime_dir (& st );
195
+ if (!match_stat_data (& base , & st )) {
196
+ fputc ('\n' , stderr );
197
+ fprintf_ln (stderr , _ ("directory stat info does not "
198
+ "change after deleting a directory" ));
199
+ goto done ;
200
+ }
201
+
202
+ if (rmdir (mtime_dir .buf ))
203
+ die_errno (_ ("failed to delete directory %s" ), mtime_dir .buf );
204
+ fprintf_ln (stderr , _ (" OK" ));
205
+ ret = 1 ;
206
+
207
+ done :
208
+ strbuf_release (& mtime_dir );
209
+ return ret ;
210
+ }
211
+
51
212
static int mark_ce_flags (const char * path , int flag , int mark )
52
213
{
53
214
int namelen = strlen (path );
@@ -835,6 +996,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
835
996
N_ ("enable or disable split index" )),
836
997
OPT_BOOL (0 , "untracked-cache" , & untracked_cache ,
837
998
N_ ("enable/disable untracked cache" )),
999
+ OPT_SET_INT (0 , "force-untracked-cache" , & untracked_cache ,
1000
+ N_ ("enable untracked cache without testing the filesystem" ), 2 ),
838
1001
OPT_END ()
839
1002
};
840
1003
@@ -944,6 +1107,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
944
1107
if (untracked_cache > 0 && !the_index .untracked ) {
945
1108
struct untracked_cache * uc ;
946
1109
1110
+ if (untracked_cache < 2 ) {
1111
+ setup_work_tree ();
1112
+ if (!test_if_untracked_cache_is_supported ())
1113
+ return 1 ;
1114
+ }
947
1115
uc = xcalloc (1 , sizeof (* uc ));
948
1116
uc -> exclude_per_dir = ".gitignore" ;
949
1117
/* should be the same flags used by git-status */
0 commit comments