summaryrefslogtreecommitdiffstats
path: root/win/tclWinFile.c
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2014-05-15 14:54:45 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2014-05-15 14:54:45 (GMT)
commit47b1f4425678fcc051e9a75f59f6c4cd4f21b176 (patch)
treecdbc77bc0588dd7ed0f06b4d9250ebb889dbb7d1 /win/tclWinFile.c
parent5e610145644e54a301c3f508b6c6fb4dcf95f7b6 (diff)
downloadtcl-47b1f4425678fcc051e9a75f59f6c4cd4f21b176.zip
tcl-47b1f4425678fcc051e9a75f59f6c4cd4f21b176.tar.gz
tcl-47b1f4425678fcc051e9a75f59f6c4cd4f21b176.tar.bz2
Fix [3118489]: NUL in filenames. (On Windows, protect against invalid use of ':' in filenames as well)
Diffstat (limited to 'win/tclWinFile.c')
-rw-r--r--win/tclWinFile.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index ed0c40f..9bf63b1 100644
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -1856,6 +1856,9 @@ TclpObjChdir(
nativePath = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
+ if (!nativePath) {
+ return -1;
+ }
result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath);
if (result == 0) {
@@ -3200,13 +3203,69 @@ TclNativeCreateNativeRep(
Tcl_WinUtfToTChar(str, len, &ds);
if (tclWinProcs->useWide) {
WCHAR *wp = (WCHAR *) Tcl_DStringValue(&ds);
- for (; *wp; ++wp) {
- if (*wp=='/') {
+ len = Tcl_DStringLength(&ds)>>1;
+ /*
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ wp[0] = wp[1] = wp[3] = '\\';
+ str += 4;
+ wp += 4;
+ len -= 4;
+ }
+ /*
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ wp += 2;
+ len -= 2;
+ }
+ while (len-->0) {
+ if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*wp=='/') {
*wp = '\\';
}
+ ++wp;
}
len = Tcl_DStringLength(&ds) + sizeof(WCHAR);
} else {
+ char *p = Tcl_DStringValue(&ds);
+ len = Tcl_DStringLength(&ds);
+ /*
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ p[0] = p[1] = p[3] = '\\';
+ str += 4;
+ p += 4;
+ len -= 4;
+ }
+ /*
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ p += 2;
+ len -= 2;
+ }
+ while (len-->0) {
+ if ((*p < ' ') || strchr("\"*:<>?|", *p)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*p=='/') {
+ *p = '\\';
+ }
+ ++p;
+ }
len = Tcl_DStringLength(&ds) + sizeof(char);
}
Tcl_DecrRefCount(validPathPtr);