Diff
Not logged in

Differences From Artifact [bd80f0944e]:

To Artifact [ba5438c7e5]:


13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
13
14
15
16
17
18
19

20
21
22
23
24
25
26
27







-
+







 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIOUtil.c,v 1.81.2.15 2005/01/24 21:44:38 dgp Exp $
 * RCS: @(#) $Id: tclIOUtil.c,v 1.81.2.16 2005/04/29 22:40:25 dgp Exp $
 */

#include "tclInt.h"
#ifdef __WIN32__
#include "tclWinInt.h"
#endif
#include "tclFileSystem.h"
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
1458
1459
1460
1461
1462
1463
1464
1465



1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477


1478
1479
1480

1481
1482
1483
1484






1485
1486
1487
1488
1489









1490

1491

1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505

1506
1507
1508
1509

1510
1511
1512
1513
1514
1515
1516
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
1458
1459

1460
1461
1462
1463
1464
1465
1466
1467
1468
1469

1470

1471
1472
1473

1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501



1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520

1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531





1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542

1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556

1557
1558
1559
1560

1561
1562
1563
1564
1565
1566
1567
1568








+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
+
+
+








-
+
+
+







-

-
+


-
+




+
+
+












+







-
-
-
+
+
+












+
+


-
+




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

+
-
+













-
+



-
+







}

/*
 *---------------------------------------------------------------------------
 *
 * TclGetOpenMode --
 *
 * Description:
 * 	This routine is an obsolete, limited version of
 * 	TclGetOpenModeEx() below.  It exists only to satisfy any
 * 	extensions imprudently using it via Tcl's internal stubs table.
 *
 * Results:
 * 	Same as TclGetOpenModeEx().
 *
 * Side effects:
 * 	Same as TclGetOpenModeEx().
 *
 *---------------------------------------------------------------------------
 */

int
TclGetOpenMode(interp, modeString, seekFlagPtr)
    Tcl_Interp *interp;			/* Interpreter to use for error
					 * reporting - may be NULL. */
    CONST char *modeString;		/* Mode string, e.g. "r+" or
					 * "RDONLY CREAT". */
    int *seekFlagPtr;			/* Set this to 1 if the caller
                                         * should seek to EOF during the
                                         * opening of the file. */
{
    int binary = 0;
    return TclGetOpenModeEx(interp, modeString, seekFlagPtr, &binary);
}

/*
 *---------------------------------------------------------------------------
 *
 * TclGetOpenModeEx --
 *
 * Description:
 *	Computes a POSIX mode mask for opening a file, from a given string,
 *	and also sets a flag to indicate whether the caller should seek to
 *	EOF after opening the file.
 *	and also sets flags to indicate whether the caller should seek to
 *	EOF after opening the file, and whether the caller should
 *	configure the channel for binary data.
 *
 * Results:
 *	On success, returns mode to pass to "open". If an error occurs, the
 *	return value is -1 and if interp is not NULL, sets interp's result
 *	object to an error message.
 *
 * Side effects:
 *	Sets the integer referenced by seekFlagPtr to 1 to tell the caller
 *	to seek to EOF after opening the file.
 *	to seek to EOF after opening the file, or to 0 otherwise.  Sets the
 *	integer referenced by binaryPtr to 1 to tell the caller	to seek to
 *	configure the channel for binary data, or to 0 otherwise.
 *
 * Special note:
 *	This code is based on a prototype implementation contributed
 *	by Mark Diekhans.
 *
 *---------------------------------------------------------------------------
 */

int
TclGetOpenMode(interp, string, seekFlagPtr)
TclGetOpenModeEx(interp, modeString, seekFlagPtr, binaryPtr)
    Tcl_Interp *interp;			/* Interpreter to use for error
					 * reporting - may be NULL. */
    CONST char *string;			/* Mode string, e.g. "r+" or
    CONST char *modeString;		/* Mode string, e.g. "r+" or
					 * "RDONLY CREAT". */
    int *seekFlagPtr;			/* Set this to 1 if the caller
                                         * should seek to EOF during the
                                         * opening of the file. */
    int *binaryPtr;			/* Set this to 1 if the caller
					 * should configure the opened
					 * channel for binary operations */
{
    int mode, modeArgc, c, i, gotRW;
    CONST char **modeArgv, *flag;
#define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR)

    /*
     * Check for the simpler fopen-like access modes (e.g. "r").  They
     * are distinguished from the POSIX access modes by the presence
     * of a lower-case first letter.
     */

    *seekFlagPtr = 0;
    *binaryPtr = 0;
    mode = 0;

    /*
     * Guard against international characters before using byte oriented
     * routines.
     */

    if (!(string[0] & 0x80)
	    && islower(UCHAR(string[0]))) { /* INTL: ISO only. */
	switch (string[0]) {
    if (!(modeString[0] & 0x80)
	    && islower(UCHAR(modeString[0]))) { /* INTL: ISO only. */
	switch (modeString[0]) {
	    case 'r':
		mode = O_RDONLY;
		break;
	    case 'w':
		mode = O_WRONLY|O_CREAT|O_TRUNC;
		break;
	    case 'a':
		mode = O_WRONLY|O_CREAT;
                *seekFlagPtr = 1;
		break;
	    default:
		error:
                *seekFlagPtr = 0;
		*binaryPtr = 0;
                if (interp != (Tcl_Interp *) NULL) {
                    Tcl_AppendResult(interp,
                            "illegal access mode \"", string, "\"",
                            "illegal access mode \"", modeString, "\"",
                            (char *) NULL);
                }
		return -1;
	}
	i=1;
	while (i<3 && modeString[i]) {
	    if (modeString[i] == modeString[i-1]) {
		goto error;
	    }
	    switch (modeString[i++]) {
	if (string[1] == '+') {
	    mode &= ~(O_RDONLY|O_WRONLY);
	    mode |= O_RDWR;
	    if (string[2] != 0) {
		goto error;
		case '+':
		    mode &= ~(O_RDONLY|O_WRONLY);
		    mode |= O_RDWR;
		    break;
		case 'b':
		    *binaryPtr = 1;
		    break;
		default:
		    goto error;
	    }
	}
	} else if (string[1] != 0) {
	if (modeString[i] != 0) {
	    goto error;
	}
        return mode;
    }

    /*
     * The access modes are specified using a list of POSIX modes
     * such as O_CREAT.
     *
     * IMPORTANT NOTE: We rely on Tcl_SplitList working correctly when
     * a NULL interpreter is passed in.
     */

    if (Tcl_SplitList(interp, string, &modeArgc, &modeArgv) != TCL_OK) {
    if (Tcl_SplitList(interp, modeString, &modeArgc, &modeArgv) != TCL_OK) {
        if (interp != (Tcl_Interp *) NULL) {
            Tcl_AddErrorInfo(interp,
                    "\n    while processing open access modes \"");
            Tcl_AddErrorInfo(interp, string);
            Tcl_AddErrorInfo(interp, modeString);
            Tcl_AddErrorInfo(interp, "\"");
        }
        return -1;
    }
    
    gotRW = 0;
    for (i = 0; i < modeArgc; i++) {
1556
1557
1558
1559
1560
1561
1562


1563
1564
1565
1566
1567



1568
1569
1570
1571
1572
1573
1574
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619


1620
1621
1622
1623
1624
1625
1626
1627
1628
1629







+
+



-
-
+
+
+







                        "\" not supported by this system", (char *) NULL);
            }
            ckfree((char *) modeArgv);
	    return -1;
#endif
	} else if ((c == 'T') && (strcmp(flag, "TRUNC") == 0)) {
	    mode |= O_TRUNC;
	} else if ((c == 'B') && (strcmp(flag, "BINARY") == 0)) {
	    *binaryPtr = 1;
	} else {
            if (interp != (Tcl_Interp *) NULL) {
                Tcl_AppendResult(interp, "invalid access mode \"", flag,
                        "\": must be RDONLY, WRONLY, RDWR, APPEND, CREAT",
                        " EXCL, NOCTTY, NONBLOCK, or TRUNC", (char *) NULL);
			"\": must be RDONLY, WRONLY, RDWR, APPEND, BINARY, "
			"CREAT, EXCL, NOCTTY, NONBLOCK, or TRUNC",
			(char *) NULL);
            }
	    ckfree((char *) modeArgv);
	    return -1;
	}
    }
    ckfree((char *) modeArgv);
    if (!gotRW) {
2083
2084
2085
2086
2087
2088
2089
2090
2091


2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109




2110
2111
2112
2113
2114
2115
2116
2138
2139
2140
2141
2142
2143
2144


2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175







-
-
+
+


















+
+
+
+







        return NULL;
    }
    
    fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
    if (fsPtr != NULL) {
	Tcl_FSOpenFileChannelProc *proc = fsPtr->openFileChannelProc;
	if (proc != NULL) {
	    int mode, seekFlag;
	    mode = TclGetOpenMode(interp, modeString, &seekFlag);
	    int mode, seekFlag, binary;
	    mode = TclGetOpenModeEx(interp, modeString, &seekFlag, &binary);
	    if (mode == -1) {
	        return NULL;
	    }
	    retVal = (*proc)(interp, pathPtr, mode, permissions);
	    if (retVal != NULL) {
		if (seekFlag) {
		    if (Tcl_Seek(retVal, (Tcl_WideInt)0, 
				 SEEK_END) < (Tcl_WideInt)0) {
			if (interp != (Tcl_Interp *) NULL) {
			    Tcl_AppendResult(interp,
			      "could not seek to end of file while opening \"",
			      Tcl_GetString(pathPtr), "\": ", 
			      Tcl_PosixError(interp), (char *) NULL);
			}
			Tcl_Close(NULL, retVal);
			return NULL;
		    }
		}
		if (binary) {
		    Tcl_SetChannelOption(interp, retVal,
			    "-translation", "binary");
		}
	    }
	    return retVal;
	}
    }
    /* File doesn't belong to any filesystem that can open it */
    Tcl_SetErrno(ENOENT);
    if (interp != NULL) {
2983
2984
2985
2986
2987
2988
2989

2990

2991
2992
2993
2994
2995
2996
2997
3042
3043
3044
3045
3046
3047
3048
3049

3050
3051
3052
3053
3054
3055
3056
3057







+
-
+







		    if (symbols[i] != NULL) {
			*procPtrs[i] = TclpFindSymbol(interp, *handlePtr, 
						      symbols[i]);
		    }
		}
		/* Copy this across, since both are equal for the native fs */
		*clientDataPtr = (ClientData)*handlePtr;
                Tcl_ResetResult(interp);
		return retVal;
		return TCL_OK;
	    }
	    if (Tcl_GetErrno() != EXDEV) {
	        return retVal;
	    }
	}
	/* 
	 * The filesystem doesn't support 'load', so we fall back on
3008
3009
3010
3011
3012
3013
3014


3015

3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028


3029

3030
3031
3032
3033
3034
3035
3036
3068
3069
3070
3071
3072
3073
3074
3075
3076

3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092

3093
3094
3095
3096
3097
3098
3099
3100







+
+
-
+













+
+
-
+







	
	/* 
	 * Get a temporary filename to use, first to
	 * copy the file into, and then to load. 
	 */
	copyToPtr = TclpTempFileName();
	if (copyToPtr == NULL) {
	    Tcl_AppendResult(interp, "couldn't create temporary file: ",
			     Tcl_PosixError(interp), (char *) NULL);
	    return -1;
	    return TCL_ERROR;
	}
	Tcl_IncrRefCount(copyToPtr);
	
	copyFsPtr = Tcl_FSGetFileSystemForPath(copyToPtr);
	if ((copyFsPtr == NULL) || (copyFsPtr == fsPtr)) {
	    /* 
	     * We already know we can't use Tcl_FSLoadFile from 
	     * this filesystem, and we must avoid a possible
	     * infinite loop.  Try to delete the file we
	     * probably created, and then exit.
	     */
	    Tcl_FSDeleteFile(copyToPtr);
	    Tcl_DecrRefCount(copyToPtr);
	    Tcl_AppendResult(interp, "couldn't load from current filesystem",
			     (char *) NULL);
	    return -1;
	    return TCL_ERROR;
	}
	
	if (TclCrossFilesystemCopy(interp, pathPtr, copyToPtr) == TCL_OK) {
	    Tcl_LoadHandle newLoadHandle = NULL;
	    ClientData newClientData = NULL;
	    Tcl_FSUnloadFileProc *newUnloadProcPtr = NULL;
	    FsDivertLoad *tvdlPtr;
3087
3088
3089
3090
3091
3092
3093

3094
3095
3096
3097
3098
3099
3100
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165







+







		 * by 'load' will store the original (vfs)
		 * path alongside the temporary load handle
		 * and unload proc ptr.
		 */
		(*handlePtr) = newLoadHandle;
		(*clientDataPtr) = newClientData;
		(*unloadProcPtr) = newUnloadProcPtr;
		Tcl_ResetResult(interp);
		return TCL_OK;
	    }
	    /* 
	     * When we unload this file, we need to divert the 
	     * unloading so we can unload and cleanup the 
	     * temporary file correctly.
	     */
3135
3136
3137
3138
3139
3140
3141

3142
3143
3144
3145
3146
3147
3148
3149
3150
3151

3152
3153
3154
3155
3156
3157
3158
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







+









-
+







		Tcl_DecrRefCount(copyToPtr);
	    }

	    copyToPtr = NULL;
	    (*handlePtr) = newLoadHandle;
	    (*clientDataPtr) = (ClientData)tvdlPtr;
	    (*unloadProcPtr) = &FSUnloadTempFile;
	    Tcl_ResetResult(interp);
	    return retVal;
	} else {
	    /* Cross-platform copy failed */
	    Tcl_FSDeleteFile(copyToPtr);
	    Tcl_DecrRefCount(copyToPtr);
	    return TCL_ERROR;
	}
    }
    Tcl_SetErrno(ENOENT);
    return -1;
    return TCL_ERROR;
}
/* 
 * This function used to be in the platform specific directories, but it
 * has now been made to work cross-platform
 */
int
TclpLoadFile(interp, pathPtr, sym1, sym2, proc1Ptr, proc2Ptr,