Diff
Not logged in

Differences From Artifact [f3fa4a887d]:

To Artifact [678aa636f9]:


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
10
11
12
13
14
15
16


17
18
19
20
21
22
23







-
-







 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinPipe.c,v 1.65 2007/02/20 23:24:07 nijtmans Exp $
 */

#include "tclWinInt.h"

#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>

/*
 * The following variable is used to tell whether this module has been
 * initialized.
 */

194
195
196
197
198
199
200
201

202
203
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

229
230
231
232
233
234
235
192
193
194
195
196
197
198

199
200
201
202
203
204
205
206
207
208

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225

226
227
228
229
230
231
232
233







-
+









-
+
















-
+







			    int toRead, int *errorCode);
static int		PipeOutputProc(ClientData instanceData,
			    const char *buf, int toWrite, int *errorCode);
static DWORD WINAPI	PipeReaderThread(LPVOID arg);
static void		PipeSetupProc(ClientData clientData, int flags);
static void		PipeWatchProc(ClientData instanceData, int mask);
static DWORD WINAPI	PipeWriterThread(LPVOID arg);
static int		TempFileName(WCHAR name[MAX_PATH]);
static int		TempFileName(TCHAR name[MAX_PATH]);
static int		WaitForRead(PipeInfo *infoPtr, int blocking);
static void		PipeThreadActionProc(ClientData instanceData,
			    int action);

/*
 * This structure describes the channel type structure for command pipe based
 * I/O.
 */

static Tcl_ChannelType pipeChannelType = {
static const Tcl_ChannelType pipeChannelType = {
    "pipe",			/* Type name. */
    TCL_CHANNEL_VERSION_5,	/* v5 channel */
    TCL_CLOSE2PROC,		/* Close proc. */
    PipeInputProc,		/* Input proc. */
    PipeOutputProc,		/* Output proc. */
    NULL,			/* Seek proc. */
    NULL,			/* Set option proc. */
    NULL,			/* Get option proc. */
    PipeWatchProc,		/* Set up notifier to watch the channel. */
    PipeGetHandleProc,		/* Get an OS handle from channel. */
    PipeClose2Proc,		/* close2proc */
    PipeBlockModeProc,		/* Set blocking or non-blocking mode.*/
    NULL,			/* flush proc. */
    NULL,			/* handler proc. */
    NULL,			/* wide seek proc */
    PipeThreadActionProc,	/* thread action proc */
    NULL,                       /* truncate */
    NULL                       /* truncate */
};

/*
 *----------------------------------------------------------------------
 *
 * PipeInit --
 *
472
473
474
475
476
477
478
479

480
481
482

483
484
485

486
487

488
489
490
491
492
493
494
495
496


497
498

499
500
501
502
503
504
505
470
471
472
473
474
475
476

477
478
479

480



481


482
483
484
485






486
487


488
489
490
491
492
493
494
495







-
+


-
+
-
-
-
+
-
-
+



-
-
-
-
-
-
+
+
-
-
+







 *	None.
 *
 *----------------------------------------------------------------------
 */

static int
TempFileName(
    WCHAR name[MAX_PATH])	/* Buffer in which name for temporary file
    TCHAR name[MAX_PATH])	/* Buffer in which name for temporary file
				 * gets stored. */
{
    TCHAR *prefix;
    TCHAR *prefix = TEXT("TCL");

    prefix = (tclWinProcs->useWide) ? (TCHAR *) L"TCL" : (TCHAR *) "TCL";
    if (tclWinProcs->getTempPathProc(MAX_PATH, name) != 0) {
    if (GetTempPath(MAX_PATH, name) != 0) {
	if (tclWinProcs->getTempFileNameProc((TCHAR *) name, prefix, 0,
		name) != 0) {
	if (GetTempFileName(name, prefix, 0, name) != 0) {
	    return 1;
	}
    }
    if (tclWinProcs->useWide) {
	((WCHAR *) name)[0] = '.';
	((WCHAR *) name)[1] = '\0';
    } else {
	((char *) name)[0] = '.';
	((char *) name)[1] = '\0';
    name[0] = '.';
    name[1] = '\0';
    }
    return tclWinProcs->getTempFileNameProc((TCHAR *) name, prefix, 0, name);
    return GetTempFileName(name, prefix, 0, name);
}

/*
 *----------------------------------------------------------------------
 *
 * TclpMakeFile --
 *
603
604
605
606
607
608
609
610

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626

627
628
629
630
631
632
633
593
594
595
596
597
598
599

600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615

616
617
618
619
620
621
622
623







-
+















-
+








    /*
     * If the file is not being created, use the existing file attributes.
     */

    flags = 0;
    if (!(mode & O_CREAT)) {
	flags = tclWinProcs->getFileAttributesProc(nativePath);
	flags = GetFileAttributes(nativePath);
	if (flags == 0xFFFFFFFF) {
	    flags = 0;
	}
    }

    /*
     * Set up the file sharing mode.  We want to allow simultaneous access.
     */

    shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;

    /*
     * Now we get to create the file.
     */

    handle = tclWinProcs->createFileProc(nativePath, accessMode, shareMode,
    handle = CreateFile(nativePath, accessMode, shareMode,
	    NULL, createMode, flags, NULL);
    Tcl_DStringFree(&ds);

    if (handle == INVALID_HANDLE_VALUE) {
	DWORD err;

	err = GetLastError();
667
668
669
670
671
672
673
674

675
676
677
678
679
680
681
682
683

684
685
686
687
688
689
690
657
658
659
660
661
662
663

664
665
666
667
668
669
670
671
672

673
674
675
676
677
678
679
680







-
+








-
+







 *----------------------------------------------------------------------
 */

TclFile
TclpCreateTempFile(
    const char *contents)	/* String to write into temp file, or NULL. */
{
    WCHAR name[MAX_PATH];
    TCHAR name[MAX_PATH];
    const char *native;
    Tcl_DString dstring;
    HANDLE handle;

    if (TempFileName(name) == 0) {
	return NULL;
    }

    handle = tclWinProcs->createFileProc((TCHAR *) name,
    handle = CreateFile(name,
	    GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
	    FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL);
    if (handle == INVALID_HANDLE_VALUE) {
	goto error;
    }

    /*
736
737
738
739
740
741
742
743

744
745
746
747
748
749
750
726
727
728
729
730
731
732

733
734
735
736
737
738
739
740







-
+








    if (contents != NULL) {
	Tcl_DStringFree(&dstring);
    }

    TclWinConvertError(GetLastError());
    CloseHandle(handle);
    tclWinProcs->deleteFileProc((TCHAR *) name);
    DeleteFile(name);
    return NULL;
}

/*
 *----------------------------------------------------------------------
 *
 * TclpTempFileName --
759
760
761
762
763
764
765
766

767
768
769
770
771
772

773
774
775
776
777
778
779
749
750
751
752
753
754
755

756
757
758
759
760
761

762
763
764
765
766
767
768
769







-
+





-
+







 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclpTempFileName(void)
{
    WCHAR fileName[MAX_PATH];
    TCHAR fileName[MAX_PATH];

    if (TempFileName(fileName) == 0) {
	return NULL;
    }

    return TclpNativeToNormalized((ClientData) fileName);
    return TclpNativeToNormalized(fileName);
}

/*
 *----------------------------------------------------------------------
 *
 * TclpCreatePipe --
 *
952
953
954
955
956
957
958
959

960
961
962
963
964
965
966
942
943
944
945
946
947
948

949
950
951
952
953
954
955
956







-
+







				 * may be the same as outputFile. */
    Tcl_Pid *pidPtr)		/* If this function is successful, pidPtr is
				 * filled with the process id of the child
				 * process. */
{
    int result, applType, createFlags;
    Tcl_DString cmdLine;	/* Complete command line (TCHAR). */
    STARTUPINFOA startInfo;
    STARTUPINFO startInfo;
    PROCESS_INFORMATION procInfo;
    SECURITY_ATTRIBUTES secAtts;
    HANDLE hProcess, h, inputHandle, outputHandle, errorHandle;
    char execPath[MAX_PATH * TCL_UTF_MAX];
    WinFile *filePtr;

    PipeInit();
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214



1215
1216
1217
1218

1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1131
1132
1133
1134
1135
1136
1137



































































1138
1139
1140




1141





1142
1143
1144
1145
1146
1147
1148







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
+
-
-
-
-
-







	if (HasConsole()) {
	    createFlags = 0;
	} else {
	    createFlags = DETACHED_PROCESS;
	}

	if (applType == APPL_DOS) {
	    /*
	     * Under Windows 95, 16-bit DOS applications do not work well with
	     * pipes:
	     *
	     * 1. EOF on a pipe between a detached 16-bit DOS application and
	     * another application is not seen at the other end of the pipe,
	     * so the listening process blocks forever on reads. This inablity
	     * to detect EOF happens when either a 16-bit app or the 32-bit
	     * app is the listener.
	     *
	     * 2. If a 16-bit DOS application (detached or not) blocks when
	     * writing to a pipe, it will never wake up again, and it
	     * eventually brings the whole system down around it.
	     *
	     * The 16-bit application is run as a normal process inside of a
	     * hidden helper console app, and this helper may be run as a
	     * detached process. If any of the stdio handles is a pipe, the
	     * helper application accumulates information into temp files and
	     * forwards it to or from the DOS application as appropriate.
	     * This means that DOS apps must receive EOF from a stdin pipe
	     * before they will actually begin, and must finish generating
	     * stdout or stderr before the data will be sent to the next stage
	     * of the pipe.
	     *
	     * The helper app should be located in the same directory as the
	     * tcl dll.
	     */
	    Tcl_Obj *tclExePtr, *pipeDllPtr;
	    char *start, *end;
	    int i, fileExists;
	    Tcl_DString pipeDll;

	    if (createFlags != 0) {
		startInfo.wShowWindow = SW_HIDE;
		startInfo.dwFlags |= STARTF_USESHOWWINDOW;
		createFlags = CREATE_NEW_CONSOLE;
	    }

	    Tcl_DStringInit(&pipeDll);
	    Tcl_DStringAppend(&pipeDll, TCL_PIPE_DLL, -1);
	    tclExePtr = TclGetObjNameOfExecutable();
	    Tcl_IncrRefCount(tclExePtr);
	    start = Tcl_GetStringFromObj(tclExePtr, &i);
	    for (end = start + (i-1); end > start; end--) {
		if (*end == '/') {
		    break;
		}
	    }
	    if (*end != '/') {
		Tcl_AppendResult(interp, "no / in executable path name \"",
			start, "\"", (char *) NULL);
		Tcl_DecrRefCount(tclExePtr);
		Tcl_DStringFree(&pipeDll);
		goto end;
	    }
	    i = (end - start) + 1;
	    pipeDllPtr = Tcl_NewStringObj(start, i);
	    Tcl_AppendToObj(pipeDllPtr, Tcl_DStringValue(&pipeDll), -1);
	    Tcl_IncrRefCount(pipeDllPtr);
	    if (Tcl_FSConvertToPathType(interp, pipeDllPtr) != TCL_OK) {
		Tcl_Panic("Tcl_FSConvertToPathType failed");
	    }
	    fileExists = (Tcl_FSAccess(pipeDllPtr, F_OK) == 0);
	    if (!fileExists) {
		Tcl_AppendResult(interp, "Tcl pipe dll \"",
			Tcl_DStringValue(&pipeDll), "\" not found",
			(char *) NULL);
	    Tcl_AppendResult(interp,
		    "DOS application process not supported on this platform",
		    (char *) NULL);
		Tcl_DecrRefCount(tclExePtr);
		Tcl_DecrRefCount(pipeDllPtr);
		Tcl_DStringFree(&pipeDll);
		goto end;
	    goto end;
	    }
	    Tcl_DStringAppend(&cmdLine, Tcl_DStringValue(&pipeDll), -1);
	    Tcl_DecrRefCount(tclExePtr);
	    Tcl_DecrRefCount(pipeDllPtr);
	    Tcl_DStringFree(&pipeDll);
	}
    }

    /*
     * cmdLine gets the full command line used to invoke the executable,
     * including the name of the executable itself. The command line arguments
     * in argv[] are stored in cmdLine separated by spaces. Special characters
1240
1241
1242
1243
1244
1245
1246
1247

1248
1249
1250
1251
1252
1253
1254
1158
1159
1160
1161
1162
1163
1164

1165
1166
1167
1168
1169
1170
1171
1172







-
+







     * Additionally, when calling a 16-bit dos or windows application, all
     * path names must use the short, cryptic, path format (e.g., using
     * ab~1.def instead of "a b.default").
     */

    BuildCommandLine(execPath, argc, argv, &cmdLine);

    if (tclWinProcs->createProcessProc(NULL,
    if (CreateProcess(NULL,
	    (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE,
	    (DWORD) createFlags, NULL, NULL, &startInfo, &procInfo) == 0) {
	TclWinConvertError(GetLastError());
	Tcl_AppendResult(interp, "couldn't execute \"", argv[0],
		"\": ", Tcl_PosixError(interp), (char *) NULL);
	goto end;
    }
1373
1374
1375
1376
1377
1378
1379
1380

1381
1382
1383
1384
1385
1386
1387
1291
1292
1293
1294
1295
1296
1297

1298
1299
1300
1301
1302
1303
1304
1305







-
+







    TCHAR *rest;
    char *ext;
    char buf[2];
    DWORD attr, read;
    IMAGE_DOS_HEADER header;
    Tcl_DString nameBuf, ds;
    const TCHAR *nativeName;
    WCHAR nativeFullPath[MAX_PATH];
    TCHAR nativeFullPath[MAX_PATH];
    static char extensions[][5] = {"", ".com", ".exe", ".bat"};

    /*
     * Look for the program as an external program. First try the name as it
     * is, then try adding .com, .exe, and .bat, in that order, to the name,
     * looking for an executable.
     *
1399
1400
1401
1402
1403
1404
1405
1406

1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418

1419
1420
1421
1422

1423
1424
1425
1426

1427
1428
1429
1430
1431

1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450

1451
1452
1453
1454
1455
1456
1457
1317
1318
1319
1320
1321
1322
1323

1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335

1336
1337
1338
1339

1340
1341
1342
1343

1344
1345
1346
1347
1348

1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367

1368
1369
1370
1371
1372
1373
1374
1375







-
+











-
+



-
+



-
+




-
+


















-
+







    nameLen = Tcl_DStringLength(&nameBuf);

    for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
	Tcl_DStringSetLength(&nameBuf, nameLen);
	Tcl_DStringAppend(&nameBuf, extensions[i], -1);
	nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf),
		Tcl_DStringLength(&nameBuf), &ds);
	found = tclWinProcs->searchPathProc(NULL, nativeName, NULL, MAX_PATH,
	found = SearchPath(NULL, nativeName, NULL, MAX_PATH,
		nativeFullPath, &rest);
	Tcl_DStringFree(&ds);
	if (found == 0) {
	    continue;
	}

	/*
	 * Ignore matches on directories or data files, return if identified a
	 * known type.
	 */

	attr = tclWinProcs->getFileAttributesProc((TCHAR *) nativeFullPath);
	attr = GetFileAttributes(nativeFullPath);
	if ((attr == 0xffffffff) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
	    continue;
	}
	strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
	strcpy(fullName, Tcl_WinTCharToUtf(nativeFullPath, -1, &ds));
	Tcl_DStringFree(&ds);

	ext = strrchr(fullName, '.');
	if ((ext != NULL) && (stricmp(ext, ".bat") == 0)) {
	if ((ext != NULL) && (strcasecmp(ext, ".bat") == 0)) {
	    applType = APPL_DOS;
	    break;
	}

	hFile = tclWinProcs->createFileProc((TCHAR *) nativeFullPath,
	hFile = CreateFile(nativeFullPath,
		GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
	    continue;
	}

	header.e_magic = 0;
	ReadFile(hFile, (void *) &header, sizeof(header), &read, NULL);
	if (header.e_magic != IMAGE_DOS_SIGNATURE) {
	    /*
	     * Doesn't have the magic number for relocatable executables. If
	     * filename ends with .com, assume it's a DOS application anyhow.
	     * Note that we didn't make this assumption at first, because some
	     * supposed .com files are really 32-bit executables with all the
	     * magic numbers and everything.
	     */

	    CloseHandle(hFile);
	    if ((ext != NULL) && (stricmp(ext, ".com") == 0)) {
	    if ((ext != NULL) && (strcasecmp(ext, ".com") == 0)) {
		applType = APPL_DOS;
		break;
	    }
	    continue;
	}
	if (header.e_lfarlc != sizeof(header)) {
	    /*
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513


1514
1515
1516
1517
1518
1519
1520
1422
1423
1424
1425
1426
1427
1428



1429
1430
1431
1432
1433
1434
1435
1436
1437







-
-
-
+
+







	/*
	 * Replace long path name of executable with short path name for
	 * 16-bit applications. Otherwise the application may not be able to
	 * correctly parse its own command line to separate off the
	 * application name from the arguments.
	 */

	tclWinProcs->getShortPathNameProc((TCHAR *) nativeFullPath,
		nativeFullPath, MAX_PATH);
	strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
	GetShortPathName(nativeFullPath, nativeFullPath, MAX_PATH);
	strcpy(fullName, Tcl_WinTCharToUtf(nativeFullPath, -1, &ds));
	Tcl_DStringFree(&ds);
    }
    return applType;
}

/*
 *----------------------------------------------------------------------
2684
2685
2686
2687
2688
2689
2690
2691
2692


2693
2694
2695
2696
2697
2698
2699
2601
2602
2603
2604
2605
2606
2607


2608
2609
2610
2611
2612
2613
2614
2615
2616







-
-
+
+







 *	knows about it.
 *
 *----------------------------------------------------------------------
 */

void
TclWinAddProcess(
    HANDLE hProcess,		/* Handle to process */
    DWORD id)			/* Global process identifier */
    void *hProcess,		/* Handle to process */
    unsigned long id)		/* Global process identifier */
{
    ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo));

    PipeInit();

    procPtr->hProcess = hProcess;
    procPtr->dwProcessId = id;
3170
3171
3172
3173
3174
3175
3176
3177

3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189

3190
3191
3192
3193
3194

3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206

3207
3208

3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225

3226
3227

3228
3229
3230
3231

3232
3233
3234
3235
3236
3237
3238
3087
3088
3089
3090
3091
3092
3093

3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105

3106
3107
3108
3109


3110



3111
3112
3113
3114
3115
3116
3117
3118

3119


3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134



3135


3136

3137
3138

3139
3140
3141
3142
3143
3144
3145
3146







-
+











-
+



-
-
+
-
-
-








-
+
-
-
+














-
-
-
+
-
-
+
-


-
+







Tcl_Channel
TclpOpenTemporaryFile(
    Tcl_Obj *dirObj,
    Tcl_Obj *basenameObj,
    Tcl_Obj *extensionObj,
    Tcl_Obj *resultingNameObj)
{
    WCHAR name[MAX_PATH];
    TCHAR name[MAX_PATH];
    char *namePtr;
    HANDLE handle;
    DWORD flags = FILE_ATTRIBUTE_TEMPORARY;
    int length, counter, counter2;
    Tcl_DString buf;

    if (!resultingNameObj) {
	flags |= FILE_FLAG_DELETE_ON_CLOSE;
    }

    namePtr = (char *) name;
    length = tclWinProcs->getTempPathProc(MAX_PATH, name);
    length = GetTempPath(MAX_PATH, name);
    if (length == 0) {
	goto gotError;
    }
    if (tclWinProcs->useWide) {
	namePtr += length * sizeof(WCHAR);
    namePtr += length * sizeof(TCHAR);
    } else {
	namePtr += length;
    }
    if (basenameObj) {
	const char *string = Tcl_GetStringFromObj(basenameObj, &length);

	Tcl_WinUtfToTChar(string, length, &buf);
	memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf));
	namePtr += Tcl_DStringLength(&buf);
	Tcl_DStringFree(&buf);
    } else {
	TCHAR *baseStr = tclWinProcs->useWide ?
	TCHAR *baseStr = TEXT("TCL");
		(TCHAR *) L"TCL" : (TCHAR *) "TCL";
	int length = tclWinProcs->useWide ? 3*sizeof(WCHAR) : 3;
	int length = 3 * sizeof(TCHAR);

	memcpy(namePtr, baseStr, length);
	namePtr += length;
    }
    counter = TclpGetClicks() % 65533;
    counter2 = 1024;			/* Only try this many times! Prevents
					 * an infinite loop. */

    do {
	char number[TCL_INTEGER_SPACE + 4];

	sprintf(number, "%d.TMP", counter);
	counter = (unsigned short) (counter + 1);
	Tcl_WinUtfToTChar(number, strlen(number), &buf);
	memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf));
	if (tclWinProcs->useWide) {
	    *(WCHAR *)(namePtr + Tcl_DStringLength(&buf) + 1) = '\0';
	Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf) + 1);
	} else {
	    namePtr[Tcl_DStringLength(&buf) + 1] = '\0';
	memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf) + 1);
	}
	Tcl_DStringFree(&buf);

	handle = tclWinProcs->createFileProc((TCHAR *) name,
	handle = CreateFile(name,
		GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, flags, NULL);
    } while (handle == INVALID_HANDLE_VALUE
	    && --counter2 > 0
	    && GetLastError() == ERROR_FILE_EXISTS);
    if (handle == INVALID_HANDLE_VALUE) {
	goto gotError;
    }