Fossil SCM

Summary: a number of changes to improve windows symlink handling. Detail: fixed file_contains_merge_market failure on windows symlinks; fixed inadequate S_ISLNK macro for windows; backed out change made to revert query ("OR islink" removed); added special processing to vfile_check_signature for windows symlink type changes; fixed a few flaws in the windows specific posix-compatibility routines to improve symlink handling.

sdr 2014-09-25 19:21 winsymlink
Commit 9c5bbd6a015482d3c456b0cf25ed59049db64cf4
+6 -4
--- src/checkin.c
+++ src/checkin.c
@@ -60,11 +60,11 @@
6060
filename_collation(), zName, filename_collation(),
6161
zName, filename_collation());
6262
}
6363
6464
db_prepare(&q,
65
- "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
65
+ "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0), islink"
6666
" FROM vfile "
6767
" WHERE is_selected(id) %s"
6868
" AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1",
6969
blob_str(&where)
7070
);
@@ -74,10 +74,11 @@
7474
const char *zDisplayName = zPathname;
7575
int isDeleted = db_column_int(&q, 1);
7676
int isChnged = db_column_int(&q,2);
7777
int isNew = db_column_int(&q,3)==0;
7878
int isRenamed = db_column_int(&q,4);
79
+ int isLink = db_column_int(&q,5);
7980
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
8081
if( cwdRelative ){
8182
file_relative_name(zFullName, &rewrittenPathname, 0);
8283
zDisplayName = blob_str(&rewrittenPathname);
8384
if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
@@ -110,11 +111,11 @@
110111
blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
111112
}else if( isChnged==4 ){
112113
blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
113114
}else if( isChnged==5 ){
114115
blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
115
- }else if( file_contains_merge_marker(zFullName) ){
116
+ }else if( !isLink && file_contains_merge_marker(zFullName) ){
116117
blob_appendf(report, "CONFLICT %s\n", zDisplayName);
117118
}else{
118119
blob_appendf(report, "EDITED %s\n", zDisplayName);
119120
}
120121
}else if( isRenamed ){
@@ -329,11 +330,11 @@
329330
" FROM vfile %s"
330331
" ORDER BY %s", vid, timeline_utc(), blob_str(&where), zOrderBy
331332
);
332333
}else{
333334
db_prepare(&q,
334
- "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
335
+ "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0), islink"
335336
" FROM vfile %s"
336337
" ORDER BY %s", blob_str(&where), zOrderBy
337338
);
338339
}
339340
blob_reset(&where);
@@ -341,10 +342,11 @@
341342
const char *zPathname = db_column_text(&q,0);
342343
int isDeleted = db_column_int(&q, 1);
343344
int isNew = db_column_int(&q,2)==0;
344345
int chnged = db_column_int(&q,3);
345346
int renamed = db_column_int(&q,4);
347
+ int isLink = db_column_int(&q,5);
346348
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
347349
const char *type = "";
348350
if( verboseFlag ){
349351
if( isNew ){
350352
type = "ADDED ";
@@ -363,11 +365,11 @@
363365
type = "ADDED_BY_MERGE ";
364366
}else if( chnged==4 ){
365367
type = "UPDATED_BY_INTEGRATE ";
366368
}else if( chnged==5 ){
367369
type = "ADDED_BY_INTEGRATE ";
368
- }else if( file_contains_merge_marker(zFullName) ){
370
+ }else if( !isLink && file_contains_merge_marker(zFullName) ){
369371
type = "CONFLICT ";
370372
}else{
371373
type = "EDITED ";
372374
}
373375
}else if( renamed ){
374376
--- src/checkin.c
+++ src/checkin.c
@@ -60,11 +60,11 @@
60 filename_collation(), zName, filename_collation(),
61 zName, filename_collation());
62 }
63
64 db_prepare(&q,
65 "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
66 " FROM vfile "
67 " WHERE is_selected(id) %s"
68 " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1",
69 blob_str(&where)
70 );
@@ -74,10 +74,11 @@
74 const char *zDisplayName = zPathname;
75 int isDeleted = db_column_int(&q, 1);
76 int isChnged = db_column_int(&q,2);
77 int isNew = db_column_int(&q,3)==0;
78 int isRenamed = db_column_int(&q,4);
 
79 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
80 if( cwdRelative ){
81 file_relative_name(zFullName, &rewrittenPathname, 0);
82 zDisplayName = blob_str(&rewrittenPathname);
83 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
@@ -110,11 +111,11 @@
110 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
111 }else if( isChnged==4 ){
112 blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
113 }else if( isChnged==5 ){
114 blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
115 }else if( file_contains_merge_marker(zFullName) ){
116 blob_appendf(report, "CONFLICT %s\n", zDisplayName);
117 }else{
118 blob_appendf(report, "EDITED %s\n", zDisplayName);
119 }
120 }else if( isRenamed ){
@@ -329,11 +330,11 @@
329 " FROM vfile %s"
330 " ORDER BY %s", vid, timeline_utc(), blob_str(&where), zOrderBy
331 );
332 }else{
333 db_prepare(&q,
334 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
335 " FROM vfile %s"
336 " ORDER BY %s", blob_str(&where), zOrderBy
337 );
338 }
339 blob_reset(&where);
@@ -341,10 +342,11 @@
341 const char *zPathname = db_column_text(&q,0);
342 int isDeleted = db_column_int(&q, 1);
343 int isNew = db_column_int(&q,2)==0;
344 int chnged = db_column_int(&q,3);
345 int renamed = db_column_int(&q,4);
 
346 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
347 const char *type = "";
348 if( verboseFlag ){
349 if( isNew ){
350 type = "ADDED ";
@@ -363,11 +365,11 @@
363 type = "ADDED_BY_MERGE ";
364 }else if( chnged==4 ){
365 type = "UPDATED_BY_INTEGRATE ";
366 }else if( chnged==5 ){
367 type = "ADDED_BY_INTEGRATE ";
368 }else if( file_contains_merge_marker(zFullName) ){
369 type = "CONFLICT ";
370 }else{
371 type = "EDITED ";
372 }
373 }else if( renamed ){
374
--- src/checkin.c
+++ src/checkin.c
@@ -60,11 +60,11 @@
60 filename_collation(), zName, filename_collation(),
61 zName, filename_collation());
62 }
63
64 db_prepare(&q,
65 "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0), islink"
66 " FROM vfile "
67 " WHERE is_selected(id) %s"
68 " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1",
69 blob_str(&where)
70 );
@@ -74,10 +74,11 @@
74 const char *zDisplayName = zPathname;
75 int isDeleted = db_column_int(&q, 1);
76 int isChnged = db_column_int(&q,2);
77 int isNew = db_column_int(&q,3)==0;
78 int isRenamed = db_column_int(&q,4);
79 int isLink = db_column_int(&q,5);
80 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
81 if( cwdRelative ){
82 file_relative_name(zFullName, &rewrittenPathname, 0);
83 zDisplayName = blob_str(&rewrittenPathname);
84 if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
@@ -110,11 +111,11 @@
111 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
112 }else if( isChnged==4 ){
113 blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
114 }else if( isChnged==5 ){
115 blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
116 }else if( !isLink && file_contains_merge_marker(zFullName) ){
117 blob_appendf(report, "CONFLICT %s\n", zDisplayName);
118 }else{
119 blob_appendf(report, "EDITED %s\n", zDisplayName);
120 }
121 }else if( isRenamed ){
@@ -329,11 +330,11 @@
330 " FROM vfile %s"
331 " ORDER BY %s", vid, timeline_utc(), blob_str(&where), zOrderBy
332 );
333 }else{
334 db_prepare(&q,
335 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0), islink"
336 " FROM vfile %s"
337 " ORDER BY %s", blob_str(&where), zOrderBy
338 );
339 }
340 blob_reset(&where);
@@ -341,10 +342,11 @@
342 const char *zPathname = db_column_text(&q,0);
343 int isDeleted = db_column_int(&q, 1);
344 int isNew = db_column_int(&q,2)==0;
345 int chnged = db_column_int(&q,3);
346 int renamed = db_column_int(&q,4);
347 int isLink = db_column_int(&q,5);
348 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
349 const char *type = "";
350 if( verboseFlag ){
351 if( isNew ){
352 type = "ADDED ";
@@ -363,11 +365,11 @@
365 type = "ADDED_BY_MERGE ";
366 }else if( chnged==4 ){
367 type = "UPDATED_BY_INTEGRATE ";
368 }else if( chnged==5 ){
369 type = "ADDED_BY_INTEGRATE ";
370 }else if( !isLink && file_contains_merge_marker(zFullName) ){
371 type = "CONFLICT ";
372 }else{
373 type = "EDITED ";
374 }
375 }else if( renamed ){
376
+7
--- src/file.c
+++ src/file.c
@@ -64,16 +64,23 @@
6464
6565
#if !defined(_WIN32) || !(defined(__MSVCRT__) || defined(_MSC_VER))
6666
# define fossilStat stat
6767
#endif
6868
69
+#if defined(_WIN32)
6970
/*
7071
** On Windows S_ISLNK can be true or false.
7172
*/
73
+/* the S_ISLNK provided by dirent.h for windows is inadequate, so fix it */
74
+#if defined(S_ISLNK)
75
+# undef S_ISLNK
76
+#endif
7277
#if !defined(S_ISLNK)
7378
# define S_ISLNK(x) ((x)==S_IFLNK)
7479
#endif
80
+#endif
81
+
7582
static int fileStatValid = 0;
7683
static struct fossilStat fileStat;
7784
7885
/*
7986
** Fill stat buf with information received from stat() or lstat().
8087
--- src/file.c
+++ src/file.c
@@ -64,16 +64,23 @@
64
65 #if !defined(_WIN32) || !(defined(__MSVCRT__) || defined(_MSC_VER))
66 # define fossilStat stat
67 #endif
68
 
69 /*
70 ** On Windows S_ISLNK can be true or false.
71 */
 
 
 
 
72 #if !defined(S_ISLNK)
73 # define S_ISLNK(x) ((x)==S_IFLNK)
74 #endif
 
 
75 static int fileStatValid = 0;
76 static struct fossilStat fileStat;
77
78 /*
79 ** Fill stat buf with information received from stat() or lstat().
80
--- src/file.c
+++ src/file.c
@@ -64,16 +64,23 @@
64
65 #if !defined(_WIN32) || !(defined(__MSVCRT__) || defined(_MSC_VER))
66 # define fossilStat stat
67 #endif
68
69 #if defined(_WIN32)
70 /*
71 ** On Windows S_ISLNK can be true or false.
72 */
73 /* the S_ISLNK provided by dirent.h for windows is inadequate, so fix it */
74 #if defined(S_ISLNK)
75 # undef S_ISLNK
76 #endif
77 #if !defined(S_ISLNK)
78 # define S_ISLNK(x) ((x)==S_IFLNK)
79 #endif
80 #endif
81
82 static int fileStatValid = 0;
83 static struct fossilStat fileStat;
84
85 /*
86 ** Fill stat buf with information received from stat() or lstat().
87
+1 -1
--- src/update.c
+++ src/update.c
@@ -765,11 +765,11 @@
765765
db_multi_exec(
766766
"DELETE FROM vmerge;"
767767
"INSERT OR IGNORE INTO torevert "
768768
" SELECT pathname"
769769
" FROM vfile "
770
- " WHERE chnged OR deleted OR rid=0 OR pathname!=origname OR islink;"
770
+ " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
771771
);
772772
}
773773
db_multi_exec(
774774
"INSERT OR IGNORE INTO torevert"
775775
" SELECT origname"
776776
--- src/update.c
+++ src/update.c
@@ -765,11 +765,11 @@
765 db_multi_exec(
766 "DELETE FROM vmerge;"
767 "INSERT OR IGNORE INTO torevert "
768 " SELECT pathname"
769 " FROM vfile "
770 " WHERE chnged OR deleted OR rid=0 OR pathname!=origname OR islink;"
771 );
772 }
773 db_multi_exec(
774 "INSERT OR IGNORE INTO torevert"
775 " SELECT origname"
776
--- src/update.c
+++ src/update.c
@@ -765,11 +765,11 @@
765 db_multi_exec(
766 "DELETE FROM vmerge;"
767 "INSERT OR IGNORE INTO torevert "
768 " SELECT pathname"
769 " FROM vfile "
770 " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
771 );
772 }
773 db_multi_exec(
774 "INSERT OR IGNORE INTO torevert"
775 " SELECT origname"
776
--- src/vfile.c
+++ src/vfile.c
@@ -202,10 +202,17 @@
202202
fossil_warning("not an ordinary file: %s", zName);
203203
nErr++;
204204
}
205205
chnged = 1;
206206
}
207
+#if defined(_WIN32)
208
+ if (win32_check_symlink_type_changed(zName)){
209
+ if( chnged!=1 ){
210
+ chnged = 1;
211
+ }
212
+ }else /* make the following if an else if */
213
+#endif
207214
if( origSize!=currentSize ){
208215
if( chnged!=1 ){
209216
/* A file size change is definitive - the file has changed. No
210217
** need to check the mtime or sha1sum */
211218
chnged = 1;
212219
--- src/vfile.c
+++ src/vfile.c
@@ -202,10 +202,17 @@
202 fossil_warning("not an ordinary file: %s", zName);
203 nErr++;
204 }
205 chnged = 1;
206 }
 
 
 
 
 
 
 
207 if( origSize!=currentSize ){
208 if( chnged!=1 ){
209 /* A file size change is definitive - the file has changed. No
210 ** need to check the mtime or sha1sum */
211 chnged = 1;
212
--- src/vfile.c
+++ src/vfile.c
@@ -202,10 +202,17 @@
202 fossil_warning("not an ordinary file: %s", zName);
203 nErr++;
204 }
205 chnged = 1;
206 }
207 #if defined(_WIN32)
208 if (win32_check_symlink_type_changed(zName)){
209 if( chnged!=1 ){
210 chnged = 1;
211 }
212 }else /* make the following if an else if */
213 #endif
214 if( origSize!=currentSize ){
215 if( chnged!=1 ){
216 /* A file size change is definitive - the file has changed. No
217 ** need to check the mtime or sha1sum */
218 chnged = 1;
219
+38 -10
--- src/winfile.c
+++ src/winfile.c
@@ -90,15 +90,19 @@
9090
}
9191
9292
ULARGE_INTEGER ull;
9393
9494
/* if a link was retrieved, it is a symlink, otherwise a dir or file */
95
- buf->st_mode = (tlen > 0) ? S_IFLNK :
96
- ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
97
- S_IFDIR : S_IFREG);
95
+ if (tlen == 0){
96
+ buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
97
+ S_IFDIR : S_IFREG);
9898
99
- buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
99
+ buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
100
+ }else{
101
+ buf->st_mode = S_IFLNK;
102
+ buf->st_size = tlen;
103
+ }
100104
101105
ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
102106
ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
103107
buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
104108
}
@@ -128,11 +132,11 @@
128132
/* exit on error or not link */
129133
if ((rc != 0) || (buf->st_mode != S_IFLNK))
130134
break;
131135
132136
/* it is a link, so open the linked file */
133
- file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
137
+ file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
134138
if ((file == NULL) || (file == INVALID_HANDLE_VALUE)){
135139
rc = 1;
136140
break;
137141
}
138142
@@ -167,12 +171,12 @@
167171
WIN32_FILE_ATTRIBUTE_DATA attr;
168172
int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
169173
if (rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)){
170174
171175
/* since it is a reparse point, open it */
172
- HANDLE file = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
173
- FILE_FLAG_OPEN_REPARSE_POINT, NULL);
176
+ HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
177
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
174178
if ((file != NULL) && (file != INVALID_HANDLE_VALUE)){
175179
176180
/* use DeviceIoControl to get the reparse point data */
177181
178182
int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
@@ -223,13 +227,13 @@
223227
** deleting a symlink of some type.
224228
** Returns 0 on success, 1 on failure.
225229
*/
226230
int win32_unlink_rmdir(const wchar_t *zFilename){
227231
int rc = 0;
228
- fossilStat stat;
229
- if (win32_stat(zFilename, &stat) == 0){
230
- if (stat.st_mode == S_IFDIR)
232
+ WIN32_FILE_ATTRIBUTE_DATA attr;
233
+ if (GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr)){
234
+ if ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
231235
rc = RemoveDirectoryW(zFilename);
232236
else
233237
rc = DeleteFileW(zFilename);
234238
}
235239
return !rc;
@@ -274,10 +278,34 @@
274278
created = 1;
275279
}
276280
277281
return !created;
278282
}
283
+
284
+/*
285
+** Given a pathname to a file, return true if:
286
+** 1. the file exists
287
+** 2. the file is a symbolic link
288
+** 3. the symbolic link's attributes can be acquired
289
+** 4. the symbolic link type is different than the target type
290
+*/
291
+int win32_check_symlink_type_changed(const char* zName){
292
+ int changed = 0;
293
+ wchar_t* zMbcs;
294
+ fossilStat lstat_buf, stat_buf;
295
+ WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
296
+ zMbcs = fossil_utf8_to_filename(zName);
297
+ if (win32_stat(zMbcs, &stat_buf) != 0)
298
+ stat_buf.st_mode = S_IFREG;
299
+ changed =
300
+ (win32_lstat(zMbcs, &lstat_buf) == 0) &&
301
+ (lstat_buf.st_mode == S_IFLNK) &&
302
+ GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
303
+ ((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
304
+ fossil_filename_free(zMbcs);
305
+ return changed;
306
+}
279307
280308
/*
281309
** Check if symlinks are potentially supported on the current OS for the given file.
282310
** Theoretically this code should work on any NT based version of windows
283311
** but I have no way of testing that. The initial check for
284312
--- src/winfile.c
+++ src/winfile.c
@@ -90,15 +90,19 @@
90 }
91
92 ULARGE_INTEGER ull;
93
94 /* if a link was retrieved, it is a symlink, otherwise a dir or file */
95 buf->st_mode = (tlen > 0) ? S_IFLNK :
96 ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
97 S_IFDIR : S_IFREG);
98
99 buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
 
 
 
 
100
101 ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
102 ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
103 buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
104 }
@@ -128,11 +132,11 @@
128 /* exit on error or not link */
129 if ((rc != 0) || (buf->st_mode != S_IFLNK))
130 break;
131
132 /* it is a link, so open the linked file */
133 file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
134 if ((file == NULL) || (file == INVALID_HANDLE_VALUE)){
135 rc = 1;
136 break;
137 }
138
@@ -167,12 +171,12 @@
167 WIN32_FILE_ATTRIBUTE_DATA attr;
168 int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
169 if (rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)){
170
171 /* since it is a reparse point, open it */
172 HANDLE file = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
173 FILE_FLAG_OPEN_REPARSE_POINT, NULL);
174 if ((file != NULL) && (file != INVALID_HANDLE_VALUE)){
175
176 /* use DeviceIoControl to get the reparse point data */
177
178 int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
@@ -223,13 +227,13 @@
223 ** deleting a symlink of some type.
224 ** Returns 0 on success, 1 on failure.
225 */
226 int win32_unlink_rmdir(const wchar_t *zFilename){
227 int rc = 0;
228 fossilStat stat;
229 if (win32_stat(zFilename, &stat) == 0){
230 if (stat.st_mode == S_IFDIR)
231 rc = RemoveDirectoryW(zFilename);
232 else
233 rc = DeleteFileW(zFilename);
234 }
235 return !rc;
@@ -274,10 +278,34 @@
274 created = 1;
275 }
276
277 return !created;
278 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
280 /*
281 ** Check if symlinks are potentially supported on the current OS for the given file.
282 ** Theoretically this code should work on any NT based version of windows
283 ** but I have no way of testing that. The initial check for
284
--- src/winfile.c
+++ src/winfile.c
@@ -90,15 +90,19 @@
90 }
91
92 ULARGE_INTEGER ull;
93
94 /* if a link was retrieved, it is a symlink, otherwise a dir or file */
95 if (tlen == 0){
96 buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
97 S_IFDIR : S_IFREG);
98
99 buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
100 }else{
101 buf->st_mode = S_IFLNK;
102 buf->st_size = tlen;
103 }
104
105 ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
106 ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
107 buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
108 }
@@ -128,11 +132,11 @@
132 /* exit on error or not link */
133 if ((rc != 0) || (buf->st_mode != S_IFLNK))
134 break;
135
136 /* it is a link, so open the linked file */
137 file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
138 if ((file == NULL) || (file == INVALID_HANDLE_VALUE)){
139 rc = 1;
140 break;
141 }
142
@@ -167,12 +171,12 @@
171 WIN32_FILE_ATTRIBUTE_DATA attr;
172 int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
173 if (rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)){
174
175 /* since it is a reparse point, open it */
176 HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
177 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
178 if ((file != NULL) && (file != INVALID_HANDLE_VALUE)){
179
180 /* use DeviceIoControl to get the reparse point data */
181
182 int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
@@ -223,13 +227,13 @@
227 ** deleting a symlink of some type.
228 ** Returns 0 on success, 1 on failure.
229 */
230 int win32_unlink_rmdir(const wchar_t *zFilename){
231 int rc = 0;
232 WIN32_FILE_ATTRIBUTE_DATA attr;
233 if (GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr)){
234 if ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
235 rc = RemoveDirectoryW(zFilename);
236 else
237 rc = DeleteFileW(zFilename);
238 }
239 return !rc;
@@ -274,10 +278,34 @@
278 created = 1;
279 }
280
281 return !created;
282 }
283
284 /*
285 ** Given a pathname to a file, return true if:
286 ** 1. the file exists
287 ** 2. the file is a symbolic link
288 ** 3. the symbolic link's attributes can be acquired
289 ** 4. the symbolic link type is different than the target type
290 */
291 int win32_check_symlink_type_changed(const char* zName){
292 int changed = 0;
293 wchar_t* zMbcs;
294 fossilStat lstat_buf, stat_buf;
295 WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
296 zMbcs = fossil_utf8_to_filename(zName);
297 if (win32_stat(zMbcs, &stat_buf) != 0)
298 stat_buf.st_mode = S_IFREG;
299 changed =
300 (win32_lstat(zMbcs, &lstat_buf) == 0) &&
301 (lstat_buf.st_mode == S_IFLNK) &&
302 GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
303 ((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
304 fossil_filename_free(zMbcs);
305 return changed;
306 }
307
308 /*
309 ** Check if symlinks are potentially supported on the current OS for the given file.
310 ** Theoretically this code should work on any NT based version of windows
311 ** but I have no way of testing that. The initial check for
312

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button