wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #undef DEBUG
2 /*
3 * FileChannel.java --
4 *
5 * Copyright (c) 1997 Sun Microsystems, Inc.
6 *
7 * See the file "license.terms" for information on usage and
8 * redistribution of this file, and for a DISCLAIMER OF ALL
9 * WARRANTIES.
10 *
11 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
12 *
13 * RCS @(#) $Id: FileChannel.java,v 1.20 2003/03/08 03:42:44 mdejong Exp $
14 *
15 */
16 using System;
17 using System.IO;
18  
19 namespace tcl.lang
20 {
21  
22 /// <summary> Subclass of the abstract class Channel. It implements all of the
23 /// methods to perform read, write, open, close, etc on a file.
24 /// </summary>
25  
26 class FileChannel : Channel
27 {
28 public override string ChanType
29 {
30 get
31 {
32 return "file";
33 }
34  
35 }
36 override protected internal Stream InputStream
37 {
38 get
39 {
40  
41  
42 // return new FileInputStream(file.getFD());
43 return file;
44 }
45  
46 }
47 override protected internal Stream OutputStream
48 {
49 get
50 {
51  
52  
53 // return new FileOutputStream(file.getFD());
54 return file;
55 }
56  
57 }
58  
59 /// <summary> The file needs to have a file pointer that can be moved randomly
60 /// within the file. The RandomAccessFile is the only java.io class
61 /// that allows this behavior.
62 /// </summary>
63  
64 private FileStream file = null;
65  
66 /// <summary> Open a file with the read/write permissions determined by modeFlags.
67 /// This method must be called before any other methods will function
68 /// properly.
69 ///
70 /// </summary>
71 /// <param name="interp">currrent interpreter.
72 /// </param>
73 /// <param name="fileName">the absolute path or name of file in the current
74 /// directory to open
75 /// </param>
76 /// <param name="modeFlags">modes used to open a file for reading, writing, etc
77 /// </param>
78 /// <returns> the channelId of the file.
79 /// </returns>
80 /// <exception cref=""> TclException is thrown when the modeFlags try to open
81 /// a file it does not have permission for or if the
82 /// file dosent exist and CREAT wasnt specified.
83 /// </exception>
84 /// <exception cref=""> IOException is thrown when an IO error occurs that was not
85 /// correctly tested for. Most cases should be caught.
86 /// </exception>
87  
88 internal string open( Interp interp, string fileName, int modeFlags )
89 {
90  
91 mode = modeFlags;
92 FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );
93 FileMode fileMode = 0;
94 FileAccess fileAccess = 0;
95  
96 if ( ( ( modeFlags & TclIO.CREAT ) != 0 ) && ( ( modeFlags & TclIO.EXCL ) != 0 ) )
97 {
98 fileMode = FileMode.CreateNew;
99 }
100 else if ( ( modeFlags & TclIO.CREAT ) != 0 )
101 {
102 fileMode = FileMode.Create;
103 }
104 else
105 {
106 fileMode = FileMode.Open;
107 }
108 if ( ( modeFlags & TclIO.TRUNC ) != 0 )
109 {
110 fileMode = fileMode & FileMode.Truncate;
111 }
112 if ( ( modeFlags & TclIO.APPEND ) != 0 )
113 {
114 fileMode = fileMode & FileMode.Append;
115 }
116  
117 if ( ( modeFlags & TclIO.RDWR ) != 0 )
118 {
119 fileAccess = FileAccess.ReadWrite;
120 }
121 else if ( ( modeFlags & TclIO.RDONLY ) != 0 )
122 {
123 fileAccess = FileAccess.Read;
124 }
125 else if ( ( modeFlags & TclIO.WRONLY ) != 0 )
126 {
127 fileAccess = FileAccess.Write;
128 }
129 else
130 {
131 throw new TclRuntimeError( "FileChannel.java: invalid mode value" );
132 }
133  
134 file = new FileStream( fileObj.FullName, fileMode, fileAccess, FileShare.ReadWrite );
135  
136 string fName = TclIO.getNextDescriptor( interp, "file" );
137 ChanName = fName;
138 //Console.Out.WriteLine("",file.Name);
139 return fName;
140 }
141  
142 /// <summary> Close the file. The file MUST be open or a TclRuntimeError
143 /// is thrown.
144 /// </summary>
145  
146 internal override void close()
147 {
148 if ( file == null )
149 {
150 throw new TclRuntimeError( "FileChannel.close(): null file object" );
151 }
152  
153 // Invoke super.close() first since it might write an eof char
154 try
155 {
156 base.close();
157 }
158 finally
159 {
160 // Console.Out.WriteLine("Debugg Closing {0}",file.Name);
161 file.Close();
162 }
163 }
164  
165 /// <summary> Move the file pointer internal to the RandomAccessFile object.
166 /// The file MUST be open or a TclRuntimeError is thrown.
167 ///
168 /// </summary>
169 /// <param name="offset">The number of bytes to move the file pointer.
170 /// </param>
171 /// <param name="inmode">to begin incrementing the file pointer; beginning,
172 /// current, or end of the file.
173 /// </param>
174 public override void seek( Interp interp, long offset, int inmode )
175 {
176  
177 if ( file == null )
178 {
179 throw new TclRuntimeError( "FileChannel.seek(): null file object" );
180 }
181  
182 //FIXME: Disallow seek on dead channels (raise TclPosixException ??)
183 //if (CheckForDeadChannel(NULL, statePtr)) {
184 // return Tcl_LongAsWide(-1);
185 //}
186  
187 // Compute how much input and output is buffered. If both input and
188 // output is buffered, cannot compute the current position.
189  
190 int inputBuffered = NumBufferedInputBytes;
191 int outputBuffered = NumBufferedOutputBytes;
192  
193 if ( ( inputBuffered != 0 ) && ( outputBuffered != 0 ) )
194 {
195 throw new TclPosixException( interp, TclPosixException.EFAULT, true, "error during seek on \"" + ChanName + "\"" );
196 }
197  
198 // If we are seeking relative to the current position, compute the
199 // corrected offset taking into account the amount of unread input.
200  
201 if ( inmode == TclIO.SEEK_CUR )
202 {
203 offset -= inputBuffered;
204 }
205  
206 // The seekReset method will discard queued input and
207 // reset flags like EOF and BLOCKED.
208  
209 if ( input != null )
210 {
211 input.seekReset();
212 }
213  
214 // FIXME: Next block is disabled since non-blocking is not implemented.
215 // If the channel is in asynchronous output mode, switch it back
216 // to synchronous mode and cancel any async flush that may be
217 // scheduled. After the flush, the channel will be put back into
218 // asynchronous output mode.
219  
220 bool wasAsync = false;
221 //if (false && !Blocking)
222 //{
223 // wasAsync = true;
224 // Blocking = true;
225 // if (BgFlushScheduled)
226 // {
227 // //scheduleBgFlush();
228 // }
229 //}
230  
231 // If there is data buffered in curOut then mark the
232 // channel as ready to flush before invoking flushChannel.
233  
234 if ( output != null )
235 {
236 output.seekCheckBuferReady();
237 }
238  
239 // If the flush fails we cannot recover the original position. In
240 // that case the seek is not attempted because we do not know where
241 // the access position is - instead we return the error. FlushChannel
242 // has already called Tcl_SetErrno() to report the error upwards.
243 // If the flush succeeds we do the seek also.
244  
245 if ( output != null && output.flushChannel( null, false ) != 0 )
246 {
247 // FIXME: IS this the proper action to take on error?
248 throw new IOException( "flush error while seeking" );
249 }
250 else
251 {
252 // Now seek to the new position in the channel as requested by the
253 // caller.
254  
255 long actual_offset;
256  
257 switch ( inmode )
258 {
259  
260 case TclIO.SEEK_SET:
261 {
262 actual_offset = offset;
263 break;
264 }
265  
266 case TclIO.SEEK_CUR:
267 {
268 actual_offset = file.Position + offset;
269 break;
270 }
271  
272 case TclIO.SEEK_END:
273 {
274 actual_offset = file.Length + offset;
275 break;
276 }
277  
278 default:
279 {
280 throw new TclRuntimeError( "invalid seek mode" );
281 }
282  
283 }
284  
285 // A negative offset to seek() would raise an IOException, but
286 // we want to raise an invalid argument error instead
287  
288 if ( actual_offset < 0 )
289 {
290 throw new TclPosixException( interp, TclPosixException.EINVAL, true, "error during seek on \"" + ChanName + "\"" );
291 }
292  
293 file.Seek( actual_offset, SeekOrigin.Begin );
294 }
295  
296 // Restore to nonblocking mode if that was the previous behavior.
297 //
298 // NOTE: Even if there was an async flush active we do not restore
299 // it now because we already flushed all the queued output, above.
300  
301 if ( wasAsync )
302 {
303 Blocking = false;
304 }
305 }
306  
307 /// <summary> Tcl_Tell -> tell
308 ///
309 /// Return the current offset of the file pointer in number of bytes from
310 /// the beginning of the file. The file MUST be open or a TclRuntimeError
311 /// is thrown.
312 ///
313 /// </summary>
314 /// <returns> The current value of the file pointer.
315 /// </returns>
316 public override long tell()
317 {
318 if ( file == null )
319 {
320 throw new TclRuntimeError( "FileChannel.tell(): null file object" );
321 }
322 int inputBuffered = NumBufferedInputBytes;
323 int outputBuffered = NumBufferedOutputBytes;
324  
325 if ( ( inputBuffered != 0 ) && ( outputBuffered != 0 ) )
326 {
327 // FIXME: Posix error EFAULT ?
328 return -1;
329 }
330 long curPos = file.Position;
331 if ( curPos == -1 )
332 {
333 // FIXME: Set errno here?
334 return -1;
335 }
336 if ( inputBuffered != 0 )
337 {
338 return curPos - inputBuffered;
339 }
340 return curPos + outputBuffered;
341 }
342  
343 /// <summary> If the file dosent exist then a TclExcpetion is thrown.
344 ///
345 /// </summary>
346 /// <param name="interp">currrent interpreter.
347 /// </param>
348 /// <param name="fileObj">a java.io.File object of the file for this channel.
349 /// </param>
350  
351 private void checkFileExists( Interp interp, FileInfo fileObj )
352 {
353 bool tmpBool;
354 if ( File.Exists( fileObj.FullName ) )
355 tmpBool = true;
356 else
357 tmpBool = Directory.Exists( fileObj.FullName );
358 if ( !tmpBool )
359 {
360 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "couldn't open \"" + fileObj.Name + "\"" );
361 }
362 }
363  
364  
365 /// <summary> Checks the read/write permissions on the File object. If inmode is less
366 /// than 0 it checks for read permissions, if mode greater than 0 it checks
367 /// for write permissions, and if it equals 0 then it checks both.
368 ///
369 /// </summary>
370 /// <param name="interp">currrent interpreter.
371 /// </param>
372 /// <param name="fileObj">a java.io.File object of the file for this channel.
373 /// </param>
374 /// <param name="inmode">what permissions to check for.
375 /// </param>
376  
377 private void checkReadWritePerm( Interp interp, FileInfo fileObj, int inmode )
378 {
379 bool error = false;
380  
381 if ( inmode <= 0 )
382 {
383  
384 // HACK
385 // if (!fileObj.canRead())
386 // {
387 // error = true;
388 // }
389 }
390 if ( inmode >= 0 )
391 {
392 if ( !SupportClass.FileCanWrite( fileObj ) )
393 {
394 error = true;
395 }
396 }
397 if ( error )
398 {
399 throw new TclPosixException( interp, TclPosixException.EACCES, true, "couldn't open \"" + fileObj.Name + "\"" );
400 }
401 }
402 }
403 }