Diff
Not logged in

Differences From Artifact [cf735b9423]:

To Artifact [ecc338ea91]:


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.
 * Copyright (c) 2001-2004 Vincent Darley.
 *
 * 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.45 2009/01/05 14:54:20 dgp Exp $
 * RCS: @(#) $Id: tclIOUtil.c,v 1.81.2.46 2009/01/06 15:06:50 dgp Exp $
 */

#include "tclInt.h"
#ifdef __WIN32__
#   include "tclWinInt.h"
#endif
#include "tclFileSystem.h"
137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151







-
+







    &TclpObjRemoveDirectory,
    &TclpObjDeleteFile,
    &TclpObjCopyFile,
    &TclpObjRenameFile,
    &TclpObjCopyDirectory,
    &TclpObjLstat,
    &TclpDlopen,
    /* Needs a cast since we're using version_2 */
    /* Needs a cast since we're using version_2. */
    (Tcl_FSGetCwdProc *) &TclpGetNativeCwd,
    &TclpObjChdir
};

/*
 * Define the tail of the linked list. Note that for unconventional uses of
 * Tcl without a native filesystem, we may in the future wish to modify the
247
248
249
250
251
252
253
254
255


256
257

258
259
260
261
262
263
264
247
248
249
250
251
252
253


254
255
256

257
258
259
260
261
262
263
264







-
-
+
+

-
+







	 * Note that ino_t/ino64_t is unsigned...
	 *
	 * Workaround gcc warning of "comparison is always false due to
	 * limited range of data type" by assigning to tmp var of type
	 * Tcl_WideInt.
	 */

        tmp1 = (Tcl_WideInt) buf.st_ino;
        tmp2 = (Tcl_WideInt) buf.st_size;
	tmp1 = (Tcl_WideInt) buf.st_ino;
	tmp2 = (Tcl_WideInt) buf.st_size;
#ifdef HAVE_ST_BLOCKS
        tmp3 = (Tcl_WideInt) buf.st_blocks;
	tmp3 = (Tcl_WideInt) buf.st_blocks;
#endif

	if (OUT_OF_URANGE(tmp1) || OUT_OF_RANGE(tmp2)
#ifdef HAVE_ST_BLOCKS
		|| OUT_OF_RANGE(tmp3)
#endif
	    ) {
385
386
387
388
389
390
391
392

393
394
395
396
397
398
399
385
386
387
388
389
390
391

392
393
394
395
396
397
398
399







-
+







    Tcl_IncrRefCount(pathPtr);
    ret = Tcl_FSEvalFile(interp, pathPtr);
    Tcl_DecrRefCount(pathPtr);
    return ret;
}

/*
 * Now move on to the basic filesystem implementation
 * Now move on to the basic filesystem implementation.
 */

static void
FsThrExitProc(
    ClientData cd)
{
    ThreadSpecificData *tsdPtr = cd;
718
719
720
721
722
723
724
725

726
727
728
729
730
731
732
718
719
720
721
722
723
724

725
726
727
728
729
730
731
732







-
+







    if (cwdClientData != NULL) {
	NativeFreeInternalRep(cwdClientData);
	cwdClientData = NULL;
    }

    /*
     * Remove all filesystems, freeing any allocated memory that is no longer
     * needed
     * needed.
     */

    fsRecPtr = filesystemList;
    while (fsRecPtr != NULL) {
	FilesystemRecord *tmpFsRecPtr = fsRecPtr->nextPtr;

	if (fsRecPtr->fileRefCount <= 0) {
816
817
818
819
820
821
822
823

824
825
826
827
828
829
830
816
817
818
819
820
821
822

823
824
825
826
827
828
829
830







-
+







 *	Memory allocated and modifies the link list for filesystems.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_FSRegister(
    ClientData clientData,	/* Client specific data for this fs */
    ClientData clientData,	/* Client specific data for this fs. */
    const Tcl_Filesystem *fsPtr)/* The filesystem record for the new fs. */
{
    FilesystemRecord *newFilesystemPtr;

    if (fsPtr == NULL) {
	return TCL_ERROR;
    }
990
991
992
993
994
995
996
997

998
999
1000
1001
1002
1003
1004
990
991
992
993
994
995
996

997
998
999
1000
1001
1002
1003
1004







-
+







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

int
Tcl_FSMatchInDirectory(
    Tcl_Interp *interp,		/* Interpreter to receive error messages, but
                       		 * may be NULL. */
				 * may be NULL. */
    Tcl_Obj *resultPtr,		/* List object to receive results. */
    Tcl_Obj *pathPtr,		/* Contains path to directory to search. */
    const char *pattern,	/* Pattern to match against. */
    Tcl_GlobTypeData *types)	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
1039
1040
1041
1042
1043
1044
1045
1046

1047
1048
1049
1050
1051
1052
1053
1039
1040
1041
1042
1043
1044
1045

1046
1047
1048
1049
1050
1051
1052
1053







-
+







	    FsAddMountsToGlobResult(resultPtr, pathPtr, pattern, types);
	}
	return ret;
    }

    /*
     * If the path isn't empty, we have no idea how to match files in a
     * directory which belongs to no known filesystem
     * directory which belongs to no known filesystem.
     */

    if (pathPtr != NULL && TclGetString(pathPtr)[0] != '\0') {
	Tcl_SetErrno(ENOENT);
	return -1;
    }

1115
1116
1117
1118
1119
1120
1121
1122

1123
1124
1125
1126
1127
1128
1129
1115
1116
1117
1118
1119
1120
1121

1122
1123
1124
1125
1126
1127
1128
1129







-
+







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

static void
FsAddMountsToGlobResult(
    Tcl_Obj *resultPtr,		/* The current list of matching paths; must
				 * not be shared! */
    Tcl_Obj *pathPtr,		/* The directory in question */
    Tcl_Obj *pathPtr,		/* The directory in question. */
    const char *pattern,	/* Pattern to match against. */
    Tcl_GlobTypeData *types)	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    int mLength, gLength, i;
    int dir = (types == NULL || (types->type & TCL_GLOB_TYPE_DIR));
1156
1157
1158
1159
1160
1161
1162
1163

1164
1165
1166
1167
1168
1169
1170
1156
1157
1158
1159
1160
1161
1162

1163
1164
1165
1166
1167
1168
1169
1170







-
+







		    /*
		     * We don't want to list this.
		     */

		    Tcl_ListObjReplace(NULL, resultPtr, j, 1, 0, NULL);
		    gLength--;
		}
		break;		/* Break out of for loop */
		break;		/* Break out of for loop. */
	    }
	}
	if (!found && dir) {
	    Tcl_Obj *norm;
	    int len, mlen;

	    /*
1341
1342
1343
1344
1345
1346
1347
1348
1349


1350
1351
1352
1353
1354
1355
1356
1341
1342
1343
1344
1345
1346
1347


1348
1349
1350
1351
1352
1353
1354
1355
1356







-
-
+
+







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

int
TclFSNormalizeToUniquePath(
    Tcl_Interp *interp,		/* Used for error messages. */
    Tcl_Obj *pathPtr,		/* The path to normalize in place */
    int startAt,		/* Start at this char-offset */
    Tcl_Obj *pathPtr,		/* The path to normalize in place. */
    int startAt,		/* Start at this char-offset. */
    ClientData *clientDataPtr)	/* If we generated a complete normalized path
				 * for a given filesystem, we can optionally
				 * return an fs-specific clientdata here. */
{
    FilesystemRecord *fsRecPtr, *firstFsRecPtr;
    /* Ignore this variable */
    (void) clientDataPtr;
1468
1469
1470
1471
1472
1473
1474
1475

1476
1477
1478
1479
1480
1481
1482
1468
1469
1470
1471
1472
1473
1474

1475
1476
1477
1478
1479
1480
1481
1482







-
+







    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 *binaryPtr)		/* Set this to 1 if the caller should
				 * configure the opened channel for binary
				 * operations */
				 * 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
1894
1895
1896
1897
1898
1899
1900
1901

1902
1903
1904
1905
1906
1907
1908
1894
1895
1896
1897
1898
1899
1900

1901
1902
1903
1904
1905
1906
1907
1908







-
+







    } else if (result == TCL_ERROR) {
	/*
	 * Record information telling where the error occurred.
	 */

	int length;
	const char *pathString = Tcl_GetStringFromObj(pathPtr, &length);
	int limit = 150;
	const int limit = 150;
	int overflow = (length > limit);

	Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
		"\n    (file \"%.*s%s\" line %d)",
		(overflow ? limit : length), pathString,
		(overflow ? "..." : ""), Tcl_GetErrorLine(interp)));
    }
2218
2219
2220
2221
2222
2223
2224
2225


2226
2227
2228
2229
2230
2231
2232
2218
2219
2220
2221
2222
2223
2224

2225
2226
2227
2228
2229
2230
2231
2232
2233







-
+
+







 *	See utime documentation.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_FSUtime(
    Tcl_Obj *pathPtr,		/* File to change access/modification times */
    Tcl_Obj *pathPtr,		/* File to change access/modification
				 * times. */
    struct utimbuf *tval)	/* Structure containing access/modification
				 * times to use. Should not be modified. */
{
    const Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);

    if (fsPtr != NULL && fsPtr->utimeProc != NULL) {
	return fsPtr->utimeProc(pathPtr, tval);
2580
2581
2582
2583
2584
2585
2586

2587



2588
2589
2590
2591
2592
2593
2594
2581
2582
2583
2584
2585
2586
2587
2588

2589
2590
2591
2592
2593
2594
2595
2596
2597
2598







+
-
+
+
+







	    }

	    proc2 = (TclFSGetCwdProc2 *) fsRecPtr->fsPtr->getCwdProc;
	    retCd = proc2(NULL);
	    if (retCd != NULL) {
		Tcl_Obj *norm;

		/*
		/* Looks like a new current directory */
		 * Looks like a new current directory.
		 */

		retVal = fsRecPtr->fsPtr->internalToNormalizedProc(retCd);
		Tcl_IncrRefCount(retVal);
		norm = TclFSNormalizeAbsolutePath(interp,retVal,NULL);
		if (norm != NULL) {
		    /*
		     * We found a cwd, which is now in our global storage. We
		     * must make a copy. Norm already has a refCount of 1.
2820
2821
2822
2823
2824
2825
2826
2827

2828
2829
2830
2831
2832
2833
2834
2824
2825
2826
2827
2828
2829
2830

2831
2832
2833
2834
2835
2836
2837
2838







-
+








	    Tcl_StatBuf buf;

	    /*
	     * If the file can be stat'ed and is a directory and is readable,
	     * then we can chdir. If any of these actions fail, then
	     * 'Tcl_SetErrno()' should automatically have been called to set
	     * an appropriate error code
	     * an appropriate error code.
	     */

	    if ((Tcl_FSStat(pathPtr, &buf) == 0) && (S_ISDIR(buf.st_mode))
		    && (Tcl_FSAccess(pathPtr, R_OK) == 0)) {
		/*
		 * We allow the chdir.
		 */
3325
3326
3327
3328
3329
3330
3331
3332

3333
3334
3335
3336
3337
3338
3339
3329
3330
3331
3332
3333
3334
3335

3336
3337
3338
3339
3340
3341
3342
3343







-
+







	}
    }
    return TCL_OK;
}

/*
 * This function used to be in the platform specific directories, but it has
 * now been made to work cross-platform
 * now been made to work cross-platform.
 */

int
TclpLoadFile(
    Tcl_Interp *interp,		/* Used for error reporting. */
    Tcl_Obj *pathPtr,		/* Name of the file containing the desired
				 * code (UTF-8). */
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504



3505
3506
3507
3508
3509
3510
3511
3499
3500
3501
3502
3503
3504
3505



3506
3507
3508
3509
3510
3511
3512
3513
3514
3515







-
-
-
+
+
+







 *	See readlink() documentation. A new filesystem link object may appear.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj *
Tcl_FSLink(
    Tcl_Obj *pathPtr,		/* Path of file to readlink or link */
    Tcl_Obj *toPtr,		/* NULL or path to be linked to */
    int linkAction)		/* Action to perform */
    Tcl_Obj *pathPtr,		/* Path of file to readlink or link. */
    Tcl_Obj *toPtr,		/* NULL or path to be linked to. */
    int linkAction)		/* Action to perform. */
{
    const Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);

    if (fsPtr != NULL && fsPtr->linkProc != NULL) {
	return fsPtr->linkProc(pathPtr, toPtr, linkAction);
    }

3733
3734
3735
3736
3737
3738
3739
3740

3741
3742
3743
3744
3745
3746
3747
3737
3738
3739
3740
3741
3742
3743

3744
3745
3746
3747
3748
3749
3750
3751







-
+








    if (lenPtr != NULL) {
	TclListObjLength(NULL, result, lenPtr);
    }
    return result;
}

/* Simple helper function */
/* Simple helper function. */
Tcl_Obj *
TclFSInternalToNormalized(
    const Tcl_Filesystem *fromFilesystem,
    ClientData clientData,
    FilesystemRecord **fsRecPtrPtr)
{
    FilesystemRecord *fsRecPtr = FsGetFirstFilesystem();
3778
3779
3780
3781
3782
3783
3784
3785

3786
3787
3788
3789
3790
3791
3792
3782
3783
3784
3785
3786
3787
3788

3789
3790
3791
3792
3793
3794
3795
3796







-
+







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

Tcl_PathType
TclGetPathType(
    Tcl_Obj *pathPtr,		/* Path to determine type for */
    Tcl_Obj *pathPtr,		/* Path to determine type for. */
    const Tcl_Filesystem **filesystemPtrPtr,
				/* If absolute path and this is not NULL, then
				 * set to the filesystem which claims this
				 * path. */
    int *driveNameLengthPtr,	/* If the path is absolute, and this is
				 * non-NULL, then set to the length of the
				 * driveName. */
3833
3834
3835
3836
3837
3838
3839
3840
3841


3842
3843
3844
3845
3846
3847
3848
3837
3838
3839
3840
3841
3842
3843


3844
3845
3846
3847
3848
3849
3850
3851
3852







-
-
+
+







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

Tcl_PathType
TclFSNonnativePathType(
    const char *path,		/* Path to determine type for */
    int pathLen,		/* Length of the path */
    const char *path,		/* Path to determine type for. */
    int pathLen,		/* Length of the path. */
    const Tcl_Filesystem **filesystemPtrPtr,
				/* If absolute path and this is not NULL, then
				 * set to the filesystem which claims this
				 * path. */
    int *driveNameLengthPtr,	/* If the path is absolute, and this is
				 * non-NULL, then set to the length of the
				 * driveName. */
4041
4042
4043
4044
4045
4046
4047
4048

4049
4050
4051
4052
4053
4054
4055
4045
4046
4047
4048
4049
4050
4051

4052
4053
4054
4055
4056
4057
4058
4059







-
+







 *	A file may be created.
 *
 *---------------------------------------------------------------------------
 */

int
TclCrossFilesystemCopy(
    Tcl_Interp *interp,		/* For error messages */
    Tcl_Interp *interp,		/* For error messages. */
    Tcl_Obj *source,		/* Pathname of file to be copied (UTF-8). */
    Tcl_Obj *target)		/* Pathname of file to copy to (UTF-8). */
{
    int result = TCL_ERROR;
    int prot = 0666;
    Tcl_Channel in, out;
    Tcl_StatBuf sourceStatBuf;