summaryrefslogtreecommitdiffstats
path: root/win/tclWinChan.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinChan.c')
-rw-r--r--win/tclWinChan.c75
1 files changed, 74 insertions, 1 deletions
diff --git a/win/tclWinChan.c b/win/tclWinChan.c
index 7cee496..673cd6a 100644
--- a/win/tclWinChan.c
+++ b/win/tclWinChan.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinChan.c,v 1.40 2005/05/10 18:35:37 kennykb Exp $
+ * RCS: @(#) $Id: tclWinChan.c,v 1.41 2005/06/07 21:31:53 dkf Exp $
*/
#include "tclWinInt.h"
@@ -100,6 +100,8 @@ static void FileWatchProc _ANSI_ARGS_((ClientData instanceData,
int mask));
static void FileThreadActionProc _ANSI_ARGS_ ((
ClientData instanceData, int action));
+static void FileTruncateProc _ANSI_ARGS_ ((
+ ClientData instanceData, Tcl_WideInt length));
/*
* This structure describes the channel type structure for file based IO.
@@ -122,6 +124,7 @@ static Tcl_ChannelType fileChannelType = {
NULL, /* handler proc. */
FileWideSeekProc, /* Wide seek proc. */
FileThreadActionProc, /* Thread action proc. */
+ FileTruncateProc, /* Truncate proc. */
};
#if defined(HAVE_NO_SEH) && defined(TCL_MEM_DEBUG)
@@ -577,6 +580,76 @@ FileWideSeekProc(instanceData, offset, mode, errorCodePtr)
/*
*----------------------------------------------------------------------
*
+ * FileTruncateProc --
+ *
+ * Truncates a file-based channel. Returns the error code.
+ *
+ * Results:
+ * 0 if successful, POSIX-y error code if it failed.
+ *
+ * Side effects:
+ * Truncates the file, may move file pointers too.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+FileTruncateProc(instanceData, length)
+ ClientData instanceData; /* File state. */
+ Tcl_WideInt length; /* Length to truncate at. */
+{
+ FileInfo *infoPtr = (FileInfo *) instanceData;
+ LONG newPos, newPosHigh, oldPos, oldPosHigh;
+
+ /*
+ * Save where we were...
+ */
+ oldPosHigh = 0;
+ oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT);
+ if (oldPos == INVALID_SET_FILE_POINTER) {
+ DWORD winError = GetLastError();
+ if (winError != NO_ERROR) {
+ TclWinConvertError(winError);
+ return errno;
+ }
+ }
+
+ /*
+ * Move to where we want to truncate
+ */
+ newPosHigh = Tcl_WideAsLong(length >> 32);
+ newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(length),
+ &newPosHigh, FILE_BEGIN);
+ if (newPos == INVALID_SET_FILE_POINTER) {
+ DWORD winError = GetLastError();
+ if (winError != NO_ERROR) {
+ TclWinConvertError(winError);
+ return errno;
+ }
+ }
+
+ /*
+ * Perform the truncation (unlike POSIX ftruncate(), we needed to
+ * move to the location to truncate at first).
+ */
+ if (!SetEndOfFile(infoPtr->handle)) {
+ TclWinConvertError(GetLastError());
+ return errno;
+ }
+
+ /*
+ * Move back. If this last step fails, we don't care; it's just a
+ * "best effort" attempt to restore our file pointer to where it
+ * was.
+ */
+ SetFilePointer(infoPtr->handle, oldPos, &oldPosHigh, FILE_BEGIN);
+
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* FileInputProc --
*
* Reads input from the IO channel into the buffer given. Returns