Fossil SCM

Merge trunk. Style changes. Implement fallback in case of Windows XP.

jan.nijtmans 2014-09-29 09:46 winsymlink merge
Commit f2ba1d223373bd51ab888b7c2d58df25f3252ed6
+24 -3
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -1171,10 +1171,13 @@
11711171
# Uncomment to enable miniz usage
11721172
# FOSSIL_ENABLE_MINIZ = 1
11731173
11741174
# Uncomment to enable SSL support
11751175
# FOSSIL_ENABLE_SSL = 1
1176
+
1177
+# Uncomment to build SSL libraries
1178
+# FOSSIL_BUILD_SSL = 1
11761179
11771180
# Uncomment to enable TH1 scripts in embedded documentation files
11781181
# FOSSIL_ENABLE_TH1_DOCS = 1
11791182
11801183
# Uncomment to enable TH1 hooks
@@ -1186,10 +1189,26 @@
11861189
!ifdef FOSSIL_ENABLE_SSL
11871190
SSLDIR = $(B)\compat\openssl-1.0.1i
11881191
SSLINCDIR = $(SSLDIR)\inc32
11891192
SSLLIBDIR = $(SSLDIR)\out32
11901193
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
1194
+!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
1195
+!message Using 'x64' platform for OpenSSL...
1196
+SSLCONFIG = VC-WIN64A no-asm
1197
+SSLSETUP = ms\do_win64a.bat
1198
+SSLNMAKE = ms\nt.mak all
1199
+!elseif "$(PLATFORM)"=="ia64"
1200
+!message Using 'ia64' platform for OpenSSL...
1201
+SSLCONFIG = VC-WIN64I no-asm
1202
+SSLSETUP = ms\do_win64i.bat
1203
+SSLNMAKE = ms\nt.mak all
1204
+!else
1205
+!message Assuming 'x86' platform for OpenSSL...
1206
+SSLCONFIG = VC-WIN32 no-asm
1207
+SSLSETUP = ms\do_ms.bat
1208
+SSLNMAKE = ms\nt.mak all
1209
+!endif
11911210
!endif
11921211
11931212
!ifdef FOSSIL_ENABLE_TCL
11941213
TCLDIR = $(B)\compat\tcl-8.6
11951214
TCLSRCDIR = $(TCLDIR)
@@ -1329,21 +1348,23 @@
13291348
openssl:
13301349
@echo Building OpenSSL from "$(SSLDIR)"...
13311350
!if "$(PERLDIR)" != ""
13321351
@set PATH=$(PERLDIR);$(PATH)
13331352
!endif
1334
- @pushd "$(SSLDIR)" && $(PERL) Configure VC-WIN32 no-asm && popd
1335
- @pushd "$(SSLDIR)" && call ms\do_ms.bat && popd
1336
- @pushd "$(SSLDIR)" && $(MAKE) /f ms\nt.mak all && popd
1353
+ @pushd "$(SSLDIR)" && $(PERL) Configure $(SSLCONFIG) && popd
1354
+ @pushd "$(SSLDIR)" && call $(SSLSETUP) && popd
1355
+ @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) && popd
13371356
!endif
13381357
13391358
!ifndef FOSSIL_ENABLE_MINIZ
13401359
APPTARGETS = $(APPTARGETS) zlib
13411360
!endif
13421361
13431362
!ifdef FOSSIL_ENABLE_SSL
1363
+!ifdef FOSSIL_BUILD_SSL
13441364
APPTARGETS = $(APPTARGETS) openssl
1365
+!endif
13451366
!endif
13461367
13471368
$(APPNAME) : $(APPTARGETS) translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
13481369
cd $(OX)
13491370
link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
13501371
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -1171,10 +1171,13 @@
1171 # Uncomment to enable miniz usage
1172 # FOSSIL_ENABLE_MINIZ = 1
1173
1174 # Uncomment to enable SSL support
1175 # FOSSIL_ENABLE_SSL = 1
 
 
 
1176
1177 # Uncomment to enable TH1 scripts in embedded documentation files
1178 # FOSSIL_ENABLE_TH1_DOCS = 1
1179
1180 # Uncomment to enable TH1 hooks
@@ -1186,10 +1189,26 @@
1186 !ifdef FOSSIL_ENABLE_SSL
1187 SSLDIR = $(B)\compat\openssl-1.0.1i
1188 SSLINCDIR = $(SSLDIR)\inc32
1189 SSLLIBDIR = $(SSLDIR)\out32
1190 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1191 !endif
1192
1193 !ifdef FOSSIL_ENABLE_TCL
1194 TCLDIR = $(B)\compat\tcl-8.6
1195 TCLSRCDIR = $(TCLDIR)
@@ -1329,21 +1348,23 @@
1329 openssl:
1330 @echo Building OpenSSL from "$(SSLDIR)"...
1331 !if "$(PERLDIR)" != ""
1332 @set PATH=$(PERLDIR);$(PATH)
1333 !endif
1334 @pushd "$(SSLDIR)" && $(PERL) Configure VC-WIN32 no-asm && popd
1335 @pushd "$(SSLDIR)" && call ms\do_ms.bat && popd
1336 @pushd "$(SSLDIR)" && $(MAKE) /f ms\nt.mak all && popd
1337 !endif
1338
1339 !ifndef FOSSIL_ENABLE_MINIZ
1340 APPTARGETS = $(APPTARGETS) zlib
1341 !endif
1342
1343 !ifdef FOSSIL_ENABLE_SSL
 
1344 APPTARGETS = $(APPTARGETS) openssl
 
1345 !endif
1346
1347 $(APPNAME) : $(APPTARGETS) translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
1348 cd $(OX)
1349 link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
1350
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -1171,10 +1171,13 @@
1171 # Uncomment to enable miniz usage
1172 # FOSSIL_ENABLE_MINIZ = 1
1173
1174 # Uncomment to enable SSL support
1175 # FOSSIL_ENABLE_SSL = 1
1176
1177 # Uncomment to build SSL libraries
1178 # FOSSIL_BUILD_SSL = 1
1179
1180 # Uncomment to enable TH1 scripts in embedded documentation files
1181 # FOSSIL_ENABLE_TH1_DOCS = 1
1182
1183 # Uncomment to enable TH1 hooks
@@ -1186,10 +1189,26 @@
1189 !ifdef FOSSIL_ENABLE_SSL
1190 SSLDIR = $(B)\compat\openssl-1.0.1i
1191 SSLINCDIR = $(SSLDIR)\inc32
1192 SSLLIBDIR = $(SSLDIR)\out32
1193 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
1194 !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
1195 !message Using 'x64' platform for OpenSSL...
1196 SSLCONFIG = VC-WIN64A no-asm
1197 SSLSETUP = ms\do_win64a.bat
1198 SSLNMAKE = ms\nt.mak all
1199 !elseif "$(PLATFORM)"=="ia64"
1200 !message Using 'ia64' platform for OpenSSL...
1201 SSLCONFIG = VC-WIN64I no-asm
1202 SSLSETUP = ms\do_win64i.bat
1203 SSLNMAKE = ms\nt.mak all
1204 !else
1205 !message Assuming 'x86' platform for OpenSSL...
1206 SSLCONFIG = VC-WIN32 no-asm
1207 SSLSETUP = ms\do_ms.bat
1208 SSLNMAKE = ms\nt.mak all
1209 !endif
1210 !endif
1211
1212 !ifdef FOSSIL_ENABLE_TCL
1213 TCLDIR = $(B)\compat\tcl-8.6
1214 TCLSRCDIR = $(TCLDIR)
@@ -1329,21 +1348,23 @@
1348 openssl:
1349 @echo Building OpenSSL from "$(SSLDIR)"...
1350 !if "$(PERLDIR)" != ""
1351 @set PATH=$(PERLDIR);$(PATH)
1352 !endif
1353 @pushd "$(SSLDIR)" && $(PERL) Configure $(SSLCONFIG) && popd
1354 @pushd "$(SSLDIR)" && call $(SSLSETUP) && popd
1355 @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) && popd
1356 !endif
1357
1358 !ifndef FOSSIL_ENABLE_MINIZ
1359 APPTARGETS = $(APPTARGETS) zlib
1360 !endif
1361
1362 !ifdef FOSSIL_ENABLE_SSL
1363 !ifdef FOSSIL_BUILD_SSL
1364 APPTARGETS = $(APPTARGETS) openssl
1365 !endif
1366 !endif
1367
1368 $(APPNAME) : $(APPTARGETS) translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
1369 cd $(OX)
1370 link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
1371
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -82,10 +82,20 @@
8282
}
8383
}
8484
8585
8686
/* HTML block tags */
87
+
88
+static void html_prolog(struct Blob *ob, void *opaque){
89
+ INTER_BLOCK(ob);
90
+ BLOB_APPEND_LITTERAL(ob, "<div class=\"markdown\">\n");
91
+}
92
+
93
+static void html_epilog(struct Blob *ob, void *opaque){
94
+ INTER_BLOCK(ob);
95
+ BLOB_APPEND_LITTERAL(ob, "</div>\n");
96
+}
8797
8898
static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
8999
char *data = blob_buffer(text);
90100
size_t first = 0, size = blob_size(text);
91101
INTER_BLOCK(ob);
@@ -364,11 +374,13 @@
364374
struct Blob *input_markdown,
365375
struct Blob *output_title,
366376
struct Blob *output_body
367377
){
368378
struct mkd_renderer html_renderer = {
369
- 0, 0, /* no prolog or epilog */
379
+ /* prolog and epilog */
380
+ html_prolog,
381
+ html_epilog,
370382
371383
/* block level elements */
372384
html_blockcode,
373385
html_blockquote,
374386
html_raw_block,
375387
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -82,10 +82,20 @@
82 }
83 }
84
85
86 /* HTML block tags */
 
 
 
 
 
 
 
 
 
 
87
88 static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
89 char *data = blob_buffer(text);
90 size_t first = 0, size = blob_size(text);
91 INTER_BLOCK(ob);
@@ -364,11 +374,13 @@
364 struct Blob *input_markdown,
365 struct Blob *output_title,
366 struct Blob *output_body
367 ){
368 struct mkd_renderer html_renderer = {
369 0, 0, /* no prolog or epilog */
 
 
370
371 /* block level elements */
372 html_blockcode,
373 html_blockquote,
374 html_raw_block,
375
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -82,10 +82,20 @@
82 }
83 }
84
85
86 /* HTML block tags */
87
88 static void html_prolog(struct Blob *ob, void *opaque){
89 INTER_BLOCK(ob);
90 BLOB_APPEND_LITTERAL(ob, "<div class=\"markdown\">\n");
91 }
92
93 static void html_epilog(struct Blob *ob, void *opaque){
94 INTER_BLOCK(ob);
95 BLOB_APPEND_LITTERAL(ob, "</div>\n");
96 }
97
98 static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
99 char *data = blob_buffer(text);
100 size_t first = 0, size = blob_size(text);
101 INTER_BLOCK(ob);
@@ -364,11 +374,13 @@
374 struct Blob *input_markdown,
375 struct Blob *output_title,
376 struct Blob *output_body
377 ){
378 struct mkd_renderer html_renderer = {
379 /* prolog and epilog */
380 html_prolog,
381 html_epilog,
382
383 /* block level elements */
384 html_blockcode,
385 html_blockquote,
386 html_raw_block,
387
+61 -61
--- src/setup.c
+++ src/setup.c
@@ -441,38 +441,38 @@
441441
if( fossil_strcmp(zLogin, "developer") ){
442442
char *z1, *z2;
443443
z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='developer'");
444444
while( z1 && *z1 ){
445445
inherit[0x7f & *(z1++)] =
446
- "<span class=\"ueditInheritDeveloper\">&bull;</span>";
446
+ "<span class=\"ueditInheritDeveloper\"><sub>D</sub></span>";
447447
}
448448
free(z2);
449449
}
450450
if( fossil_strcmp(zLogin, "reader") ){
451451
char *z1, *z2;
452452
z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='reader'");
453453
while( z1 && *z1 ){
454454
inherit[0x7f & *(z1++)] =
455
- "<span class=\"ueditInheritReader\">&bull;</span>";
455
+ "<span class=\"ueditInheritReader\"><sub>R</sub></span>";
456456
}
457457
free(z2);
458458
}
459459
if( fossil_strcmp(zLogin, "anonymous") ){
460460
char *z1, *z2;
461461
z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='anonymous'");
462462
while( z1 && *z1 ){
463463
inherit[0x7f & *(z1++)] =
464
- "<span class=\"ueditInheritAnonymous\">&bull;</span>";
464
+ "<span class=\"ueditInheritAnonymous\"><sub>A</sub></span>";
465465
}
466466
free(z2);
467467
}
468468
if( fossil_strcmp(zLogin, "nobody") ){
469469
char *z1, *z2;
470470
z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='nobody'");
471471
while( z1 && *z1 ){
472472
inherit[0x7f & *(z1++)] =
473
- "<span class=\"ueditInheritNobody\">&bull;</span>";
473
+ "<span class=\"ueditInheritNobody\"><sub>N</sub></span>";
474474
}
475475
free(z2);
476476
}
477477
478478
/* Begin generating the page
@@ -516,63 +516,63 @@
516516
@ <td class="usetupEditLabel">Capabilities:</td>
517517
@ <td>
518518
#define B(x) inherit[x]
519519
@ <table border=0><tr><td valign="top">
520520
if( g.perm.Setup ){
521
- @ <label><input type="checkbox" name="as"%s(oa['s']) />%s(B('s'))Setup
522
- @ </label><br />
523
- }
524
- @ <label><input type="checkbox" name="aa"%s(oa['a']) />%s(B('a'))Admin
525
- @ </label><br />
526
- @ <label><input type="checkbox" name="ad"%s(oa['d']) />%s(B('d'))Delete
527
- @ </label><br />
528
- @ <label><input type="checkbox" name="ae"%s(oa['e']) />%s(B('e'))Email
529
- @ </label><br />
530
- @ <label><input type="checkbox" name="ap"%s(oa['p']) />%s(B('p'))Password
531
- @ </label><br />
532
- @ <label><input type="checkbox" name="ai"%s(oa['i']) />%s(B('i'))Check-In
533
- @ </label><br />
534
- @ <label><input type="checkbox" name="ao"%s(oa['o']) />%s(B('o'))Check-Out
535
- @ </label><br />
536
- @ <label><input type="checkbox" name="ah"%s(oa['h']) />%s(B('h'))Hyperlinks
537
- @ </label><br />
538
- @ <label><input type="checkbox" name="ab"%s(oa['b']) />%s(B('b'))Attachments
539
- @ </label><br />
540
- @ </td><td><td width="40"></td><td valign="top">
541
- @ <label><input type="checkbox" name="au"%s(oa['u']) />%s(B('u'))Reader
542
- @ </label><br />
543
- @ <label><input type="checkbox" name="av"%s(oa['v']) />%s(B('v'))Developer
544
- @ </label><br />
545
- @ <label><input type="checkbox" name="ag"%s(oa['g']) />%s(B('g'))Clone
546
- @ </label><br />
547
- @ <label><input type="checkbox" name="aj"%s(oa['j']) />%s(B('j'))Read Wiki
548
- @ </label><br />
549
- @ <label><input type="checkbox" name="af"%s(oa['f']) />%s(B('f'))New Wiki
550
- @ </label><br />
551
- @ <label><input type="checkbox" name="am"%s(oa['m']) />%s(B('m'))Append Wiki
552
- @ </label><br />
553
- @ <label><input type="checkbox" name="ak"%s(oa['k']) />%s(B('k'))Write Wiki
554
- @ </label><br />
555
- @ <label><input type="checkbox" name="al"%s(oa['l']) />%s(B('l'))Moderate
556
- @ Wiki</label><br />
557
- @ </td><td><td width="40"></td><td valign="top">
558
- @ <label><input type="checkbox" name="ar"%s(oa['r']) />%s(B('r'))Read Ticket
559
- @ </label><br />
560
- @ <label><input type="checkbox" name="an"%s(oa['n']) />%s(B('n'))New Tickets
561
- @ </label><br />
562
- @ <label><input type="checkbox" name="ac"%s(oa['c']) />%s(B('c'))Append
563
- @ To Ticket </label><br />
564
- @ <label><input type="checkbox" name="aw"%s(oa['w']) />%s(B('w'))Write
565
- @ Tickets </label><br />
566
- @ <label><input type="checkbox" name="aq"%s(oa['q']) />%s(B('q'))Moderate
567
- @ Tickets </label><br />
568
- @ <label><input type="checkbox" name="at"%s(oa['t']) />%s(B('t'))Ticket
569
- @ Report </label><br />
570
- @ <label><input type="checkbox" name="ax"%s(oa['x']) />%s(B('x'))Private
571
- @ </label><br />
572
- @ <label><input type="checkbox" name="az"%s(oa['z']) />%s(B('z'))Download
573
- @ Zip </label>
521
+ @ <label><input type="checkbox" name="as"%s(oa['s']) />
522
+ @ Setup%s(B('s'))</label><br />
523
+ }
524
+ @ <label><input type="checkbox" name="aa"%s(oa['a']) />
525
+ @ Admin%s(B('a'))</label><br />
526
+ @ <label><input type="checkbox" name="ad"%s(oa['d']) />
527
+ @ Delete%s(B('d'))</label><br />
528
+ @ <label><input type="checkbox" name="ae"%s(oa['e']) />
529
+ @ Email%s(B('e'))</label><br />
530
+ @ <label><input type="checkbox" name="ap"%s(oa['p']) />
531
+ @ Password%s(B('p'))</label><br />
532
+ @ <label><input type="checkbox" name="ai"%s(oa['i']) />
533
+ @ Check-In%s(B('i'))</label><br />
534
+ @ <label><input type="checkbox" name="ao"%s(oa['o']) />
535
+ @ Check-Out%s(B('o'))</label><br />
536
+ @ <label><input type="checkbox" name="ah"%s(oa['h']) />
537
+ @ Hyperlinks%s(B('h'))</label><br />
538
+ @ <label><input type="checkbox" name="ab"%s(oa['b']) />
539
+ @ Attachments%s(B('b'))</label><br />
540
+ @ </td><td><td width="40"></td><td valign="top">
541
+ @ <label><input type="checkbox" name="au"%s(oa['u']) />
542
+ @ Reader%s(B('u'))</label><br />
543
+ @ <label><input type="checkbox" name="av"%s(oa['v']) />
544
+ @ Developer%s(B('v'))</label><br />
545
+ @ <label><input type="checkbox" name="ag"%s(oa['g']) />
546
+ @ Clone%s(B('g'))</label><br />
547
+ @ <label><input type="checkbox" name="aj"%s(oa['j']) />
548
+ @ Read Wiki%s(B('j'))</label><br />
549
+ @ <label><input type="checkbox" name="af"%s(oa['f']) />
550
+ @ New Wiki%s(B('f'))</label><br />
551
+ @ <label><input type="checkbox" name="am"%s(oa['m']) />
552
+ @ Append Wiki%s(B('m'))</label><br />
553
+ @ <label><input type="checkbox" name="ak"%s(oa['k']) />
554
+ @ Write Wiki%s(B('k'))</label><br />
555
+ @ <label><input type="checkbox" name="al"%s(oa['l']) />
556
+ @ Moderate Wiki%s(B('l'))</label><br />
557
+ @ </td><td><td width="40"></td><td valign="top">
558
+ @ <label><input type="checkbox" name="ar"%s(oa['r']) />
559
+ @ Read Ticket%s(B('r'))</label><br />
560
+ @ <label><input type="checkbox" name="an"%s(oa['n']) />
561
+ @ New Tickets%s(B('n'))</label><br />
562
+ @ <label><input type="checkbox" name="ac"%s(oa['c']) />
563
+ @ Append To Ticket%s(B('c'))</label><br />
564
+ @ <label><input type="checkbox" name="aw"%s(oa['w']) />
565
+ @ Write Tickets%s(B('w'))</label><br />
566
+ @ <label><input type="checkbox" name="aq"%s(oa['q']) />
567
+ @ Moderate Tickets%s(B('q'))</label><br />
568
+ @ <label><input type="checkbox" name="at"%s(oa['t']) />
569
+ @ Ticket Report%s(B('t'))</label><br />
570
+ @ <label><input type="checkbox" name="ax"%s(oa['x']) />
571
+ @ Private%s(B('x'))</label><br />
572
+ @ <label><input type="checkbox" name="az"%s(oa['z']) />
573
+ @ Download Zip%s(B('z'))</label>
574574
@ </td></tr></table>
575575
@ </td>
576576
@ </tr>
577577
if( !login_is_special(zLogin) ){
578578
@ <tr>
@@ -622,30 +622,30 @@
622622
@ and reset user passwords. Both automatically get all other privileges
623623
@ listed below. Use these two settings with discretion.
624624
@ </p></li>
625625
@
626626
@ <li><p>
627
- @ The "<span class="ueditInheritNobody"><big>&bull;</big></span>" mark
627
+ @ The "<span class="ueditInheritNobody"><sub>N</sub></span>" subscript suffix
628628
@ indicates the privileges of <span class="usertype">nobody</span> that
629629
@ are available to all users regardless of whether or not they are logged in.
630630
@ </p></li>
631631
@
632632
@ <li><p>
633
- @ The "<span class="ueditInheritAnonymous"><big>&bull;</big></span>" mark
633
+ @ The "<span class="ueditInheritAnonymous"><sub>A</sub></span>" subscript suffix
634634
@ indicates the privileges of <span class="usertype">anonymous</span> that
635635
@ are inherited by all logged-in users.
636636
@ </p></li>
637637
@
638638
@ <li><p>
639
- @ The "<span class="ueditInheritDeveloper"><big>&bull;</big></span>" mark
639
+ @ The "<span class="ueditInheritDeveloper"><sub>D</sub></span>" subscript suffix
640640
@ indicates the privileges of <span class="usertype">developer</span> that
641641
@ are inherited by all users with the
642642
@ <span class="capability">Developer</span> privilege.
643643
@ </p></li>
644644
@
645645
@ <li><p>
646
- @ The "<span class="ueditInheritReader"><big>&bull;</big></span>" mark
646
+ @ The "<span class="ueditInheritReader"><sub>R</sub></span>" subscript suffix
647647
@ indicates the privileges of <span class="usertype">reader</span> that
648648
@ are inherited by all users with the <span class="capability">Reader</span>
649649
@ privilege.
650650
@ </p></li>
651651
@
652652
--- src/setup.c
+++ src/setup.c
@@ -441,38 +441,38 @@
441 if( fossil_strcmp(zLogin, "developer") ){
442 char *z1, *z2;
443 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='developer'");
444 while( z1 && *z1 ){
445 inherit[0x7f & *(z1++)] =
446 "<span class=\"ueditInheritDeveloper\">&bull;</span>";
447 }
448 free(z2);
449 }
450 if( fossil_strcmp(zLogin, "reader") ){
451 char *z1, *z2;
452 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='reader'");
453 while( z1 && *z1 ){
454 inherit[0x7f & *(z1++)] =
455 "<span class=\"ueditInheritReader\">&bull;</span>";
456 }
457 free(z2);
458 }
459 if( fossil_strcmp(zLogin, "anonymous") ){
460 char *z1, *z2;
461 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='anonymous'");
462 while( z1 && *z1 ){
463 inherit[0x7f & *(z1++)] =
464 "<span class=\"ueditInheritAnonymous\">&bull;</span>";
465 }
466 free(z2);
467 }
468 if( fossil_strcmp(zLogin, "nobody") ){
469 char *z1, *z2;
470 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='nobody'");
471 while( z1 && *z1 ){
472 inherit[0x7f & *(z1++)] =
473 "<span class=\"ueditInheritNobody\">&bull;</span>";
474 }
475 free(z2);
476 }
477
478 /* Begin generating the page
@@ -516,63 +516,63 @@
516 @ <td class="usetupEditLabel">Capabilities:</td>
517 @ <td>
518 #define B(x) inherit[x]
519 @ <table border=0><tr><td valign="top">
520 if( g.perm.Setup ){
521 @ <label><input type="checkbox" name="as"%s(oa['s']) />%s(B('s'))Setup
522 @ </label><br />
523 }
524 @ <label><input type="checkbox" name="aa"%s(oa['a']) />%s(B('a'))Admin
525 @ </label><br />
526 @ <label><input type="checkbox" name="ad"%s(oa['d']) />%s(B('d'))Delete
527 @ </label><br />
528 @ <label><input type="checkbox" name="ae"%s(oa['e']) />%s(B('e'))Email
529 @ </label><br />
530 @ <label><input type="checkbox" name="ap"%s(oa['p']) />%s(B('p'))Password
531 @ </label><br />
532 @ <label><input type="checkbox" name="ai"%s(oa['i']) />%s(B('i'))Check-In
533 @ </label><br />
534 @ <label><input type="checkbox" name="ao"%s(oa['o']) />%s(B('o'))Check-Out
535 @ </label><br />
536 @ <label><input type="checkbox" name="ah"%s(oa['h']) />%s(B('h'))Hyperlinks
537 @ </label><br />
538 @ <label><input type="checkbox" name="ab"%s(oa['b']) />%s(B('b'))Attachments
539 @ </label><br />
540 @ </td><td><td width="40"></td><td valign="top">
541 @ <label><input type="checkbox" name="au"%s(oa['u']) />%s(B('u'))Reader
542 @ </label><br />
543 @ <label><input type="checkbox" name="av"%s(oa['v']) />%s(B('v'))Developer
544 @ </label><br />
545 @ <label><input type="checkbox" name="ag"%s(oa['g']) />%s(B('g'))Clone
546 @ </label><br />
547 @ <label><input type="checkbox" name="aj"%s(oa['j']) />%s(B('j'))Read Wiki
548 @ </label><br />
549 @ <label><input type="checkbox" name="af"%s(oa['f']) />%s(B('f'))New Wiki
550 @ </label><br />
551 @ <label><input type="checkbox" name="am"%s(oa['m']) />%s(B('m'))Append Wiki
552 @ </label><br />
553 @ <label><input type="checkbox" name="ak"%s(oa['k']) />%s(B('k'))Write Wiki
554 @ </label><br />
555 @ <label><input type="checkbox" name="al"%s(oa['l']) />%s(B('l'))Moderate
556 @ Wiki</label><br />
557 @ </td><td><td width="40"></td><td valign="top">
558 @ <label><input type="checkbox" name="ar"%s(oa['r']) />%s(B('r'))Read Ticket
559 @ </label><br />
560 @ <label><input type="checkbox" name="an"%s(oa['n']) />%s(B('n'))New Tickets
561 @ </label><br />
562 @ <label><input type="checkbox" name="ac"%s(oa['c']) />%s(B('c'))Append
563 @ To Ticket </label><br />
564 @ <label><input type="checkbox" name="aw"%s(oa['w']) />%s(B('w'))Write
565 @ Tickets </label><br />
566 @ <label><input type="checkbox" name="aq"%s(oa['q']) />%s(B('q'))Moderate
567 @ Tickets </label><br />
568 @ <label><input type="checkbox" name="at"%s(oa['t']) />%s(B('t'))Ticket
569 @ Report </label><br />
570 @ <label><input type="checkbox" name="ax"%s(oa['x']) />%s(B('x'))Private
571 @ </label><br />
572 @ <label><input type="checkbox" name="az"%s(oa['z']) />%s(B('z'))Download
573 @ Zip </label>
574 @ </td></tr></table>
575 @ </td>
576 @ </tr>
577 if( !login_is_special(zLogin) ){
578 @ <tr>
@@ -622,30 +622,30 @@
622 @ and reset user passwords. Both automatically get all other privileges
623 @ listed below. Use these two settings with discretion.
624 @ </p></li>
625 @
626 @ <li><p>
627 @ The "<span class="ueditInheritNobody"><big>&bull;</big></span>" mark
628 @ indicates the privileges of <span class="usertype">nobody</span> that
629 @ are available to all users regardless of whether or not they are logged in.
630 @ </p></li>
631 @
632 @ <li><p>
633 @ The "<span class="ueditInheritAnonymous"><big>&bull;</big></span>" mark
634 @ indicates the privileges of <span class="usertype">anonymous</span> that
635 @ are inherited by all logged-in users.
636 @ </p></li>
637 @
638 @ <li><p>
639 @ The "<span class="ueditInheritDeveloper"><big>&bull;</big></span>" mark
640 @ indicates the privileges of <span class="usertype">developer</span> that
641 @ are inherited by all users with the
642 @ <span class="capability">Developer</span> privilege.
643 @ </p></li>
644 @
645 @ <li><p>
646 @ The "<span class="ueditInheritReader"><big>&bull;</big></span>" mark
647 @ indicates the privileges of <span class="usertype">reader</span> that
648 @ are inherited by all users with the <span class="capability">Reader</span>
649 @ privilege.
650 @ </p></li>
651 @
652
--- src/setup.c
+++ src/setup.c
@@ -441,38 +441,38 @@
441 if( fossil_strcmp(zLogin, "developer") ){
442 char *z1, *z2;
443 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='developer'");
444 while( z1 && *z1 ){
445 inherit[0x7f & *(z1++)] =
446 "<span class=\"ueditInheritDeveloper\"><sub>D</sub></span>";
447 }
448 free(z2);
449 }
450 if( fossil_strcmp(zLogin, "reader") ){
451 char *z1, *z2;
452 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='reader'");
453 while( z1 && *z1 ){
454 inherit[0x7f & *(z1++)] =
455 "<span class=\"ueditInheritReader\"><sub>R</sub></span>";
456 }
457 free(z2);
458 }
459 if( fossil_strcmp(zLogin, "anonymous") ){
460 char *z1, *z2;
461 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='anonymous'");
462 while( z1 && *z1 ){
463 inherit[0x7f & *(z1++)] =
464 "<span class=\"ueditInheritAnonymous\"><sub>A</sub></span>";
465 }
466 free(z2);
467 }
468 if( fossil_strcmp(zLogin, "nobody") ){
469 char *z1, *z2;
470 z1 = z2 = db_text(0,"SELECT cap FROM user WHERE login='nobody'");
471 while( z1 && *z1 ){
472 inherit[0x7f & *(z1++)] =
473 "<span class=\"ueditInheritNobody\"><sub>N</sub></span>";
474 }
475 free(z2);
476 }
477
478 /* Begin generating the page
@@ -516,63 +516,63 @@
516 @ <td class="usetupEditLabel">Capabilities:</td>
517 @ <td>
518 #define B(x) inherit[x]
519 @ <table border=0><tr><td valign="top">
520 if( g.perm.Setup ){
521 @ <label><input type="checkbox" name="as"%s(oa['s']) />
522 @ Setup%s(B('s'))</label><br />
523 }
524 @ <label><input type="checkbox" name="aa"%s(oa['a']) />
525 @ Admin%s(B('a'))</label><br />
526 @ <label><input type="checkbox" name="ad"%s(oa['d']) />
527 @ Delete%s(B('d'))</label><br />
528 @ <label><input type="checkbox" name="ae"%s(oa['e']) />
529 @ Email%s(B('e'))</label><br />
530 @ <label><input type="checkbox" name="ap"%s(oa['p']) />
531 @ Password%s(B('p'))</label><br />
532 @ <label><input type="checkbox" name="ai"%s(oa['i']) />
533 @ Check-In%s(B('i'))</label><br />
534 @ <label><input type="checkbox" name="ao"%s(oa['o']) />
535 @ Check-Out%s(B('o'))</label><br />
536 @ <label><input type="checkbox" name="ah"%s(oa['h']) />
537 @ Hyperlinks%s(B('h'))</label><br />
538 @ <label><input type="checkbox" name="ab"%s(oa['b']) />
539 @ Attachments%s(B('b'))</label><br />
540 @ </td><td><td width="40"></td><td valign="top">
541 @ <label><input type="checkbox" name="au"%s(oa['u']) />
542 @ Reader%s(B('u'))</label><br />
543 @ <label><input type="checkbox" name="av"%s(oa['v']) />
544 @ Developer%s(B('v'))</label><br />
545 @ <label><input type="checkbox" name="ag"%s(oa['g']) />
546 @ Clone%s(B('g'))</label><br />
547 @ <label><input type="checkbox" name="aj"%s(oa['j']) />
548 @ Read Wiki%s(B('j'))</label><br />
549 @ <label><input type="checkbox" name="af"%s(oa['f']) />
550 @ New Wiki%s(B('f'))</label><br />
551 @ <label><input type="checkbox" name="am"%s(oa['m']) />
552 @ Append Wiki%s(B('m'))</label><br />
553 @ <label><input type="checkbox" name="ak"%s(oa['k']) />
554 @ Write Wiki%s(B('k'))</label><br />
555 @ <label><input type="checkbox" name="al"%s(oa['l']) />
556 @ Moderate Wiki%s(B('l'))</label><br />
557 @ </td><td><td width="40"></td><td valign="top">
558 @ <label><input type="checkbox" name="ar"%s(oa['r']) />
559 @ Read Ticket%s(B('r'))</label><br />
560 @ <label><input type="checkbox" name="an"%s(oa['n']) />
561 @ New Tickets%s(B('n'))</label><br />
562 @ <label><input type="checkbox" name="ac"%s(oa['c']) />
563 @ Append To Ticket%s(B('c'))</label><br />
564 @ <label><input type="checkbox" name="aw"%s(oa['w']) />
565 @ Write Tickets%s(B('w'))</label><br />
566 @ <label><input type="checkbox" name="aq"%s(oa['q']) />
567 @ Moderate Tickets%s(B('q'))</label><br />
568 @ <label><input type="checkbox" name="at"%s(oa['t']) />
569 @ Ticket Report%s(B('t'))</label><br />
570 @ <label><input type="checkbox" name="ax"%s(oa['x']) />
571 @ Private%s(B('x'))</label><br />
572 @ <label><input type="checkbox" name="az"%s(oa['z']) />
573 @ Download Zip%s(B('z'))</label>
574 @ </td></tr></table>
575 @ </td>
576 @ </tr>
577 if( !login_is_special(zLogin) ){
578 @ <tr>
@@ -622,30 +622,30 @@
622 @ and reset user passwords. Both automatically get all other privileges
623 @ listed below. Use these two settings with discretion.
624 @ </p></li>
625 @
626 @ <li><p>
627 @ The "<span class="ueditInheritNobody"><sub>N</sub></span>" subscript suffix
628 @ indicates the privileges of <span class="usertype">nobody</span> that
629 @ are available to all users regardless of whether or not they are logged in.
630 @ </p></li>
631 @
632 @ <li><p>
633 @ The "<span class="ueditInheritAnonymous"><sub>A</sub></span>" subscript suffix
634 @ indicates the privileges of <span class="usertype">anonymous</span> that
635 @ are inherited by all logged-in users.
636 @ </p></li>
637 @
638 @ <li><p>
639 @ The "<span class="ueditInheritDeveloper"><sub>D</sub></span>" subscript suffix
640 @ indicates the privileges of <span class="usertype">developer</span> that
641 @ are inherited by all users with the
642 @ <span class="capability">Developer</span> privilege.
643 @ </p></li>
644 @
645 @ <li><p>
646 @ The "<span class="ueditInheritReader"><sub>R</sub></span>" subscript suffix
647 @ indicates the privileges of <span class="usertype">reader</span> that
648 @ are inherited by all users with the <span class="capability">Reader</span>
649 @ privilege.
650 @ </p></li>
651 @
652
+85 -61
--- src/winfile.c
+++ src/winfile.c
@@ -35,13 +35,13 @@
3535
#ifndef LABEL_SECURITY_INFORMATION
3636
# define LABEL_SECURITY_INFORMATION (0x00000010L)
3737
#endif
3838
3939
#if defined(__MSVCRT__)
40
-/* TODO: determine those dynamically. */
41
-WINBASEAPI DWORD WINAPI GetFinalPathNameByHandleW (HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
42
-WINBASEAPI BOOLEAN APIENTRY CreateSymbolicLinkW (LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags);
40
+static HANDLE dllhandle = NULL;
41
+static DWORD WINAPI (*getFinalPathNameByHandleW) (HANDLE, LPWSTR, DWORD, DWORD) = NULL;
42
+static BOOLEAN APIENTRY (*createSymbolicLinkW) (LPCWSTR, LPCWSTR, DWORD) = NULL;
4343
#endif
4444
4545
/* a couple defines to make the borrowed struct below compile */
4646
#ifndef _ANONYMOUS_UNION
4747
# define _ANONYMOUS_UNION
@@ -79,10 +79,20 @@
7979
} GenericReparseBuffer;
8080
} DUMMYUNIONNAME;
8181
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
8282
8383
#define LINK_BUFFER_SIZE 1024
84
+
85
+static int isVistaOrLater(){
86
+ if( !dllhandle ){
87
+ HANDLE h = LoadLibraryW(L"KERNEL32");
88
+ createSymbolicLinkW = (BOOLEAN APIENTRY (*) (LPCWSTR, LPCWSTR, DWORD)) GetProcAddress(h, "CreateSymbolicLinkW");
89
+ getFinalPathNameByHandleW = (DWORD WINAPI (*) (HANDLE, LPWSTR, DWORD, DWORD)) GetProcAddress(h, "GetFinalPathNameByHandleW");
90
+ dllhandle = h;
91
+ }
92
+ return createSymbolicLinkW != NULL;
93
+}
8494
8595
/*
8696
** Fill stat buf with information received from GetFileAttributesExW().
8797
** Does not follow symbolic links, returning instead information about
8898
** the link itself.
@@ -91,33 +101,33 @@
91101
int win32_lstat(const wchar_t *zFilename, struct fossilStat *buf){
92102
WIN32_FILE_ATTRIBUTE_DATA attr;
93103
int rc = GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr);
94104
if( rc ){
95105
ssize_t tlen = 0; /* assume it is not a symbolic link */
96
-
106
+
97107
/* if it is a reparse point it *might* be a symbolic link */
98108
/* so defer to win32_readlink to actually check */
99
- if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
109
+ if( attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ){
100110
char *tname = fossil_filename_to_utf8(zFilename);
101111
char tlink[LINK_BUFFER_SIZE];
102112
tlen = win32_readlink(tname, tlink, sizeof(tlink));
103113
fossil_filename_free(tname);
104114
}
105
-
115
+
106116
ULARGE_INTEGER ull;
107117
108118
/* if a link was retrieved, it is a symlink, otherwise a dir or file */
109
- if (tlen == 0){
119
+ if( tlen == 0 ){
110120
buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
111121
S_IFDIR : S_IFREG);
112
-
122
+
113123
buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
114124
}else{
115125
buf->st_mode = S_IFLNK;
116126
buf->st_size = tlen;
117127
}
118
-
128
+
119129
ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
120130
ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
121131
buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
122132
}
123133
return !rc;
@@ -126,11 +136,11 @@
126136
/*
127137
** Fill stat buf with information received from win32_lstat().
128138
** If a symbolic link is found, follow it and return information about
129139
** the target, repeating until an actual target is found.
130140
** Limit the number of loop iterations so as to avoid an infinite loop
131
-** due to circular links. This should never happen because
141
+** due to circular links. This should never happen because
132142
** GetFinalPathNameByHandleW() should always preclude that need, but being
133143
** prepared to loop seems prudent, or at least not harmful.
134144
** Returns 0 on success, 1 on failure.
135145
*/
136146
int win32_stat(const wchar_t *zFilename, struct fossilStat *buf){
@@ -137,40 +147,44 @@
137147
int rc;
138148
HANDLE file;
139149
wchar_t nextFilename[LINK_BUFFER_SIZE];
140150
DWORD len;
141151
int iterationsRemaining = 8; /* 8 is arbitrary, can be modified as needed */
142
-
152
+
143153
while (iterationsRemaining-- > 0){
144154
rc = win32_lstat(zFilename, buf);
145155
146156
/* exit on error or not link */
147
- if ((rc != 0) || (buf->st_mode != S_IFLNK))
157
+ if( (rc != 0) || (buf->st_mode != S_IFLNK) )
148158
break;
149159
150
- /* it is a link, so open the linked file */
160
+ /* it is a link, so open the linked file */
151161
file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
152
- if ((file == NULL) || (file == INVALID_HANDLE_VALUE)){
162
+ if( (file == NULL) || (file == INVALID_HANDLE_VALUE) ){
153163
rc = 1;
154164
break;
155165
}
156166
157167
/* get the final path name and close the handle */
158
- len = GetFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
168
+ if( isVistaOrLater() ){
169
+ len = getFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
170
+ }else{
171
+ len = -1;
172
+ }
159173
CloseHandle(file);
160
-
174
+
161175
/* if any problems getting the final path name error so exit */
162
- if ((len <= 0) || (len > LINK_BUFFER_SIZE - 1)){
176
+ if( (len <= 0) || (len > LINK_BUFFER_SIZE - 1) ){
163177
rc = 1;
164178
break;
165179
}
166
-
180
+
167181
/* prepare to try again just in case we have a chain to follow */
168182
/* this shouldn't happen, but just trying to be safe */
169183
zFilename = nextFilename;
170184
}
171
-
185
+
172186
return rc;
173187
}
174188
175189
/*
176190
** An implementation of a posix-like readlink function for win32.
@@ -178,36 +192,36 @@
178192
** Returns the length of the link copied to buf on success, -1 on failure.
179193
*/
180194
ssize_t win32_readlink(const char *path, char *buf, size_t bufsiz){
181195
/* assume we're going to fail */
182196
ssize_t rv = -1;
183
-
197
+
184198
/* does path reference a reparse point? */
185199
WIN32_FILE_ATTRIBUTE_DATA attr;
186200
int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
187
- if (rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)){
188
-
201
+ if( rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ){
202
+
189203
/* since it is a reparse point, open it */
190
- HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
191
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
192
- if ((file != NULL) && (file != INVALID_HANDLE_VALUE)){
204
+ HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
205
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
206
+ if( (file != NULL) && (file != INVALID_HANDLE_VALUE) ){
193207
194208
/* use DeviceIoControl to get the reparse point data */
195
-
209
+
196210
int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
197211
REPARSE_DATA_BUFFER* data = fossil_malloc(data_size);
198212
DWORD data_used;
199
-
213
+
200214
data->ReparseTag = IO_REPARSE_TAG_SYMLINK;
201215
data->ReparseDataLength = 0;
202216
data->Reserved = 0;
203
-
217
+
204218
int rc = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0,
205219
data, data_size, &data_used, NULL);
206220
207221
/* did the reparse point data fit into the desired buffer? */
208
- if (rc && (data_used < data_size)){
222
+ if( rc && (data_used < data_size) ){
209223
/* it fit, so setup the print name for further processing */
210224
USHORT
211225
offset = data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t),
212226
length = data->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t);
213227
char *temp;
@@ -214,18 +228,18 @@
214228
data->SymbolicLinkReparseBuffer.PathBuffer[offset + length] = 0;
215229
216230
/* convert the filename to utf8, copy it, and discard the converted copy */
217231
temp = fossil_filename_to_utf8(data->SymbolicLinkReparseBuffer.PathBuffer + offset);
218232
rv = strlen(temp);
219
- if (rv >= bufsiz)
233
+ if( rv >= bufsiz )
220234
rv = bufsiz;
221235
memcpy(buf, temp, rv);
222236
fossil_filename_free(temp);
223237
}
224
-
238
+
225239
fossil_free(data);
226
-
240
+
227241
/* all done, close the reparse point */
228242
CloseHandle(file);
229243
}
230244
}
231245
@@ -242,12 +256,12 @@
242256
** Returns 0 on success, 1 on failure.
243257
*/
244258
int win32_unlink_rmdir(const wchar_t *zFilename){
245259
int rc = 0;
246260
WIN32_FILE_ATTRIBUTE_DATA attr;
247
- if (GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr)){
248
- if ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
261
+ if( GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr) ){
262
+ if( (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY )
249263
rc = RemoveDirectoryW(zFilename);
250264
else
251265
rc = DeleteFileW(zFilename);
252266
}
253267
return !rc;
@@ -266,33 +280,36 @@
266280
fossilStat stat;
267281
int created = 0;
268282
DWORD flags = 0;
269283
wchar_t *zMbcs, *zMbcsOld;
270284
271
- /* does oldpath exist? is it a dir or a file? */
285
+ /* does oldpath exist? is it a dir or a file? */
272286
zMbcsOld = fossil_utf8_to_filename(oldpath);
273
- if (win32_stat(zMbcsOld, &stat) == 0){
274
- if (stat.st_mode == S_IFDIR)
287
+ if( win32_stat(zMbcsOld, &stat) == 0 ){
288
+ if( stat.st_mode == S_IFDIR ){
275289
flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
290
+ }
276291
}
277292
278293
/* remove newpath before creating the symlink */
279294
zMbcs = fossil_utf8_to_filename(newpath);
280295
win32_unlink_rmdir(zMbcs);
281
- created = CreateSymbolicLinkW(zMbcs, zMbcsOld, flags);
296
+ if( isVistaOrLater() ){
297
+ created = createSymbolicLinkW(zMbcs, zMbcsOld, flags);
298
+ }
282299
fossil_filename_free(zMbcs);
283300
fossil_filename_free(zMbcsOld);
284301
285302
/* if the symlink was not created, create a plain text file */
286
- if (!created){
303
+ if( !created ){
287304
Blob content;
288305
blob_set(&content, oldpath);
289306
blob_write_to_file(&content, newpath);
290307
blob_reset(&content);
291308
created = 1;
292309
}
293
-
310
+
294311
return !created;
295312
}
296313
297314
/*
298315
** Given a pathname to a file, return true if:
@@ -305,12 +322,13 @@
305322
int changed = 0;
306323
wchar_t* zMbcs;
307324
fossilStat lstat_buf, stat_buf;
308325
WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
309326
zMbcs = fossil_utf8_to_filename(zName);
310
- if (win32_stat(zMbcs, &stat_buf) != 0)
327
+ if( win32_stat(zMbcs, &stat_buf) != 0 ){
311328
stat_buf.st_mode = S_IFREG;
329
+ }
312330
changed =
313331
(win32_lstat(zMbcs, &lstat_buf) == 0) &&
314332
(lstat_buf.st_mode == S_IFLNK) &&
315333
GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
316334
((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
@@ -337,65 +355,69 @@
337355
DWORD fullLength;
338356
wchar_t volName[MAX_PATH+1];
339357
DWORD fsFlags;
340358
341359
/* symlinks only supported on vista or greater */
342
- /* if (!IsWindowsVistaOrGreater()) // TODO: make it work on MinGW
343
- return 0; */
360
+ if( !isVistaOrLater() ){
361
+ return 0;
362
+ }
344363
345364
/* next we need to check to see if the privilege is available */
346
-
365
+
347366
/* can't check privilege if we can't lookup its value */
348
- if (!LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid))
367
+ if( !LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid) ){
349368
return 0;
350
-
369
+ }
370
+
351371
/* can't check privilege if we can't open the process token */
352372
process = GetCurrentProcess();
353
- if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
373
+ if( !OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token) ){
354374
return 0;
355
-
375
+ }
376
+
356377
/* by this point, we have a process token and the privilege value */
357378
/* try to enable the privilege then close the token */
358
-
379
+
359380
tp.PrivilegeCount = 1;
360381
tp.Privileges[0].Luid = luid;
361382
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
362
-
383
+
363384
AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
364385
status = GetLastError();
365
-
386
+
366387
CloseHandle(token);
367388
368389
/* any error means we failed to enable the privilege, symlinks not supported */
369
- if (status != ERROR_SUCCESS)
390
+ if( status != ERROR_SUCCESS ){
370391
return 0;
392
+ }
371393
372394
/* assume no support for symlinks */
373395
success = 0;
374
-
396
+
375397
pFilename = fossil_utf8_to_filename(zFilename);
376398
377399
/* given the filename we're interested in, symlinks are supported if */
378400
/* 1. we can get the full name of the path from the given path */
379401
fullLength = GetFullPathNameW(pFilename, sizeof(fullName), fullName, NULL);
380
- if ((fullLength > 0) && (fullLength < sizeof(fullName))){
402
+ if( (fullLength > 0) && (fullLength < sizeof(fullName)) ){
381403
/* 2. we can get the volume path name from the full name */
382
- if (GetVolumePathNameW(fullName, volName, sizeof(volName))){
404
+ if( GetVolumePathNameW(fullName, volName, sizeof(volName)) ){
383405
/* 3. we can get volume information from the volume path name */
384
- if (GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0)){
406
+ if( GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0) ){
385407
/* 4. the given volume support reparse points */
386
- if (fsFlags & FILE_SUPPORTS_REPARSE_POINTS){
408
+ if( fsFlags & FILE_SUPPORTS_REPARSE_POINTS ){
387409
/* all four conditions were true, so we support symlinks; success! */
388410
success = 1;
389411
}
390412
}
391413
}
392414
}
393
-
415
+
394416
fossil_filename_free(pFilename);
395
-
396
- return success;
417
+
418
+ return success;
397419
}
398420
399421
/*
400422
** Wrapper around the access() system call. This code was copied from Tcl
401423
** 8.6 and then modified.
@@ -587,11 +609,13 @@
587609
* Unable to perform access check.
588610
*/
589611
590612
rc = -1; goto done;
591613
}
592
- if( !accessYesNo ) rc = -1;
614
+ if( !accessYesNo ){
615
+ rc = -1;
616
+ }
593617
594618
done:
595619
596620
if( hToken != NULL ){
597621
CloseHandle(hToken);
598622
--- src/winfile.c
+++ src/winfile.c
@@ -35,13 +35,13 @@
35 #ifndef LABEL_SECURITY_INFORMATION
36 # define LABEL_SECURITY_INFORMATION (0x00000010L)
37 #endif
38
39 #if defined(__MSVCRT__)
40 /* TODO: determine those dynamically. */
41 WINBASEAPI DWORD WINAPI GetFinalPathNameByHandleW (HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
42 WINBASEAPI BOOLEAN APIENTRY CreateSymbolicLinkW (LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags);
43 #endif
44
45 /* a couple defines to make the borrowed struct below compile */
46 #ifndef _ANONYMOUS_UNION
47 # define _ANONYMOUS_UNION
@@ -79,10 +79,20 @@
79 } GenericReparseBuffer;
80 } DUMMYUNIONNAME;
81 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
82
83 #define LINK_BUFFER_SIZE 1024
 
 
 
 
 
 
 
 
 
 
84
85 /*
86 ** Fill stat buf with information received from GetFileAttributesExW().
87 ** Does not follow symbolic links, returning instead information about
88 ** the link itself.
@@ -91,33 +101,33 @@
91 int win32_lstat(const wchar_t *zFilename, struct fossilStat *buf){
92 WIN32_FILE_ATTRIBUTE_DATA attr;
93 int rc = GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr);
94 if( rc ){
95 ssize_t tlen = 0; /* assume it is not a symbolic link */
96
97 /* if it is a reparse point it *might* be a symbolic link */
98 /* so defer to win32_readlink to actually check */
99 if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
100 char *tname = fossil_filename_to_utf8(zFilename);
101 char tlink[LINK_BUFFER_SIZE];
102 tlen = win32_readlink(tname, tlink, sizeof(tlink));
103 fossil_filename_free(tname);
104 }
105
106 ULARGE_INTEGER ull;
107
108 /* if a link was retrieved, it is a symlink, otherwise a dir or file */
109 if (tlen == 0){
110 buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
111 S_IFDIR : S_IFREG);
112
113 buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
114 }else{
115 buf->st_mode = S_IFLNK;
116 buf->st_size = tlen;
117 }
118
119 ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
120 ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
121 buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
122 }
123 return !rc;
@@ -126,11 +136,11 @@
126 /*
127 ** Fill stat buf with information received from win32_lstat().
128 ** If a symbolic link is found, follow it and return information about
129 ** the target, repeating until an actual target is found.
130 ** Limit the number of loop iterations so as to avoid an infinite loop
131 ** due to circular links. This should never happen because
132 ** GetFinalPathNameByHandleW() should always preclude that need, but being
133 ** prepared to loop seems prudent, or at least not harmful.
134 ** Returns 0 on success, 1 on failure.
135 */
136 int win32_stat(const wchar_t *zFilename, struct fossilStat *buf){
@@ -137,40 +147,44 @@
137 int rc;
138 HANDLE file;
139 wchar_t nextFilename[LINK_BUFFER_SIZE];
140 DWORD len;
141 int iterationsRemaining = 8; /* 8 is arbitrary, can be modified as needed */
142
143 while (iterationsRemaining-- > 0){
144 rc = win32_lstat(zFilename, buf);
145
146 /* exit on error or not link */
147 if ((rc != 0) || (buf->st_mode != S_IFLNK))
148 break;
149
150 /* it is a link, so open the linked file */
151 file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
152 if ((file == NULL) || (file == INVALID_HANDLE_VALUE)){
153 rc = 1;
154 break;
155 }
156
157 /* get the final path name and close the handle */
158 len = GetFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
 
 
 
 
159 CloseHandle(file);
160
161 /* if any problems getting the final path name error so exit */
162 if ((len <= 0) || (len > LINK_BUFFER_SIZE - 1)){
163 rc = 1;
164 break;
165 }
166
167 /* prepare to try again just in case we have a chain to follow */
168 /* this shouldn't happen, but just trying to be safe */
169 zFilename = nextFilename;
170 }
171
172 return rc;
173 }
174
175 /*
176 ** An implementation of a posix-like readlink function for win32.
@@ -178,36 +192,36 @@
178 ** Returns the length of the link copied to buf on success, -1 on failure.
179 */
180 ssize_t win32_readlink(const char *path, char *buf, size_t bufsiz){
181 /* assume we're going to fail */
182 ssize_t rv = -1;
183
184 /* does path reference a reparse point? */
185 WIN32_FILE_ATTRIBUTE_DATA attr;
186 int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
187 if (rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)){
188
189 /* since it is a reparse point, open it */
190 HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
191 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
192 if ((file != NULL) && (file != INVALID_HANDLE_VALUE)){
193
194 /* use DeviceIoControl to get the reparse point data */
195
196 int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
197 REPARSE_DATA_BUFFER* data = fossil_malloc(data_size);
198 DWORD data_used;
199
200 data->ReparseTag = IO_REPARSE_TAG_SYMLINK;
201 data->ReparseDataLength = 0;
202 data->Reserved = 0;
203
204 int rc = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0,
205 data, data_size, &data_used, NULL);
206
207 /* did the reparse point data fit into the desired buffer? */
208 if (rc && (data_used < data_size)){
209 /* it fit, so setup the print name for further processing */
210 USHORT
211 offset = data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t),
212 length = data->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t);
213 char *temp;
@@ -214,18 +228,18 @@
214 data->SymbolicLinkReparseBuffer.PathBuffer[offset + length] = 0;
215
216 /* convert the filename to utf8, copy it, and discard the converted copy */
217 temp = fossil_filename_to_utf8(data->SymbolicLinkReparseBuffer.PathBuffer + offset);
218 rv = strlen(temp);
219 if (rv >= bufsiz)
220 rv = bufsiz;
221 memcpy(buf, temp, rv);
222 fossil_filename_free(temp);
223 }
224
225 fossil_free(data);
226
227 /* all done, close the reparse point */
228 CloseHandle(file);
229 }
230 }
231
@@ -242,12 +256,12 @@
242 ** Returns 0 on success, 1 on failure.
243 */
244 int win32_unlink_rmdir(const wchar_t *zFilename){
245 int rc = 0;
246 WIN32_FILE_ATTRIBUTE_DATA attr;
247 if (GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr)){
248 if ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
249 rc = RemoveDirectoryW(zFilename);
250 else
251 rc = DeleteFileW(zFilename);
252 }
253 return !rc;
@@ -266,33 +280,36 @@
266 fossilStat stat;
267 int created = 0;
268 DWORD flags = 0;
269 wchar_t *zMbcs, *zMbcsOld;
270
271 /* does oldpath exist? is it a dir or a file? */
272 zMbcsOld = fossil_utf8_to_filename(oldpath);
273 if (win32_stat(zMbcsOld, &stat) == 0){
274 if (stat.st_mode == S_IFDIR)
275 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
 
276 }
277
278 /* remove newpath before creating the symlink */
279 zMbcs = fossil_utf8_to_filename(newpath);
280 win32_unlink_rmdir(zMbcs);
281 created = CreateSymbolicLinkW(zMbcs, zMbcsOld, flags);
 
 
282 fossil_filename_free(zMbcs);
283 fossil_filename_free(zMbcsOld);
284
285 /* if the symlink was not created, create a plain text file */
286 if (!created){
287 Blob content;
288 blob_set(&content, oldpath);
289 blob_write_to_file(&content, newpath);
290 blob_reset(&content);
291 created = 1;
292 }
293
294 return !created;
295 }
296
297 /*
298 ** Given a pathname to a file, return true if:
@@ -305,12 +322,13 @@
305 int changed = 0;
306 wchar_t* zMbcs;
307 fossilStat lstat_buf, stat_buf;
308 WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
309 zMbcs = fossil_utf8_to_filename(zName);
310 if (win32_stat(zMbcs, &stat_buf) != 0)
311 stat_buf.st_mode = S_IFREG;
 
312 changed =
313 (win32_lstat(zMbcs, &lstat_buf) == 0) &&
314 (lstat_buf.st_mode == S_IFLNK) &&
315 GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
316 ((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
@@ -337,65 +355,69 @@
337 DWORD fullLength;
338 wchar_t volName[MAX_PATH+1];
339 DWORD fsFlags;
340
341 /* symlinks only supported on vista or greater */
342 /* if (!IsWindowsVistaOrGreater()) // TODO: make it work on MinGW
343 return 0; */
 
344
345 /* next we need to check to see if the privilege is available */
346
347 /* can't check privilege if we can't lookup its value */
348 if (!LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid))
349 return 0;
350
 
351 /* can't check privilege if we can't open the process token */
352 process = GetCurrentProcess();
353 if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
354 return 0;
355
 
356 /* by this point, we have a process token and the privilege value */
357 /* try to enable the privilege then close the token */
358
359 tp.PrivilegeCount = 1;
360 tp.Privileges[0].Luid = luid;
361 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
362
363 AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
364 status = GetLastError();
365
366 CloseHandle(token);
367
368 /* any error means we failed to enable the privilege, symlinks not supported */
369 if (status != ERROR_SUCCESS)
370 return 0;
 
371
372 /* assume no support for symlinks */
373 success = 0;
374
375 pFilename = fossil_utf8_to_filename(zFilename);
376
377 /* given the filename we're interested in, symlinks are supported if */
378 /* 1. we can get the full name of the path from the given path */
379 fullLength = GetFullPathNameW(pFilename, sizeof(fullName), fullName, NULL);
380 if ((fullLength > 0) && (fullLength < sizeof(fullName))){
381 /* 2. we can get the volume path name from the full name */
382 if (GetVolumePathNameW(fullName, volName, sizeof(volName))){
383 /* 3. we can get volume information from the volume path name */
384 if (GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0)){
385 /* 4. the given volume support reparse points */
386 if (fsFlags & FILE_SUPPORTS_REPARSE_POINTS){
387 /* all four conditions were true, so we support symlinks; success! */
388 success = 1;
389 }
390 }
391 }
392 }
393
394 fossil_filename_free(pFilename);
395
396 return success;
397 }
398
399 /*
400 ** Wrapper around the access() system call. This code was copied from Tcl
401 ** 8.6 and then modified.
@@ -587,11 +609,13 @@
587 * Unable to perform access check.
588 */
589
590 rc = -1; goto done;
591 }
592 if( !accessYesNo ) rc = -1;
 
 
593
594 done:
595
596 if( hToken != NULL ){
597 CloseHandle(hToken);
598
--- src/winfile.c
+++ src/winfile.c
@@ -35,13 +35,13 @@
35 #ifndef LABEL_SECURITY_INFORMATION
36 # define LABEL_SECURITY_INFORMATION (0x00000010L)
37 #endif
38
39 #if defined(__MSVCRT__)
40 static HANDLE dllhandle = NULL;
41 static DWORD WINAPI (*getFinalPathNameByHandleW) (HANDLE, LPWSTR, DWORD, DWORD) = NULL;
42 static BOOLEAN APIENTRY (*createSymbolicLinkW) (LPCWSTR, LPCWSTR, DWORD) = NULL;
43 #endif
44
45 /* a couple defines to make the borrowed struct below compile */
46 #ifndef _ANONYMOUS_UNION
47 # define _ANONYMOUS_UNION
@@ -79,10 +79,20 @@
79 } GenericReparseBuffer;
80 } DUMMYUNIONNAME;
81 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
82
83 #define LINK_BUFFER_SIZE 1024
84
85 static int isVistaOrLater(){
86 if( !dllhandle ){
87 HANDLE h = LoadLibraryW(L"KERNEL32");
88 createSymbolicLinkW = (BOOLEAN APIENTRY (*) (LPCWSTR, LPCWSTR, DWORD)) GetProcAddress(h, "CreateSymbolicLinkW");
89 getFinalPathNameByHandleW = (DWORD WINAPI (*) (HANDLE, LPWSTR, DWORD, DWORD)) GetProcAddress(h, "GetFinalPathNameByHandleW");
90 dllhandle = h;
91 }
92 return createSymbolicLinkW != NULL;
93 }
94
95 /*
96 ** Fill stat buf with information received from GetFileAttributesExW().
97 ** Does not follow symbolic links, returning instead information about
98 ** the link itself.
@@ -91,33 +101,33 @@
101 int win32_lstat(const wchar_t *zFilename, struct fossilStat *buf){
102 WIN32_FILE_ATTRIBUTE_DATA attr;
103 int rc = GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr);
104 if( rc ){
105 ssize_t tlen = 0; /* assume it is not a symbolic link */
106
107 /* if it is a reparse point it *might* be a symbolic link */
108 /* so defer to win32_readlink to actually check */
109 if( attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ){
110 char *tname = fossil_filename_to_utf8(zFilename);
111 char tlink[LINK_BUFFER_SIZE];
112 tlen = win32_readlink(tname, tlink, sizeof(tlink));
113 fossil_filename_free(tname);
114 }
115
116 ULARGE_INTEGER ull;
117
118 /* if a link was retrieved, it is a symlink, otherwise a dir or file */
119 if( tlen == 0 ){
120 buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
121 S_IFDIR : S_IFREG);
122
123 buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
124 }else{
125 buf->st_mode = S_IFLNK;
126 buf->st_size = tlen;
127 }
128
129 ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
130 ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
131 buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
132 }
133 return !rc;
@@ -126,11 +136,11 @@
136 /*
137 ** Fill stat buf with information received from win32_lstat().
138 ** If a symbolic link is found, follow it and return information about
139 ** the target, repeating until an actual target is found.
140 ** Limit the number of loop iterations so as to avoid an infinite loop
141 ** due to circular links. This should never happen because
142 ** GetFinalPathNameByHandleW() should always preclude that need, but being
143 ** prepared to loop seems prudent, or at least not harmful.
144 ** Returns 0 on success, 1 on failure.
145 */
146 int win32_stat(const wchar_t *zFilename, struct fossilStat *buf){
@@ -137,40 +147,44 @@
147 int rc;
148 HANDLE file;
149 wchar_t nextFilename[LINK_BUFFER_SIZE];
150 DWORD len;
151 int iterationsRemaining = 8; /* 8 is arbitrary, can be modified as needed */
152
153 while (iterationsRemaining-- > 0){
154 rc = win32_lstat(zFilename, buf);
155
156 /* exit on error or not link */
157 if( (rc != 0) || (buf->st_mode != S_IFLNK) )
158 break;
159
160 /* it is a link, so open the linked file */
161 file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
162 if( (file == NULL) || (file == INVALID_HANDLE_VALUE) ){
163 rc = 1;
164 break;
165 }
166
167 /* get the final path name and close the handle */
168 if( isVistaOrLater() ){
169 len = getFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
170 }else{
171 len = -1;
172 }
173 CloseHandle(file);
174
175 /* if any problems getting the final path name error so exit */
176 if( (len <= 0) || (len > LINK_BUFFER_SIZE - 1) ){
177 rc = 1;
178 break;
179 }
180
181 /* prepare to try again just in case we have a chain to follow */
182 /* this shouldn't happen, but just trying to be safe */
183 zFilename = nextFilename;
184 }
185
186 return rc;
187 }
188
189 /*
190 ** An implementation of a posix-like readlink function for win32.
@@ -178,36 +192,36 @@
192 ** Returns the length of the link copied to buf on success, -1 on failure.
193 */
194 ssize_t win32_readlink(const char *path, char *buf, size_t bufsiz){
195 /* assume we're going to fail */
196 ssize_t rv = -1;
197
198 /* does path reference a reparse point? */
199 WIN32_FILE_ATTRIBUTE_DATA attr;
200 int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
201 if( rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ){
202
203 /* since it is a reparse point, open it */
204 HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
205 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
206 if( (file != NULL) && (file != INVALID_HANDLE_VALUE) ){
207
208 /* use DeviceIoControl to get the reparse point data */
209
210 int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
211 REPARSE_DATA_BUFFER* data = fossil_malloc(data_size);
212 DWORD data_used;
213
214 data->ReparseTag = IO_REPARSE_TAG_SYMLINK;
215 data->ReparseDataLength = 0;
216 data->Reserved = 0;
217
218 int rc = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0,
219 data, data_size, &data_used, NULL);
220
221 /* did the reparse point data fit into the desired buffer? */
222 if( rc && (data_used < data_size) ){
223 /* it fit, so setup the print name for further processing */
224 USHORT
225 offset = data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t),
226 length = data->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t);
227 char *temp;
@@ -214,18 +228,18 @@
228 data->SymbolicLinkReparseBuffer.PathBuffer[offset + length] = 0;
229
230 /* convert the filename to utf8, copy it, and discard the converted copy */
231 temp = fossil_filename_to_utf8(data->SymbolicLinkReparseBuffer.PathBuffer + offset);
232 rv = strlen(temp);
233 if( rv >= bufsiz )
234 rv = bufsiz;
235 memcpy(buf, temp, rv);
236 fossil_filename_free(temp);
237 }
238
239 fossil_free(data);
240
241 /* all done, close the reparse point */
242 CloseHandle(file);
243 }
244 }
245
@@ -242,12 +256,12 @@
256 ** Returns 0 on success, 1 on failure.
257 */
258 int win32_unlink_rmdir(const wchar_t *zFilename){
259 int rc = 0;
260 WIN32_FILE_ATTRIBUTE_DATA attr;
261 if( GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr) ){
262 if( (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY )
263 rc = RemoveDirectoryW(zFilename);
264 else
265 rc = DeleteFileW(zFilename);
266 }
267 return !rc;
@@ -266,33 +280,36 @@
280 fossilStat stat;
281 int created = 0;
282 DWORD flags = 0;
283 wchar_t *zMbcs, *zMbcsOld;
284
285 /* does oldpath exist? is it a dir or a file? */
286 zMbcsOld = fossil_utf8_to_filename(oldpath);
287 if( win32_stat(zMbcsOld, &stat) == 0 ){
288 if( stat.st_mode == S_IFDIR ){
289 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
290 }
291 }
292
293 /* remove newpath before creating the symlink */
294 zMbcs = fossil_utf8_to_filename(newpath);
295 win32_unlink_rmdir(zMbcs);
296 if( isVistaOrLater() ){
297 created = createSymbolicLinkW(zMbcs, zMbcsOld, flags);
298 }
299 fossil_filename_free(zMbcs);
300 fossil_filename_free(zMbcsOld);
301
302 /* if the symlink was not created, create a plain text file */
303 if( !created ){
304 Blob content;
305 blob_set(&content, oldpath);
306 blob_write_to_file(&content, newpath);
307 blob_reset(&content);
308 created = 1;
309 }
310
311 return !created;
312 }
313
314 /*
315 ** Given a pathname to a file, return true if:
@@ -305,12 +322,13 @@
322 int changed = 0;
323 wchar_t* zMbcs;
324 fossilStat lstat_buf, stat_buf;
325 WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
326 zMbcs = fossil_utf8_to_filename(zName);
327 if( win32_stat(zMbcs, &stat_buf) != 0 ){
328 stat_buf.st_mode = S_IFREG;
329 }
330 changed =
331 (win32_lstat(zMbcs, &lstat_buf) == 0) &&
332 (lstat_buf.st_mode == S_IFLNK) &&
333 GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
334 ((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
@@ -337,65 +355,69 @@
355 DWORD fullLength;
356 wchar_t volName[MAX_PATH+1];
357 DWORD fsFlags;
358
359 /* symlinks only supported on vista or greater */
360 if( !isVistaOrLater() ){
361 return 0;
362 }
363
364 /* next we need to check to see if the privilege is available */
365
366 /* can't check privilege if we can't lookup its value */
367 if( !LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid) ){
368 return 0;
369 }
370
371 /* can't check privilege if we can't open the process token */
372 process = GetCurrentProcess();
373 if( !OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token) ){
374 return 0;
375 }
376
377 /* by this point, we have a process token and the privilege value */
378 /* try to enable the privilege then close the token */
379
380 tp.PrivilegeCount = 1;
381 tp.Privileges[0].Luid = luid;
382 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
383
384 AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
385 status = GetLastError();
386
387 CloseHandle(token);
388
389 /* any error means we failed to enable the privilege, symlinks not supported */
390 if( status != ERROR_SUCCESS ){
391 return 0;
392 }
393
394 /* assume no support for symlinks */
395 success = 0;
396
397 pFilename = fossil_utf8_to_filename(zFilename);
398
399 /* given the filename we're interested in, symlinks are supported if */
400 /* 1. we can get the full name of the path from the given path */
401 fullLength = GetFullPathNameW(pFilename, sizeof(fullName), fullName, NULL);
402 if( (fullLength > 0) && (fullLength < sizeof(fullName)) ){
403 /* 2. we can get the volume path name from the full name */
404 if( GetVolumePathNameW(fullName, volName, sizeof(volName)) ){
405 /* 3. we can get volume information from the volume path name */
406 if( GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0) ){
407 /* 4. the given volume support reparse points */
408 if( fsFlags & FILE_SUPPORTS_REPARSE_POINTS ){
409 /* all four conditions were true, so we support symlinks; success! */
410 success = 1;
411 }
412 }
413 }
414 }
415
416 fossil_filename_free(pFilename);
417
418 return success;
419 }
420
421 /*
422 ** Wrapper around the access() system call. This code was copied from Tcl
423 ** 8.6 and then modified.
@@ -587,11 +609,13 @@
609 * Unable to perform access check.
610 */
611
612 rc = -1; goto done;
613 }
614 if( !accessYesNo ){
615 rc = -1;
616 }
617
618 done:
619
620 if( hToken != NULL ){
621 CloseHandle(hToken);
622
+85 -61
--- src/winfile.c
+++ src/winfile.c
@@ -35,13 +35,13 @@
3535
#ifndef LABEL_SECURITY_INFORMATION
3636
# define LABEL_SECURITY_INFORMATION (0x00000010L)
3737
#endif
3838
3939
#if defined(__MSVCRT__)
40
-/* TODO: determine those dynamically. */
41
-WINBASEAPI DWORD WINAPI GetFinalPathNameByHandleW (HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
42
-WINBASEAPI BOOLEAN APIENTRY CreateSymbolicLinkW (LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags);
40
+static HANDLE dllhandle = NULL;
41
+static DWORD WINAPI (*getFinalPathNameByHandleW) (HANDLE, LPWSTR, DWORD, DWORD) = NULL;
42
+static BOOLEAN APIENTRY (*createSymbolicLinkW) (LPCWSTR, LPCWSTR, DWORD) = NULL;
4343
#endif
4444
4545
/* a couple defines to make the borrowed struct below compile */
4646
#ifndef _ANONYMOUS_UNION
4747
# define _ANONYMOUS_UNION
@@ -79,10 +79,20 @@
7979
} GenericReparseBuffer;
8080
} DUMMYUNIONNAME;
8181
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
8282
8383
#define LINK_BUFFER_SIZE 1024
84
+
85
+static int isVistaOrLater(){
86
+ if( !dllhandle ){
87
+ HANDLE h = LoadLibraryW(L"KERNEL32");
88
+ createSymbolicLinkW = (BOOLEAN APIENTRY (*) (LPCWSTR, LPCWSTR, DWORD)) GetProcAddress(h, "CreateSymbolicLinkW");
89
+ getFinalPathNameByHandleW = (DWORD WINAPI (*) (HANDLE, LPWSTR, DWORD, DWORD)) GetProcAddress(h, "GetFinalPathNameByHandleW");
90
+ dllhandle = h;
91
+ }
92
+ return createSymbolicLinkW != NULL;
93
+}
8494
8595
/*
8696
** Fill stat buf with information received from GetFileAttributesExW().
8797
** Does not follow symbolic links, returning instead information about
8898
** the link itself.
@@ -91,33 +101,33 @@
91101
int win32_lstat(const wchar_t *zFilename, struct fossilStat *buf){
92102
WIN32_FILE_ATTRIBUTE_DATA attr;
93103
int rc = GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr);
94104
if( rc ){
95105
ssize_t tlen = 0; /* assume it is not a symbolic link */
96
-
106
+
97107
/* if it is a reparse point it *might* be a symbolic link */
98108
/* so defer to win32_readlink to actually check */
99
- if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
109
+ if( attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ){
100110
char *tname = fossil_filename_to_utf8(zFilename);
101111
char tlink[LINK_BUFFER_SIZE];
102112
tlen = win32_readlink(tname, tlink, sizeof(tlink));
103113
fossil_filename_free(tname);
104114
}
105
-
115
+
106116
ULARGE_INTEGER ull;
107117
108118
/* if a link was retrieved, it is a symlink, otherwise a dir or file */
109
- if (tlen == 0){
119
+ if( tlen == 0 ){
110120
buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
111121
S_IFDIR : S_IFREG);
112
-
122
+
113123
buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
114124
}else{
115125
buf->st_mode = S_IFLNK;
116126
buf->st_size = tlen;
117127
}
118
-
128
+
119129
ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
120130
ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
121131
buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
122132
}
123133
return !rc;
@@ -126,11 +136,11 @@
126136
/*
127137
** Fill stat buf with information received from win32_lstat().
128138
** If a symbolic link is found, follow it and return information about
129139
** the target, repeating until an actual target is found.
130140
** Limit the number of loop iterations so as to avoid an infinite loop
131
-** due to circular links. This should never happen because
141
+** due to circular links. This should never happen because
132142
** GetFinalPathNameByHandleW() should always preclude that need, but being
133143
** prepared to loop seems prudent, or at least not harmful.
134144
** Returns 0 on success, 1 on failure.
135145
*/
136146
int win32_stat(const wchar_t *zFilename, struct fossilStat *buf){
@@ -137,40 +147,44 @@
137147
int rc;
138148
HANDLE file;
139149
wchar_t nextFilename[LINK_BUFFER_SIZE];
140150
DWORD len;
141151
int iterationsRemaining = 8; /* 8 is arbitrary, can be modified as needed */
142
-
152
+
143153
while (iterationsRemaining-- > 0){
144154
rc = win32_lstat(zFilename, buf);
145155
146156
/* exit on error or not link */
147
- if ((rc != 0) || (buf->st_mode != S_IFLNK))
157
+ if( (rc != 0) || (buf->st_mode != S_IFLNK) )
148158
break;
149159
150
- /* it is a link, so open the linked file */
160
+ /* it is a link, so open the linked file */
151161
file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
152
- if ((file == NULL) || (file == INVALID_HANDLE_VALUE)){
162
+ if( (file == NULL) || (file == INVALID_HANDLE_VALUE) ){
153163
rc = 1;
154164
break;
155165
}
156166
157167
/* get the final path name and close the handle */
158
- len = GetFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
168
+ if( isVistaOrLater() ){
169
+ len = getFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
170
+ }else{
171
+ len = -1;
172
+ }
159173
CloseHandle(file);
160
-
174
+
161175
/* if any problems getting the final path name error so exit */
162
- if ((len <= 0) || (len > LINK_BUFFER_SIZE - 1)){
176
+ if( (len <= 0) || (len > LINK_BUFFER_SIZE - 1) ){
163177
rc = 1;
164178
break;
165179
}
166
-
180
+
167181
/* prepare to try again just in case we have a chain to follow */
168182
/* this shouldn't happen, but just trying to be safe */
169183
zFilename = nextFilename;
170184
}
171
-
185
+
172186
return rc;
173187
}
174188
175189
/*
176190
** An implementation of a posix-like readlink function for win32.
@@ -178,36 +192,36 @@
178192
** Returns the length of the link copied to buf on success, -1 on failure.
179193
*/
180194
ssize_t win32_readlink(const char *path, char *buf, size_t bufsiz){
181195
/* assume we're going to fail */
182196
ssize_t rv = -1;
183
-
197
+
184198
/* does path reference a reparse point? */
185199
WIN32_FILE_ATTRIBUTE_DATA attr;
186200
int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
187
- if (rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)){
188
-
201
+ if( rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ){
202
+
189203
/* since it is a reparse point, open it */
190
- HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
191
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
192
- if ((file != NULL) && (file != INVALID_HANDLE_VALUE)){
204
+ HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
205
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
206
+ if( (file != NULL) && (file != INVALID_HANDLE_VALUE) ){
193207
194208
/* use DeviceIoControl to get the reparse point data */
195
-
209
+
196210
int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
197211
REPARSE_DATA_BUFFER* data = fossil_malloc(data_size);
198212
DWORD data_used;
199
-
213
+
200214
data->ReparseTag = IO_REPARSE_TAG_SYMLINK;
201215
data->ReparseDataLength = 0;
202216
data->Reserved = 0;
203
-
217
+
204218
int rc = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0,
205219
data, data_size, &data_used, NULL);
206220
207221
/* did the reparse point data fit into the desired buffer? */
208
- if (rc && (data_used < data_size)){
222
+ if( rc && (data_used < data_size) ){
209223
/* it fit, so setup the print name for further processing */
210224
USHORT
211225
offset = data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t),
212226
length = data->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t);
213227
char *temp;
@@ -214,18 +228,18 @@
214228
data->SymbolicLinkReparseBuffer.PathBuffer[offset + length] = 0;
215229
216230
/* convert the filename to utf8, copy it, and discard the converted copy */
217231
temp = fossil_filename_to_utf8(data->SymbolicLinkReparseBuffer.PathBuffer + offset);
218232
rv = strlen(temp);
219
- if (rv >= bufsiz)
233
+ if( rv >= bufsiz )
220234
rv = bufsiz;
221235
memcpy(buf, temp, rv);
222236
fossil_filename_free(temp);
223237
}
224
-
238
+
225239
fossil_free(data);
226
-
240
+
227241
/* all done, close the reparse point */
228242
CloseHandle(file);
229243
}
230244
}
231245
@@ -242,12 +256,12 @@
242256
** Returns 0 on success, 1 on failure.
243257
*/
244258
int win32_unlink_rmdir(const wchar_t *zFilename){
245259
int rc = 0;
246260
WIN32_FILE_ATTRIBUTE_DATA attr;
247
- if (GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr)){
248
- if ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
261
+ if( GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr) ){
262
+ if( (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY )
249263
rc = RemoveDirectoryW(zFilename);
250264
else
251265
rc = DeleteFileW(zFilename);
252266
}
253267
return !rc;
@@ -266,33 +280,36 @@
266280
fossilStat stat;
267281
int created = 0;
268282
DWORD flags = 0;
269283
wchar_t *zMbcs, *zMbcsOld;
270284
271
- /* does oldpath exist? is it a dir or a file? */
285
+ /* does oldpath exist? is it a dir or a file? */
272286
zMbcsOld = fossil_utf8_to_filename(oldpath);
273
- if (win32_stat(zMbcsOld, &stat) == 0){
274
- if (stat.st_mode == S_IFDIR)
287
+ if( win32_stat(zMbcsOld, &stat) == 0 ){
288
+ if( stat.st_mode == S_IFDIR ){
275289
flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
290
+ }
276291
}
277292
278293
/* remove newpath before creating the symlink */
279294
zMbcs = fossil_utf8_to_filename(newpath);
280295
win32_unlink_rmdir(zMbcs);
281
- created = CreateSymbolicLinkW(zMbcs, zMbcsOld, flags);
296
+ if( isVistaOrLater() ){
297
+ created = createSymbolicLinkW(zMbcs, zMbcsOld, flags);
298
+ }
282299
fossil_filename_free(zMbcs);
283300
fossil_filename_free(zMbcsOld);
284301
285302
/* if the symlink was not created, create a plain text file */
286
- if (!created){
303
+ if( !created ){
287304
Blob content;
288305
blob_set(&content, oldpath);
289306
blob_write_to_file(&content, newpath);
290307
blob_reset(&content);
291308
created = 1;
292309
}
293
-
310
+
294311
return !created;
295312
}
296313
297314
/*
298315
** Given a pathname to a file, return true if:
@@ -305,12 +322,13 @@
305322
int changed = 0;
306323
wchar_t* zMbcs;
307324
fossilStat lstat_buf, stat_buf;
308325
WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
309326
zMbcs = fossil_utf8_to_filename(zName);
310
- if (win32_stat(zMbcs, &stat_buf) != 0)
327
+ if( win32_stat(zMbcs, &stat_buf) != 0 ){
311328
stat_buf.st_mode = S_IFREG;
329
+ }
312330
changed =
313331
(win32_lstat(zMbcs, &lstat_buf) == 0) &&
314332
(lstat_buf.st_mode == S_IFLNK) &&
315333
GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
316334
((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
@@ -337,65 +355,69 @@
337355
DWORD fullLength;
338356
wchar_t volName[MAX_PATH+1];
339357
DWORD fsFlags;
340358
341359
/* symlinks only supported on vista or greater */
342
- /* if (!IsWindowsVistaOrGreater()) // TODO: make it work on MinGW
343
- return 0; */
360
+ if( !isVistaOrLater() ){
361
+ return 0;
362
+ }
344363
345364
/* next we need to check to see if the privilege is available */
346
-
365
+
347366
/* can't check privilege if we can't lookup its value */
348
- if (!LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid))
367
+ if( !LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid) ){
349368
return 0;
350
-
369
+ }
370
+
351371
/* can't check privilege if we can't open the process token */
352372
process = GetCurrentProcess();
353
- if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
373
+ if( !OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token) ){
354374
return 0;
355
-
375
+ }
376
+
356377
/* by this point, we have a process token and the privilege value */
357378
/* try to enable the privilege then close the token */
358
-
379
+
359380
tp.PrivilegeCount = 1;
360381
tp.Privileges[0].Luid = luid;
361382
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
362
-
383
+
363384
AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
364385
status = GetLastError();
365
-
386
+
366387
CloseHandle(token);
367388
368389
/* any error means we failed to enable the privilege, symlinks not supported */
369
- if (status != ERROR_SUCCESS)
390
+ if( status != ERROR_SUCCESS ){
370391
return 0;
392
+ }
371393
372394
/* assume no support for symlinks */
373395
success = 0;
374
-
396
+
375397
pFilename = fossil_utf8_to_filename(zFilename);
376398
377399
/* given the filename we're interested in, symlinks are supported if */
378400
/* 1. we can get the full name of the path from the given path */
379401
fullLength = GetFullPathNameW(pFilename, sizeof(fullName), fullName, NULL);
380
- if ((fullLength > 0) && (fullLength < sizeof(fullName))){
402
+ if( (fullLength > 0) && (fullLength < sizeof(fullName)) ){
381403
/* 2. we can get the volume path name from the full name */
382
- if (GetVolumePathNameW(fullName, volName, sizeof(volName))){
404
+ if( GetVolumePathNameW(fullName, volName, sizeof(volName)) ){
383405
/* 3. we can get volume information from the volume path name */
384
- if (GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0)){
406
+ if( GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0) ){
385407
/* 4. the given volume support reparse points */
386
- if (fsFlags & FILE_SUPPORTS_REPARSE_POINTS){
408
+ if( fsFlags & FILE_SUPPORTS_REPARSE_POINTS ){
387409
/* all four conditions were true, so we support symlinks; success! */
388410
success = 1;
389411
}
390412
}
391413
}
392414
}
393
-
415
+
394416
fossil_filename_free(pFilename);
395
-
396
- return success;
417
+
418
+ return success;
397419
}
398420
399421
/*
400422
** Wrapper around the access() system call. This code was copied from Tcl
401423
** 8.6 and then modified.
@@ -587,11 +609,13 @@
587609
* Unable to perform access check.
588610
*/
589611
590612
rc = -1; goto done;
591613
}
592
- if( !accessYesNo ) rc = -1;
614
+ if( !accessYesNo ){
615
+ rc = -1;
616
+ }
593617
594618
done:
595619
596620
if( hToken != NULL ){
597621
CloseHandle(hToken);
598622
--- src/winfile.c
+++ src/winfile.c
@@ -35,13 +35,13 @@
35 #ifndef LABEL_SECURITY_INFORMATION
36 # define LABEL_SECURITY_INFORMATION (0x00000010L)
37 #endif
38
39 #if defined(__MSVCRT__)
40 /* TODO: determine those dynamically. */
41 WINBASEAPI DWORD WINAPI GetFinalPathNameByHandleW (HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
42 WINBASEAPI BOOLEAN APIENTRY CreateSymbolicLinkW (LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags);
43 #endif
44
45 /* a couple defines to make the borrowed struct below compile */
46 #ifndef _ANONYMOUS_UNION
47 # define _ANONYMOUS_UNION
@@ -79,10 +79,20 @@
79 } GenericReparseBuffer;
80 } DUMMYUNIONNAME;
81 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
82
83 #define LINK_BUFFER_SIZE 1024
 
 
 
 
 
 
 
 
 
 
84
85 /*
86 ** Fill stat buf with information received from GetFileAttributesExW().
87 ** Does not follow symbolic links, returning instead information about
88 ** the link itself.
@@ -91,33 +101,33 @@
91 int win32_lstat(const wchar_t *zFilename, struct fossilStat *buf){
92 WIN32_FILE_ATTRIBUTE_DATA attr;
93 int rc = GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr);
94 if( rc ){
95 ssize_t tlen = 0; /* assume it is not a symbolic link */
96
97 /* if it is a reparse point it *might* be a symbolic link */
98 /* so defer to win32_readlink to actually check */
99 if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
100 char *tname = fossil_filename_to_utf8(zFilename);
101 char tlink[LINK_BUFFER_SIZE];
102 tlen = win32_readlink(tname, tlink, sizeof(tlink));
103 fossil_filename_free(tname);
104 }
105
106 ULARGE_INTEGER ull;
107
108 /* if a link was retrieved, it is a symlink, otherwise a dir or file */
109 if (tlen == 0){
110 buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
111 S_IFDIR : S_IFREG);
112
113 buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
114 }else{
115 buf->st_mode = S_IFLNK;
116 buf->st_size = tlen;
117 }
118
119 ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
120 ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
121 buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
122 }
123 return !rc;
@@ -126,11 +136,11 @@
126 /*
127 ** Fill stat buf with information received from win32_lstat().
128 ** If a symbolic link is found, follow it and return information about
129 ** the target, repeating until an actual target is found.
130 ** Limit the number of loop iterations so as to avoid an infinite loop
131 ** due to circular links. This should never happen because
132 ** GetFinalPathNameByHandleW() should always preclude that need, but being
133 ** prepared to loop seems prudent, or at least not harmful.
134 ** Returns 0 on success, 1 on failure.
135 */
136 int win32_stat(const wchar_t *zFilename, struct fossilStat *buf){
@@ -137,40 +147,44 @@
137 int rc;
138 HANDLE file;
139 wchar_t nextFilename[LINK_BUFFER_SIZE];
140 DWORD len;
141 int iterationsRemaining = 8; /* 8 is arbitrary, can be modified as needed */
142
143 while (iterationsRemaining-- > 0){
144 rc = win32_lstat(zFilename, buf);
145
146 /* exit on error or not link */
147 if ((rc != 0) || (buf->st_mode != S_IFLNK))
148 break;
149
150 /* it is a link, so open the linked file */
151 file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
152 if ((file == NULL) || (file == INVALID_HANDLE_VALUE)){
153 rc = 1;
154 break;
155 }
156
157 /* get the final path name and close the handle */
158 len = GetFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
 
 
 
 
159 CloseHandle(file);
160
161 /* if any problems getting the final path name error so exit */
162 if ((len <= 0) || (len > LINK_BUFFER_SIZE - 1)){
163 rc = 1;
164 break;
165 }
166
167 /* prepare to try again just in case we have a chain to follow */
168 /* this shouldn't happen, but just trying to be safe */
169 zFilename = nextFilename;
170 }
171
172 return rc;
173 }
174
175 /*
176 ** An implementation of a posix-like readlink function for win32.
@@ -178,36 +192,36 @@
178 ** Returns the length of the link copied to buf on success, -1 on failure.
179 */
180 ssize_t win32_readlink(const char *path, char *buf, size_t bufsiz){
181 /* assume we're going to fail */
182 ssize_t rv = -1;
183
184 /* does path reference a reparse point? */
185 WIN32_FILE_ATTRIBUTE_DATA attr;
186 int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
187 if (rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)){
188
189 /* since it is a reparse point, open it */
190 HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
191 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
192 if ((file != NULL) && (file != INVALID_HANDLE_VALUE)){
193
194 /* use DeviceIoControl to get the reparse point data */
195
196 int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
197 REPARSE_DATA_BUFFER* data = fossil_malloc(data_size);
198 DWORD data_used;
199
200 data->ReparseTag = IO_REPARSE_TAG_SYMLINK;
201 data->ReparseDataLength = 0;
202 data->Reserved = 0;
203
204 int rc = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0,
205 data, data_size, &data_used, NULL);
206
207 /* did the reparse point data fit into the desired buffer? */
208 if (rc && (data_used < data_size)){
209 /* it fit, so setup the print name for further processing */
210 USHORT
211 offset = data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t),
212 length = data->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t);
213 char *temp;
@@ -214,18 +228,18 @@
214 data->SymbolicLinkReparseBuffer.PathBuffer[offset + length] = 0;
215
216 /* convert the filename to utf8, copy it, and discard the converted copy */
217 temp = fossil_filename_to_utf8(data->SymbolicLinkReparseBuffer.PathBuffer + offset);
218 rv = strlen(temp);
219 if (rv >= bufsiz)
220 rv = bufsiz;
221 memcpy(buf, temp, rv);
222 fossil_filename_free(temp);
223 }
224
225 fossil_free(data);
226
227 /* all done, close the reparse point */
228 CloseHandle(file);
229 }
230 }
231
@@ -242,12 +256,12 @@
242 ** Returns 0 on success, 1 on failure.
243 */
244 int win32_unlink_rmdir(const wchar_t *zFilename){
245 int rc = 0;
246 WIN32_FILE_ATTRIBUTE_DATA attr;
247 if (GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr)){
248 if ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
249 rc = RemoveDirectoryW(zFilename);
250 else
251 rc = DeleteFileW(zFilename);
252 }
253 return !rc;
@@ -266,33 +280,36 @@
266 fossilStat stat;
267 int created = 0;
268 DWORD flags = 0;
269 wchar_t *zMbcs, *zMbcsOld;
270
271 /* does oldpath exist? is it a dir or a file? */
272 zMbcsOld = fossil_utf8_to_filename(oldpath);
273 if (win32_stat(zMbcsOld, &stat) == 0){
274 if (stat.st_mode == S_IFDIR)
275 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
 
276 }
277
278 /* remove newpath before creating the symlink */
279 zMbcs = fossil_utf8_to_filename(newpath);
280 win32_unlink_rmdir(zMbcs);
281 created = CreateSymbolicLinkW(zMbcs, zMbcsOld, flags);
 
 
282 fossil_filename_free(zMbcs);
283 fossil_filename_free(zMbcsOld);
284
285 /* if the symlink was not created, create a plain text file */
286 if (!created){
287 Blob content;
288 blob_set(&content, oldpath);
289 blob_write_to_file(&content, newpath);
290 blob_reset(&content);
291 created = 1;
292 }
293
294 return !created;
295 }
296
297 /*
298 ** Given a pathname to a file, return true if:
@@ -305,12 +322,13 @@
305 int changed = 0;
306 wchar_t* zMbcs;
307 fossilStat lstat_buf, stat_buf;
308 WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
309 zMbcs = fossil_utf8_to_filename(zName);
310 if (win32_stat(zMbcs, &stat_buf) != 0)
311 stat_buf.st_mode = S_IFREG;
 
312 changed =
313 (win32_lstat(zMbcs, &lstat_buf) == 0) &&
314 (lstat_buf.st_mode == S_IFLNK) &&
315 GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
316 ((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
@@ -337,65 +355,69 @@
337 DWORD fullLength;
338 wchar_t volName[MAX_PATH+1];
339 DWORD fsFlags;
340
341 /* symlinks only supported on vista or greater */
342 /* if (!IsWindowsVistaOrGreater()) // TODO: make it work on MinGW
343 return 0; */
 
344
345 /* next we need to check to see if the privilege is available */
346
347 /* can't check privilege if we can't lookup its value */
348 if (!LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid))
349 return 0;
350
 
351 /* can't check privilege if we can't open the process token */
352 process = GetCurrentProcess();
353 if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
354 return 0;
355
 
356 /* by this point, we have a process token and the privilege value */
357 /* try to enable the privilege then close the token */
358
359 tp.PrivilegeCount = 1;
360 tp.Privileges[0].Luid = luid;
361 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
362
363 AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
364 status = GetLastError();
365
366 CloseHandle(token);
367
368 /* any error means we failed to enable the privilege, symlinks not supported */
369 if (status != ERROR_SUCCESS)
370 return 0;
 
371
372 /* assume no support for symlinks */
373 success = 0;
374
375 pFilename = fossil_utf8_to_filename(zFilename);
376
377 /* given the filename we're interested in, symlinks are supported if */
378 /* 1. we can get the full name of the path from the given path */
379 fullLength = GetFullPathNameW(pFilename, sizeof(fullName), fullName, NULL);
380 if ((fullLength > 0) && (fullLength < sizeof(fullName))){
381 /* 2. we can get the volume path name from the full name */
382 if (GetVolumePathNameW(fullName, volName, sizeof(volName))){
383 /* 3. we can get volume information from the volume path name */
384 if (GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0)){
385 /* 4. the given volume support reparse points */
386 if (fsFlags & FILE_SUPPORTS_REPARSE_POINTS){
387 /* all four conditions were true, so we support symlinks; success! */
388 success = 1;
389 }
390 }
391 }
392 }
393
394 fossil_filename_free(pFilename);
395
396 return success;
397 }
398
399 /*
400 ** Wrapper around the access() system call. This code was copied from Tcl
401 ** 8.6 and then modified.
@@ -587,11 +609,13 @@
587 * Unable to perform access check.
588 */
589
590 rc = -1; goto done;
591 }
592 if( !accessYesNo ) rc = -1;
 
 
593
594 done:
595
596 if( hToken != NULL ){
597 CloseHandle(hToken);
598
--- src/winfile.c
+++ src/winfile.c
@@ -35,13 +35,13 @@
35 #ifndef LABEL_SECURITY_INFORMATION
36 # define LABEL_SECURITY_INFORMATION (0x00000010L)
37 #endif
38
39 #if defined(__MSVCRT__)
40 static HANDLE dllhandle = NULL;
41 static DWORD WINAPI (*getFinalPathNameByHandleW) (HANDLE, LPWSTR, DWORD, DWORD) = NULL;
42 static BOOLEAN APIENTRY (*createSymbolicLinkW) (LPCWSTR, LPCWSTR, DWORD) = NULL;
43 #endif
44
45 /* a couple defines to make the borrowed struct below compile */
46 #ifndef _ANONYMOUS_UNION
47 # define _ANONYMOUS_UNION
@@ -79,10 +79,20 @@
79 } GenericReparseBuffer;
80 } DUMMYUNIONNAME;
81 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
82
83 #define LINK_BUFFER_SIZE 1024
84
85 static int isVistaOrLater(){
86 if( !dllhandle ){
87 HANDLE h = LoadLibraryW(L"KERNEL32");
88 createSymbolicLinkW = (BOOLEAN APIENTRY (*) (LPCWSTR, LPCWSTR, DWORD)) GetProcAddress(h, "CreateSymbolicLinkW");
89 getFinalPathNameByHandleW = (DWORD WINAPI (*) (HANDLE, LPWSTR, DWORD, DWORD)) GetProcAddress(h, "GetFinalPathNameByHandleW");
90 dllhandle = h;
91 }
92 return createSymbolicLinkW != NULL;
93 }
94
95 /*
96 ** Fill stat buf with information received from GetFileAttributesExW().
97 ** Does not follow symbolic links, returning instead information about
98 ** the link itself.
@@ -91,33 +101,33 @@
101 int win32_lstat(const wchar_t *zFilename, struct fossilStat *buf){
102 WIN32_FILE_ATTRIBUTE_DATA attr;
103 int rc = GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr);
104 if( rc ){
105 ssize_t tlen = 0; /* assume it is not a symbolic link */
106
107 /* if it is a reparse point it *might* be a symbolic link */
108 /* so defer to win32_readlink to actually check */
109 if( attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ){
110 char *tname = fossil_filename_to_utf8(zFilename);
111 char tlink[LINK_BUFFER_SIZE];
112 tlen = win32_readlink(tname, tlink, sizeof(tlink));
113 fossil_filename_free(tname);
114 }
115
116 ULARGE_INTEGER ull;
117
118 /* if a link was retrieved, it is a symlink, otherwise a dir or file */
119 if( tlen == 0 ){
120 buf->st_mode = ((attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
121 S_IFDIR : S_IFREG);
122
123 buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
124 }else{
125 buf->st_mode = S_IFLNK;
126 buf->st_size = tlen;
127 }
128
129 ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
130 ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
131 buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
132 }
133 return !rc;
@@ -126,11 +136,11 @@
136 /*
137 ** Fill stat buf with information received from win32_lstat().
138 ** If a symbolic link is found, follow it and return information about
139 ** the target, repeating until an actual target is found.
140 ** Limit the number of loop iterations so as to avoid an infinite loop
141 ** due to circular links. This should never happen because
142 ** GetFinalPathNameByHandleW() should always preclude that need, but being
143 ** prepared to loop seems prudent, or at least not harmful.
144 ** Returns 0 on success, 1 on failure.
145 */
146 int win32_stat(const wchar_t *zFilename, struct fossilStat *buf){
@@ -137,40 +147,44 @@
147 int rc;
148 HANDLE file;
149 wchar_t nextFilename[LINK_BUFFER_SIZE];
150 DWORD len;
151 int iterationsRemaining = 8; /* 8 is arbitrary, can be modified as needed */
152
153 while (iterationsRemaining-- > 0){
154 rc = win32_lstat(zFilename, buf);
155
156 /* exit on error or not link */
157 if( (rc != 0) || (buf->st_mode != S_IFLNK) )
158 break;
159
160 /* it is a link, so open the linked file */
161 file = CreateFileW(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
162 if( (file == NULL) || (file == INVALID_HANDLE_VALUE) ){
163 rc = 1;
164 break;
165 }
166
167 /* get the final path name and close the handle */
168 if( isVistaOrLater() ){
169 len = getFinalPathNameByHandleW(file, nextFilename, LINK_BUFFER_SIZE - 1, 0);
170 }else{
171 len = -1;
172 }
173 CloseHandle(file);
174
175 /* if any problems getting the final path name error so exit */
176 if( (len <= 0) || (len > LINK_BUFFER_SIZE - 1) ){
177 rc = 1;
178 break;
179 }
180
181 /* prepare to try again just in case we have a chain to follow */
182 /* this shouldn't happen, but just trying to be safe */
183 zFilename = nextFilename;
184 }
185
186 return rc;
187 }
188
189 /*
190 ** An implementation of a posix-like readlink function for win32.
@@ -178,36 +192,36 @@
192 ** Returns the length of the link copied to buf on success, -1 on failure.
193 */
194 ssize_t win32_readlink(const char *path, char *buf, size_t bufsiz){
195 /* assume we're going to fail */
196 ssize_t rv = -1;
197
198 /* does path reference a reparse point? */
199 WIN32_FILE_ATTRIBUTE_DATA attr;
200 int rc = GetFileAttributesEx(path, GetFileExInfoStandard, &attr);
201 if( rc && (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ){
202
203 /* since it is a reparse point, open it */
204 HANDLE file = CreateFile(path, FILE_READ_EA, 0, NULL, OPEN_EXISTING,
205 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
206 if( (file != NULL) && (file != INVALID_HANDLE_VALUE) ){
207
208 /* use DeviceIoControl to get the reparse point data */
209
210 int data_size = sizeof(REPARSE_DATA_BUFFER) + LINK_BUFFER_SIZE * sizeof(wchar_t);
211 REPARSE_DATA_BUFFER* data = fossil_malloc(data_size);
212 DWORD data_used;
213
214 data->ReparseTag = IO_REPARSE_TAG_SYMLINK;
215 data->ReparseDataLength = 0;
216 data->Reserved = 0;
217
218 int rc = DeviceIoControl(file, FSCTL_GET_REPARSE_POINT, NULL, 0,
219 data, data_size, &data_used, NULL);
220
221 /* did the reparse point data fit into the desired buffer? */
222 if( rc && (data_used < data_size) ){
223 /* it fit, so setup the print name for further processing */
224 USHORT
225 offset = data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t),
226 length = data->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t);
227 char *temp;
@@ -214,18 +228,18 @@
228 data->SymbolicLinkReparseBuffer.PathBuffer[offset + length] = 0;
229
230 /* convert the filename to utf8, copy it, and discard the converted copy */
231 temp = fossil_filename_to_utf8(data->SymbolicLinkReparseBuffer.PathBuffer + offset);
232 rv = strlen(temp);
233 if( rv >= bufsiz )
234 rv = bufsiz;
235 memcpy(buf, temp, rv);
236 fossil_filename_free(temp);
237 }
238
239 fossil_free(data);
240
241 /* all done, close the reparse point */
242 CloseHandle(file);
243 }
244 }
245
@@ -242,12 +256,12 @@
256 ** Returns 0 on success, 1 on failure.
257 */
258 int win32_unlink_rmdir(const wchar_t *zFilename){
259 int rc = 0;
260 WIN32_FILE_ATTRIBUTE_DATA attr;
261 if( GetFileAttributesExW(zFilename, GetFileExInfoStandard, &attr) ){
262 if( (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY )
263 rc = RemoveDirectoryW(zFilename);
264 else
265 rc = DeleteFileW(zFilename);
266 }
267 return !rc;
@@ -266,33 +280,36 @@
280 fossilStat stat;
281 int created = 0;
282 DWORD flags = 0;
283 wchar_t *zMbcs, *zMbcsOld;
284
285 /* does oldpath exist? is it a dir or a file? */
286 zMbcsOld = fossil_utf8_to_filename(oldpath);
287 if( win32_stat(zMbcsOld, &stat) == 0 ){
288 if( stat.st_mode == S_IFDIR ){
289 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
290 }
291 }
292
293 /* remove newpath before creating the symlink */
294 zMbcs = fossil_utf8_to_filename(newpath);
295 win32_unlink_rmdir(zMbcs);
296 if( isVistaOrLater() ){
297 created = createSymbolicLinkW(zMbcs, zMbcsOld, flags);
298 }
299 fossil_filename_free(zMbcs);
300 fossil_filename_free(zMbcsOld);
301
302 /* if the symlink was not created, create a plain text file */
303 if( !created ){
304 Blob content;
305 blob_set(&content, oldpath);
306 blob_write_to_file(&content, newpath);
307 blob_reset(&content);
308 created = 1;
309 }
310
311 return !created;
312 }
313
314 /*
315 ** Given a pathname to a file, return true if:
@@ -305,12 +322,13 @@
322 int changed = 0;
323 wchar_t* zMbcs;
324 fossilStat lstat_buf, stat_buf;
325 WIN32_FILE_ATTRIBUTE_DATA lstat_attr;
326 zMbcs = fossil_utf8_to_filename(zName);
327 if( win32_stat(zMbcs, &stat_buf) != 0 ){
328 stat_buf.st_mode = S_IFREG;
329 }
330 changed =
331 (win32_lstat(zMbcs, &lstat_buf) == 0) &&
332 (lstat_buf.st_mode == S_IFLNK) &&
333 GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &lstat_attr) &&
334 ((stat_buf.st_mode == S_IFDIR) != ((lstat_attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY));
@@ -337,65 +355,69 @@
355 DWORD fullLength;
356 wchar_t volName[MAX_PATH+1];
357 DWORD fsFlags;
358
359 /* symlinks only supported on vista or greater */
360 if( !isVistaOrLater() ){
361 return 0;
362 }
363
364 /* next we need to check to see if the privilege is available */
365
366 /* can't check privilege if we can't lookup its value */
367 if( !LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid) ){
368 return 0;
369 }
370
371 /* can't check privilege if we can't open the process token */
372 process = GetCurrentProcess();
373 if( !OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token) ){
374 return 0;
375 }
376
377 /* by this point, we have a process token and the privilege value */
378 /* try to enable the privilege then close the token */
379
380 tp.PrivilegeCount = 1;
381 tp.Privileges[0].Luid = luid;
382 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
383
384 AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
385 status = GetLastError();
386
387 CloseHandle(token);
388
389 /* any error means we failed to enable the privilege, symlinks not supported */
390 if( status != ERROR_SUCCESS ){
391 return 0;
392 }
393
394 /* assume no support for symlinks */
395 success = 0;
396
397 pFilename = fossil_utf8_to_filename(zFilename);
398
399 /* given the filename we're interested in, symlinks are supported if */
400 /* 1. we can get the full name of the path from the given path */
401 fullLength = GetFullPathNameW(pFilename, sizeof(fullName), fullName, NULL);
402 if( (fullLength > 0) && (fullLength < sizeof(fullName)) ){
403 /* 2. we can get the volume path name from the full name */
404 if( GetVolumePathNameW(fullName, volName, sizeof(volName)) ){
405 /* 3. we can get volume information from the volume path name */
406 if( GetVolumeInformationW(volName, NULL, 0, NULL, NULL, &fsFlags, NULL, 0) ){
407 /* 4. the given volume support reparse points */
408 if( fsFlags & FILE_SUPPORTS_REPARSE_POINTS ){
409 /* all four conditions were true, so we support symlinks; success! */
410 success = 1;
411 }
412 }
413 }
414 }
415
416 fossil_filename_free(pFilename);
417
418 return success;
419 }
420
421 /*
422 ** Wrapper around the access() system call. This code was copied from Tcl
423 ** 8.6 and then modified.
@@ -587,11 +609,13 @@
609 * Unable to perform access check.
610 */
611
612 rc = -1; goto done;
613 }
614 if( !accessYesNo ){
615 rc = -1;
616 }
617
618 done:
619
620 if( hToken != NULL ){
621 CloseHandle(hToken);
622
+24 -3
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -30,10 +30,13 @@
3030
# Uncomment to enable miniz usage
3131
# FOSSIL_ENABLE_MINIZ = 1
3232
3333
# Uncomment to enable SSL support
3434
# FOSSIL_ENABLE_SSL = 1
35
+
36
+# Uncomment to build SSL libraries
37
+# FOSSIL_BUILD_SSL = 1
3538
3639
# Uncomment to enable TH1 scripts in embedded documentation files
3740
# FOSSIL_ENABLE_TH1_DOCS = 1
3841
3942
# Uncomment to enable TH1 hooks
@@ -45,10 +48,26 @@
4548
!ifdef FOSSIL_ENABLE_SSL
4649
SSLDIR = $(B)\compat\openssl-1.0.1i
4750
SSLINCDIR = $(SSLDIR)\inc32
4851
SSLLIBDIR = $(SSLDIR)\out32
4952
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
53
+!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
54
+!message Using 'x64' platform for OpenSSL...
55
+SSLCONFIG = VC-WIN64A no-asm
56
+SSLSETUP = ms\do_win64a.bat
57
+SSLNMAKE = ms\nt.mak all
58
+!elseif "$(PLATFORM)"=="ia64"
59
+!message Using 'ia64' platform for OpenSSL...
60
+SSLCONFIG = VC-WIN64I no-asm
61
+SSLSETUP = ms\do_win64i.bat
62
+SSLNMAKE = ms\nt.mak all
63
+!else
64
+!message Assuming 'x86' platform for OpenSSL...
65
+SSLCONFIG = VC-WIN32 no-asm
66
+SSLSETUP = ms\do_ms.bat
67
+SSLNMAKE = ms\nt.mak all
68
+!endif
5069
!endif
5170
5271
!ifdef FOSSIL_ENABLE_TCL
5372
TCLDIR = $(B)\compat\tcl-8.6
5473
TCLSRCDIR = $(TCLDIR)
@@ -404,21 +423,23 @@
404423
openssl:
405424
@echo Building OpenSSL from "$(SSLDIR)"...
406425
!if "$(PERLDIR)" != ""
407426
@set PATH=$(PERLDIR);$(PATH)
408427
!endif
409
- @pushd "$(SSLDIR)" && $(PERL) Configure VC-WIN32 no-asm && popd
410
- @pushd "$(SSLDIR)" && call ms\do_ms.bat && popd
411
- @pushd "$(SSLDIR)" && $(MAKE) /f ms\nt.mak all && popd
428
+ @pushd "$(SSLDIR)" && $(PERL) Configure $(SSLCONFIG) && popd
429
+ @pushd "$(SSLDIR)" && call $(SSLSETUP) && popd
430
+ @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) && popd
412431
!endif
413432
414433
!ifndef FOSSIL_ENABLE_MINIZ
415434
APPTARGETS = $(APPTARGETS) zlib
416435
!endif
417436
418437
!ifdef FOSSIL_ENABLE_SSL
438
+!ifdef FOSSIL_BUILD_SSL
419439
APPTARGETS = $(APPTARGETS) openssl
440
+!endif
420441
!endif
421442
422443
$(APPNAME) : $(APPTARGETS) translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
423444
cd $(OX)
424445
link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
425446
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -30,10 +30,13 @@
30 # Uncomment to enable miniz usage
31 # FOSSIL_ENABLE_MINIZ = 1
32
33 # Uncomment to enable SSL support
34 # FOSSIL_ENABLE_SSL = 1
 
 
 
35
36 # Uncomment to enable TH1 scripts in embedded documentation files
37 # FOSSIL_ENABLE_TH1_DOCS = 1
38
39 # Uncomment to enable TH1 hooks
@@ -45,10 +48,26 @@
45 !ifdef FOSSIL_ENABLE_SSL
46 SSLDIR = $(B)\compat\openssl-1.0.1i
47 SSLINCDIR = $(SSLDIR)\inc32
48 SSLLIBDIR = $(SSLDIR)\out32
49 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50 !endif
51
52 !ifdef FOSSIL_ENABLE_TCL
53 TCLDIR = $(B)\compat\tcl-8.6
54 TCLSRCDIR = $(TCLDIR)
@@ -404,21 +423,23 @@
404 openssl:
405 @echo Building OpenSSL from "$(SSLDIR)"...
406 !if "$(PERLDIR)" != ""
407 @set PATH=$(PERLDIR);$(PATH)
408 !endif
409 @pushd "$(SSLDIR)" && $(PERL) Configure VC-WIN32 no-asm && popd
410 @pushd "$(SSLDIR)" && call ms\do_ms.bat && popd
411 @pushd "$(SSLDIR)" && $(MAKE) /f ms\nt.mak all && popd
412 !endif
413
414 !ifndef FOSSIL_ENABLE_MINIZ
415 APPTARGETS = $(APPTARGETS) zlib
416 !endif
417
418 !ifdef FOSSIL_ENABLE_SSL
 
419 APPTARGETS = $(APPTARGETS) openssl
 
420 !endif
421
422 $(APPNAME) : $(APPTARGETS) translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
423 cd $(OX)
424 link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
425
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -30,10 +30,13 @@
30 # Uncomment to enable miniz usage
31 # FOSSIL_ENABLE_MINIZ = 1
32
33 # Uncomment to enable SSL support
34 # FOSSIL_ENABLE_SSL = 1
35
36 # Uncomment to build SSL libraries
37 # FOSSIL_BUILD_SSL = 1
38
39 # Uncomment to enable TH1 scripts in embedded documentation files
40 # FOSSIL_ENABLE_TH1_DOCS = 1
41
42 # Uncomment to enable TH1 hooks
@@ -45,10 +48,26 @@
48 !ifdef FOSSIL_ENABLE_SSL
49 SSLDIR = $(B)\compat\openssl-1.0.1i
50 SSLINCDIR = $(SSLDIR)\inc32
51 SSLLIBDIR = $(SSLDIR)\out32
52 SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
53 !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
54 !message Using 'x64' platform for OpenSSL...
55 SSLCONFIG = VC-WIN64A no-asm
56 SSLSETUP = ms\do_win64a.bat
57 SSLNMAKE = ms\nt.mak all
58 !elseif "$(PLATFORM)"=="ia64"
59 !message Using 'ia64' platform for OpenSSL...
60 SSLCONFIG = VC-WIN64I no-asm
61 SSLSETUP = ms\do_win64i.bat
62 SSLNMAKE = ms\nt.mak all
63 !else
64 !message Assuming 'x86' platform for OpenSSL...
65 SSLCONFIG = VC-WIN32 no-asm
66 SSLSETUP = ms\do_ms.bat
67 SSLNMAKE = ms\nt.mak all
68 !endif
69 !endif
70
71 !ifdef FOSSIL_ENABLE_TCL
72 TCLDIR = $(B)\compat\tcl-8.6
73 TCLSRCDIR = $(TCLDIR)
@@ -404,21 +423,23 @@
423 openssl:
424 @echo Building OpenSSL from "$(SSLDIR)"...
425 !if "$(PERLDIR)" != ""
426 @set PATH=$(PERLDIR);$(PATH)
427 !endif
428 @pushd "$(SSLDIR)" && $(PERL) Configure $(SSLCONFIG) && popd
429 @pushd "$(SSLDIR)" && call $(SSLSETUP) && popd
430 @pushd "$(SSLDIR)" && $(MAKE) /f $(SSLNMAKE) && popd
431 !endif
432
433 !ifndef FOSSIL_ENABLE_MINIZ
434 APPTARGETS = $(APPTARGETS) zlib
435 !endif
436
437 !ifdef FOSSIL_ENABLE_SSL
438 !ifdef FOSSIL_BUILD_SSL
439 APPTARGETS = $(APPTARGETS) openssl
440 !endif
441 !endif
442
443 $(APPNAME) : $(APPTARGETS) translate$E mkindex$E headers $(OBJ) $(OX)\linkopts
444 cd $(OX)
445 link $(LDFLAGS) /OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
446
+2 -2
--- www/build.wiki
+++ www/build.wiki
@@ -126,14 +126,14 @@
126126
[/tree?ci=trunk&name=compat | compat] directory (e.g.
127127
"<b>compat/openssl-1.0.1i</b>"), then make sure that some recent
128128
<a href="http://www.perl.org/">Perl</a> binaries are installed locally,
129129
and finally run one of the following commands:
130130
<blockquote><pre>
131
-nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
131
+nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
132132
</pre></blockquote>
133133
<blockquote><pre>
134
-buildmsvc.bat FOSSIL_ENABLE_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
134
+buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
135135
</pre></blockquote>
136136
137137
<li><p><i>Cygwin</i> → The same as other unix-like systems. It is
138138
recommended to configure using: "<b>configure --disable-internal-sqlite</b>",
139139
making sure you have the "libsqlite3-devel" , "zlib-devel" and
140140
--- www/build.wiki
+++ www/build.wiki
@@ -126,14 +126,14 @@
126 [/tree?ci=trunk&name=compat | compat] directory (e.g.
127 "<b>compat/openssl-1.0.1i</b>"), then make sure that some recent
128 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
129 and finally run one of the following commands:
130 <blockquote><pre>
131 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
132 </pre></blockquote>
133 <blockquote><pre>
134 buildmsvc.bat FOSSIL_ENABLE_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
135 </pre></blockquote>
136
137 <li><p><i>Cygwin</i> → The same as other unix-like systems. It is
138 recommended to configure using: "<b>configure --disable-internal-sqlite</b>",
139 making sure you have the "libsqlite3-devel" , "zlib-devel" and
140
--- www/build.wiki
+++ www/build.wiki
@@ -126,14 +126,14 @@
126 [/tree?ci=trunk&name=compat | compat] directory (e.g.
127 "<b>compat/openssl-1.0.1i</b>"), then make sure that some recent
128 <a href="http://www.perl.org/">Perl</a> binaries are installed locally,
129 and finally run one of the following commands:
130 <blockquote><pre>
131 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
132 </pre></blockquote>
133 <blockquote><pre>
134 buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
135 </pre></blockquote>
136
137 <li><p><i>Cygwin</i> → The same as other unix-like systems. It is
138 recommended to configure using: "<b>configure --disable-internal-sqlite</b>",
139 making sure you have the "libsqlite3-devel" , "zlib-devel" and
140

Keyboard Shortcuts

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