wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * FileCmd.java --
3 *
4 * This file contains the Jacl implementation of the built-in Tcl "file"
5 * command.
6 *
7 * Copyright (c) 1997 Cornell University.
8 * Copyright (c) 1997 Sun Microsystems, Inc.
9 *
10 * See the file "license.terms" for information on usage and
11 * redistribution of this file, and for a DISCLAIMER OF ALL
12 * WARRANTIES.
13 *
14 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
15 *
16 * RCS @(#) $Id: FileCmd.java,v 1.9 2003/02/03 01:39:02 mdejong Exp $
17 *
18 */
19 using System;
20 using System.IO;
21 namespace tcl.lang
22 {
23  
24 /*
25 * This class implements the built-in "file" command in Tcl.
26 */
27  
28 class FileCmd : Command
29 {
30  
31 /// <summary> Reference to File.listRoots, null when JDK < 1.2</summary>
32 private static System.Reflection.MethodInfo listRootsMethod;
33  
34 internal static Type procClass = null;
35  
36 private static readonly string[] validCmds = new string[] { "atime", "attributes", "channels", "copy", "delete", "dirname", "executable", "exists", "extension", "isdirectory", "isfile", "join", "link", "lstat", "mtime", "mkdir", "nativename", "normalize", "owned", "pathtype", "readable", "readlink", "rename", "rootname", "separator", "size", "split", "stat", "system", "tail", "type", "volumes", "writable" };
37  
38 private const int OPT_ATIME = 0;
39 private const int OPT_ATTRIBUTES = 1;
40 private const int OPT_CHANNELS = 2;
41 private const int OPT_COPY = 3;
42 private const int OPT_DELETE = 4;
43 private const int OPT_DIRNAME = 5;
44 private const int OPT_EXECUTABLE = 6;
45 private const int OPT_EXISTS = 7;
46 private const int OPT_EXTENSION = 8;
47 private const int OPT_ISDIRECTORY = 9;
48 private const int OPT_ISFILE = 10;
49 private const int OPT_JOIN = 11;
50 private const int OPT_LINK = 12;
51 private const int OPT_LSTAT = 13;
52 private const int OPT_MTIME = 14;
53 private const int OPT_MKDIR = 15;
54 private const int OPT_NATIVENAME = 16;
55 private const int OPT_NORMALIZE = 17;
56 private const int OPT_OWNED = 18;
57 private const int OPT_PATHTYPE = 19;
58 private const int OPT_READABLE = 20;
59 private const int OPT_READLINK = 21;
60 private const int OPT_RENAME = 22;
61 private const int OPT_ROOTNAME = 23;
62 private const int OPT_SEPARATOR = 24;
63 private const int OPT_SIZE = 25;
64 private const int OPT_SPLIT = 26;
65 private const int OPT_STAT = 27;
66 private const int OPT_SYSTEM = 28;
67 private const int OPT_TAIL = 29;
68 private const int OPT_TYPE = 30;
69 private const int OPT_VOLUMES = 31;
70 private const int OPT_WRITABLE = 32;
71  
72 private static readonly string[] validOptions = new string[] { "-force", "--" };
73  
74 private const int OPT_FORCE = 0;
75 private const int OPT_LAST = 1;
76  
77 public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
78 {
79 if ( argv.Length < 2 )
80 {
81 throw new TclNumArgsException( interp, 1, argv, "option ?arg ...?" );
82 }
83  
84 int opt = TclIndex.get( interp, argv[1], validCmds, "option", 0 );
85 string path;
86 FileInfo fileObj = null;
87  
88 switch ( opt )
89 {
90  
91 case OPT_ATIME:
92 if ( argv.Length != 3 )
93 {
94 throw new TclNumArgsException( interp, 2, argv, "name" );
95 }
96  
97 // FIXME: Currently returns the same thing as MTIME.
98 // Java does not support retrieval of access time.
99  
100  
101  
102 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
103  
104 interp.setResult( getMtime( interp, argv[2].ToString(), fileObj ) );
105 return TCL.CompletionCode.RETURN;
106  
107  
108 case OPT_ATTRIBUTES:
109 if ( argv[3].ToString() == "-readonly" )
110 fileSetReadOnly( interp, argv );
111 else
112 throw new TclException( interp, "sorry, \"file attributes\" is not implemented yet" );
113 return TCL.CompletionCode.RETURN;
114  
115  
116 case OPT_CHANNELS:
117  
118 throw new TclException( interp, "sorry, \"file channels\" is not implemented yet" );
119  
120  
121 case OPT_COPY:
122 fileCopyRename( interp, argv, true );
123 return TCL.CompletionCode.RETURN;
124  
125  
126 case OPT_DELETE:
127 fileDelete( interp, argv );
128 return TCL.CompletionCode.RETURN;
129  
130  
131 case OPT_DIRNAME:
132 if ( argv.Length != 3 )
133 {
134 throw new TclNumArgsException( interp, 2, argv, "name" );
135 }
136  
137 path = argv[2].ToString();
138  
139 // Return all but the last component. If there is only one
140 // component, return it if the path was non-relative, otherwise
141 // return the current directory.
142  
143  
144 TclObject[] splitArrayObj = TclList.getElements( interp, FileUtil.splitAndTranslate( interp, path ) );
145  
146 if ( splitArrayObj.Length > 1 )
147 {
148 interp.setResult( FileUtil.joinPath( interp, splitArrayObj, 0, splitArrayObj.Length - 1 ) );
149 }
150 else if ( ( splitArrayObj.Length == 0 ) || ( FileUtil.getPathType( path ) == FileUtil.PATH_RELATIVE ) )
151 {
152 if ( JACL.PLATFORM == JACL.PLATFORM_MAC )
153 {
154 interp.setResult( ":" );
155 }
156 else
157 {
158 interp.setResult( "." );
159 }
160 }
161 else
162 {
163  
164 interp.setResult( splitArrayObj[0].ToString() );
165 }
166 return TCL.CompletionCode.RETURN;
167  
168  
169 case OPT_EXECUTABLE:
170 if ( argv.Length != 3 )
171 {
172 throw new TclNumArgsException( interp, 2, argv, "name" );
173 }
174 bool isExe = false;
175  
176 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
177  
178 // A file must exist to be executable. Directories are always
179 // executable.
180  
181 bool tmpBool;
182 if ( File.Exists( fileObj.FullName ) )
183 tmpBool = true;
184 else
185 tmpBool = Directory.Exists( fileObj.FullName );
186 if ( tmpBool )
187 {
188 isExe = Directory.Exists( fileObj.FullName );
189 if ( isExe )
190 {
191 interp.setResult( isExe );
192 return TCL.CompletionCode.RETURN;
193 }
194  
195 if ( Util.Windows )
196 {
197 // File that ends with .exe, .com, or .bat is executable.
198  
199  
200 string fileName = argv[2].ToString();
201 isExe = ( fileName.EndsWith( ".exe" ) || fileName.EndsWith( ".com" ) || fileName.EndsWith( ".bat" ) );
202 }
203 else if ( Util.Mac )
204 {
205 // FIXME: Not yet implemented on Mac. For now, return true.
206 // Java does not support executability checking.
207  
208 isExe = true;
209 }
210 else
211 {
212 // FIXME: Not yet implemented on Unix. For now, return true.
213 // Java does not support executability checking.
214  
215 isExe = true;
216 }
217 }
218 interp.setResult( isExe );
219 return TCL.CompletionCode.RETURN;
220  
221  
222 case OPT_EXISTS:
223 if ( argv.Length != 3 )
224 {
225 throw new TclNumArgsException( interp, 2, argv, "name" );
226 }
227  
228 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
229 bool tmpBool2;
230 if ( File.Exists( fileObj.FullName ) )
231 tmpBool2 = true;
232 else
233 tmpBool2 = Directory.Exists( fileObj.FullName );
234 interp.setResult( tmpBool2 );
235 return TCL.CompletionCode.RETURN;
236  
237  
238 case OPT_EXTENSION:
239 if ( argv.Length != 3 )
240 {
241 throw new TclNumArgsException( interp, 2, argv, "name" );
242 }
243  
244 interp.setResult( getExtension( argv[2].ToString() ) );
245 return TCL.CompletionCode.RETURN;
246  
247  
248 case OPT_ISDIRECTORY:
249 if ( argv.Length != 3 )
250 {
251 throw new TclNumArgsException( interp, 2, argv, "name" );
252 }
253  
254 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
255 interp.setResult( Directory.Exists( fileObj.FullName ) );
256 return TCL.CompletionCode.RETURN;
257  
258  
259 case OPT_ISFILE:
260 if ( argv.Length != 3 )
261 {
262 throw new TclNumArgsException( interp, 2, argv, "name" );
263 }
264  
265 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
266 interp.setResult( File.Exists( fileObj.FullName ) );
267 return TCL.CompletionCode.RETURN;
268  
269  
270 case OPT_JOIN:
271 if ( argv.Length < 3 )
272 {
273 throw new TclNumArgsException( interp, 2, argv, "name ?name ...?" );
274 }
275 interp.setResult( FileUtil.joinPath( interp, argv, 2, argv.Length ) );
276 return TCL.CompletionCode.RETURN;
277  
278  
279 case OPT_LINK:
280  
281 throw new TclException( interp, "sorry, \"file link\" is not implemented yet" );
282  
283  
284 case OPT_LSTAT:
285 if ( argv.Length != 4 )
286 {
287 throw new TclNumArgsException( interp, 2, argv, "name varName" );
288 }
289  
290 // FIXME: Not yet implemented.
291 // Java does not support link access.
292  
293  
294 throw new TclException( interp, "file command with opt " + argv[1].ToString() + " is not yet implemented" );
295  
296  
297  
298 case OPT_MTIME:
299 if ( argv.Length != 3 )
300 {
301 throw new TclNumArgsException( interp, 2, argv, "name" );
302 }
303  
304 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
305  
306 interp.setResult( getMtime( interp, argv[2].ToString(), fileObj ) );
307 return TCL.CompletionCode.RETURN;
308  
309  
310 case OPT_MKDIR:
311 fileMakeDirs( interp, argv );
312 return TCL.CompletionCode.RETURN;
313  
314  
315 case OPT_NATIVENAME:
316 if ( argv.Length != 3 )
317 {
318 throw new TclNumArgsException( interp, 2, argv, "name" );
319 }
320  
321  
322 interp.setResult( FileUtil.translateFileName( interp, argv[2].ToString() ) );
323 return TCL.CompletionCode.RETURN;
324  
325  
326 case OPT_NORMALIZE:
327  
328 throw new TclException( interp, "sorry, \"file normalize\" is not implemented yet" );
329  
330  
331 case OPT_OWNED:
332 if ( argv.Length != 3 )
333 {
334 throw new TclNumArgsException( interp, 2, argv, "name" );
335 }
336  
337 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
338 interp.setResult( isOwner( interp, fileObj ) );
339 return TCL.CompletionCode.RETURN;
340  
341  
342 case OPT_PATHTYPE:
343 if ( argv.Length != 3 )
344 {
345 throw new TclNumArgsException( interp, 2, argv, "name" );
346 }
347  
348 switch ( FileUtil.getPathType( argv[2].ToString() ) )
349 {
350  
351 case FileUtil.PATH_RELATIVE:
352 interp.setResult( "relative" );
353 return TCL.CompletionCode.RETURN;
354  
355 case FileUtil.PATH_VOLUME_RELATIVE:
356 interp.setResult( "volumerelative" );
357 return TCL.CompletionCode.RETURN;
358  
359 case FileUtil.PATH_ABSOLUTE:
360 interp.setResult( "absolute" );
361 break;
362 }
363 return TCL.CompletionCode.RETURN;
364  
365  
366 case OPT_READABLE:
367 if ( argv.Length != 3 )
368 {
369 throw new TclNumArgsException( interp, 2, argv, "name" );
370 }
371  
372 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
373  
374 // interp.setResult(fileObj.canRead());
375 // HACK
376 interp.setResult( true );
377 return TCL.CompletionCode.RETURN;
378  
379  
380 case OPT_READLINK:
381 if ( argv.Length != 3 )
382 {
383 throw new TclNumArgsException( interp, 2, argv, "name" );
384 }
385  
386 // FIXME: Not yet implemented.
387 // Java does not support link access.
388  
389  
390 throw new TclException( interp, "file command with opt " + argv[1].ToString() + " is not yet implemented" );
391  
392  
393 case OPT_RENAME:
394 fileCopyRename( interp, argv, false );
395 return TCL.CompletionCode.RETURN;
396  
397  
398 case OPT_ROOTNAME:
399 if ( argv.Length != 3 )
400 {
401 throw new TclNumArgsException( interp, 2, argv, "name" );
402 }
403  
404 string fileName2 = argv[2].ToString();
405 string extension = getExtension( fileName2 );
406 int diffLength = fileName2.Length - extension.Length;
407 interp.setResult( fileName2.Substring( 0, ( diffLength ) - ( 0 ) ) );
408 return TCL.CompletionCode.RETURN;
409  
410  
411 case OPT_SEPARATOR:
412  
413 throw new TclException( interp, "sorry, \"file separator\" is not implemented yet" );
414  
415  
416 case OPT_SIZE:
417 if ( argv.Length != 3 )
418 {
419 throw new TclNumArgsException( interp, 2, argv, "name" );
420 }
421  
422 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
423 bool tmpBool3;
424 if ( File.Exists( fileObj.FullName ) )
425 tmpBool3 = true;
426 else
427 tmpBool3 = Directory.Exists( fileObj.FullName );
428 if ( !tmpBool3 )
429 {
430  
431 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + argv[2].ToString() + "\"" );
432 }
433 interp.setResult( (int)SupportClass.FileLength( fileObj ) );
434 return TCL.CompletionCode.RETURN;
435  
436  
437 case OPT_SPLIT:
438 if ( argv.Length != 3 )
439 {
440 throw new TclNumArgsException( interp, 2, argv, "name" );
441 }
442  
443 interp.setResult( FileUtil.splitPath( interp, argv[2].ToString() ) );
444 return TCL.CompletionCode.RETURN;
445  
446  
447 case OPT_STAT:
448 if ( argv.Length != 4 )
449 {
450 throw new TclNumArgsException( interp, 2, argv, "name varName" );
451 }
452  
453 getAndStoreStatData( interp, argv[2].ToString(), argv[3].ToString() );
454 return TCL.CompletionCode.RETURN;
455  
456  
457 case OPT_SYSTEM:
458  
459 throw new TclException( interp, "sorry, \"file system\" is not implemented yet" );
460  
461  
462 case OPT_TAIL:
463 if ( argv.Length != 3 )
464 {
465 throw new TclNumArgsException( interp, 2, argv, "name" );
466 }
467  
468 interp.setResult( getTail( interp, argv[2].ToString() ) );
469 return TCL.CompletionCode.RETURN;
470  
471  
472 case OPT_TYPE:
473 if ( argv.Length != 3 )
474 {
475 throw new TclNumArgsException( interp, 2, argv, "name" );
476 }
477  
478 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
479  
480 interp.setResult( getType( interp, argv[2].ToString(), fileObj ) );
481 return TCL.CompletionCode.RETURN;
482  
483  
484 case OPT_VOLUMES:
485 if ( argv.Length != 2 )
486 {
487 throw new TclNumArgsException( interp, 2, argv, null );
488 }
489  
490 // use Java 1.2's File.listRoots() method if available
491  
492 if ( listRootsMethod == null )
493 throw new TclException( interp, "\"file volumes\" is not supported" );
494  
495 try
496 {
497 FileInfo[] roots = (FileInfo[])listRootsMethod.Invoke( null, (System.Object[])new System.Object[0] );
498 if ( roots != null )
499 {
500 TclObject list = TclList.newInstance();
501 for ( int i = 0; i < roots.Length; i++ )
502 {
503 string root = roots[i].FullName;
504 TclList.append( interp, list, TclString.newInstance( root ) );
505 }
506 interp.setResult( list );
507 }
508 }
509 catch ( System.UnauthorizedAccessException ex )
510 {
511 throw new TclRuntimeError( "IllegalAccessException in volumes cmd" );
512 }
513 catch ( System.ArgumentException ex )
514 {
515 throw new TclRuntimeError( "IllegalArgumentException in volumes cmd" );
516 }
517 catch ( System.Reflection.TargetInvocationException ex )
518 {
519 System.Exception t = ex.GetBaseException();
520  
521 if ( t is System.ApplicationException )
522 {
523 throw (System.ApplicationException)t;
524 }
525 else
526 {
527 throw new TclRuntimeError( "unexected exception in volumes cmd" );
528 }
529 }
530  
531 return TCL.CompletionCode.RETURN;
532  
533 case OPT_WRITABLE:
534 if ( argv.Length != 3 )
535 {
536 throw new TclNumArgsException( interp, 2, argv, "name" );
537 }
538  
539 fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
540 interp.setResult( SupportClass.FileCanWrite( fileObj ) );
541 return TCL.CompletionCode.RETURN;
542  
543 default:
544  
545 throw new TclRuntimeError( "file command with opt " + argv[1].ToString() + " is not implemented" );
546  
547 }
548 }
549 private static bool isOwner( Interp interp, FileInfo fileObj )
550 {
551 // If the file doesn't exist, return false;
552  
553 bool tmpBool;
554 if ( File.Exists( fileObj.FullName ) )
555 tmpBool = true;
556 else
557 tmpBool = Directory.Exists( fileObj.FullName );
558 if ( !tmpBool )
559 {
560 return false;
561 }
562 bool owner = true;
563  
564 // For Windows and Macintosh, there are no user ids
565 // associated with a file, so we always return 1.
566  
567 if ( Util.Unix )
568 {
569 // FIXME: Not yet implemented on Unix. Do no checking, for now.
570 // Java does not support ownership checking.
571 }
572 return owner;
573 }
574 private static int getMtime( Interp interp, string fileName, FileInfo fileObj )
575 {
576 bool tmpBool;
577 if ( File.Exists( fileObj.FullName ) )
578 tmpBool = true;
579 else
580 tmpBool = Directory.Exists( fileObj.FullName );
581 if ( !tmpBool )
582 {
583 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + fileName + "\"" );
584 }
585 // Divide to convert msecs to seconds
586 return (int)( fileObj.LastWriteTime.Ticks / 1000 );
587 }
588 private static string getType( Interp interp, string fileName, FileInfo fileObj )
589 {
590 bool tmpBool;
591 if ( File.Exists( fileObj.FullName ) )
592 tmpBool = true;
593 else
594 tmpBool = Directory.Exists( fileObj.FullName );
595 if ( !tmpBool )
596 {
597 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + fileName + "\"" );
598 }
599  
600 if ( File.Exists( fileObj.FullName ) )
601 {
602 return "file";
603 }
604 else if ( Directory.Exists( fileObj.FullName ) )
605 {
606 return "directory";
607 }
608 return "link";
609 }
610 private static void getAndStoreStatData( Interp interp, string fileName, string varName )
611 {
612 FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );
613  
614 bool tmpBool;
615 if ( File.Exists( fileObj.FullName ) )
616 tmpBool = true;
617 else
618 tmpBool = Directory.Exists( fileObj.FullName );
619 if ( !tmpBool )
620 {
621 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + fileName + "\"" );
622 }
623  
624 try
625 {
626 int mtime = getMtime( interp, fileName, fileObj );
627 TclObject mtimeObj = TclInteger.newInstance( mtime );
628 TclObject atimeObj = TclInteger.newInstance( mtime );
629 TclObject ctimeObj = TclInteger.newInstance( mtime );
630 interp.setVar( varName, "atime", atimeObj, 0 );
631 interp.setVar( varName, "ctime", ctimeObj, 0 );
632 interp.setVar( varName, "mtime", mtimeObj, 0 );
633 }
634 catch ( System.Security.SecurityException e )
635 {
636 throw new TclException( interp, e.Message );
637 }
638 catch ( TclException e )
639 {
640 throw new TclException( interp, "can't set \"" + varName + "(dev)\": variable isn't array" );
641 }
642  
643 try
644 {
645 TclObject sizeObj = TclInteger.newInstance( (int)SupportClass.FileLength( fileObj ) );
646 interp.setVar( varName, "size", sizeObj, 0 );
647 }
648 catch ( System.Exception e )
649 {
650 // Do nothing.
651 }
652  
653 try
654 {
655 TclObject typeObj = TclString.newInstance( getType( interp, fileName, fileObj ) );
656 interp.setVar( varName, "type", typeObj, 0 );
657 }
658 catch ( System.Exception e )
659 {
660 }
661  
662 try
663 {
664 TclObject uidObj = TclBoolean.newInstance( isOwner( interp, fileObj ) );
665 interp.setVar( varName, "uid", uidObj, 0 );
666 }
667 catch ( TclException e )
668 {
669 // Do nothing.
670 }
671 }
672 private static string getExtension( string path )
673 // Path for which we find extension.
674 {
675 if ( path.Length < 1 )
676 {
677 return "";
678 }
679  
680 // Set lastSepIndex to the first index in the last component of the path.
681  
682 int lastSepIndex = -1;
683 switch ( JACL.PLATFORM )
684 {
685  
686 case JACL.PLATFORM_WINDOWS:
687 string tmpPath = path.Replace( '\\', '/' ).Replace( ':', '/' );
688 lastSepIndex = tmpPath.LastIndexOf( (System.Char)'/' );
689 break;
690  
691 case JACL.PLATFORM_MAC:
692 lastSepIndex = path.LastIndexOf( (System.Char)':' );
693 if ( lastSepIndex == -1 )
694 {
695 lastSepIndex = path.LastIndexOf( (System.Char)'/' );
696 }
697 break;
698  
699 default:
700 lastSepIndex = path.LastIndexOf( (System.Char)'/' );
701 break;
702  
703 }
704 ++lastSepIndex;
705  
706 // Return "" if the last character is a separator.
707  
708 if ( lastSepIndex >= path.Length )
709 {
710 return ( "" );
711 }
712  
713 // Find the last dot in the last component of the path.
714  
715 string lastSep = path.Substring( lastSepIndex );
716 int dotIndex = lastSep.LastIndexOf( (System.Char)'.' );
717  
718 // Return "" if no dot was found in the file's name.
719  
720 if ( dotIndex == -1 )
721 {
722 return "";
723 }
724  
725 // In earlier versions, we used to back up to the first period in a series
726 // so that "foo..o" would be split into "foo" and "..o". This is a
727 // confusing and usually incorrect behavior, so now we split at the last
728 // period in the name.
729  
730 return ( lastSep.Substring( dotIndex ) );
731 }
732 private static string getTail( Interp interp, string path )
733 {
734 // Split the path and return the string form of the last component,
735 // unless there is only one component which is the root or an absolute
736 // path.
737  
738 TclObject splitResult = FileUtil.splitAndTranslate( interp, path );
739  
740 int last = TclList.getLength( interp, splitResult ) - 1;
741  
742 if ( last >= 0 )
743 {
744 if ( ( last > 0 ) || ( FileUtil.getPathType( path ) == FileUtil.PATH_RELATIVE ) )
745 {
746 TclObject tailObj = TclList.index( interp, splitResult, last );
747  
748 return tailObj.ToString();
749 }
750 }
751 return "";
752 }
753 private static void fileMakeDirs( Interp interp, TclObject[] argv )
754 {
755 bool madeDir = false;
756  
757 for ( int currentDir = 2; currentDir < argv.Length; currentDir++ )
758 {
759  
760 string dirName = argv[currentDir].ToString();
761 if ( dirName.Length == 0 )
762 {
763 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "can't create directory \"\"" );
764 }
765 FileInfo dirObj = FileUtil.getNewFileObj( interp, dirName );
766 bool tmpBool;
767 if ( File.Exists( dirObj.FullName ) )
768 tmpBool = true;
769 else
770 tmpBool = Directory.Exists( dirObj.FullName );
771 if ( tmpBool )
772 {
773 // If the directory already exists, do nothing.
774 if ( Directory.Exists( dirObj.FullName ) )
775 {
776 continue;
777 }
778 throw new TclPosixException( interp, TclPosixException.EEXIST, true, "can't create directory \"" + dirName + "\"" );
779 }
780 try
781 {
782 Directory.CreateDirectory( dirObj.FullName );
783 madeDir = true;
784 }
785 catch ( Exception e )
786 {
787 throw new TclException( interp, e.Message );
788 }
789 if ( !madeDir )
790 {
791 throw new TclPosixException( interp, TclPosixException.EACCES, true, "can't create directory \"" + dirName + "\": best guess at reason" );
792 }
793 }
794 }
795 private static void fileDelete( Interp interp, TclObject[] argv )
796 {
797 bool force = false;
798 int firstSource = 2;
799  
800 for ( bool last = false; ( firstSource < argv.Length ) && ( !last ); firstSource++ )
801 {
802  
803  
804 if ( !argv[firstSource].ToString().StartsWith( "-" ) )
805 {
806 break;
807 }
808 int opt = TclIndex.get( interp, argv[firstSource], validOptions, "option", 1 );
809 switch ( opt )
810 {
811  
812 case OPT_FORCE:
813 force = true;
814 break;
815  
816 case OPT_LAST:
817 last = true;
818 break;
819  
820 default:
821 throw new TclRuntimeError( "FileCmd.cmdProc: bad option " + opt + " index to validOptions" );
822  
823 }
824 }
825  
826 if ( firstSource >= argv.Length )
827 {
828 throw new TclNumArgsException( interp, 2, argv, "?options? file ?file ...?" );
829 }
830  
831 for ( int i = firstSource; i < argv.Length; i++ )
832 {
833  
834 deleteOneFile( interp, argv[i].ToString(), force );
835 }
836 }
837 private static void deleteOneFile( Interp interp, string fileName, bool force )
838 {
839 if ( fileName == ":memory:" )
840 return;
841 bool isDeleted = true;
842 FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );
843  
844 // Trying to delete a file that does not exist is not
845 // considered an error, just a no-op
846  
847 bool tmpBool;
848 if ( File.Exists( fileObj.FullName ) )
849 tmpBool = true;
850 else
851 tmpBool = Directory.Exists( fileObj.FullName );
852 if ( ( !tmpBool ) || ( fileName.Length == 0 ) )
853 {
854 return;
855 }
856  
857 // If the file is a non-empty directory, recursively delete its children if
858 // the -force option was chosen. Otherwise, throw an error.
859  
860 if ( Directory.Exists( fileObj.FullName ) && ( Directory.GetFileSystemEntries( fileObj.FullName ).Length > 0 ) )
861 {
862 if ( force )
863 {
864 string[] fileList = Directory.GetFileSystemEntries( fileObj.FullName );
865 for ( int i = 0; i < fileList.Length; i++ )
866 {
867  
868 TclObject[] joinArrayObj = new TclObject[2];
869 joinArrayObj[0] = TclString.newInstance( fileName );
870 joinArrayObj[1] = TclString.newInstance( fileList[i] );
871  
872 string child = FileUtil.joinPath( interp, joinArrayObj, 0, 2 );
873 deleteOneFile( interp, child, force );
874 }
875 }
876 else
877 {
878 throw new TclPosixException( interp, TclPosixException.ENOTEMPTY, "error deleting \"" + fileName + "\": directory not empty" );
879 }
880 }
881 try
882 {
883 bool tmpBool2;
884 if ( File.Exists( fileObj.FullName ) )
885 {
886 fileObj.Attributes = FileAttributes.Normal;
887 File.Delete( fileObj.FullName );
888 tmpBool2 = true;
889 }
890 else if ( Directory.Exists( fileObj.FullName ) )
891 {
892 Directory.Delete( fileObj.FullName );
893 tmpBool2 = true;
894 }
895 else
896 tmpBool2 = false;
897 isDeleted = tmpBool2;
898 }
899 catch ( IOException e )
900 {
901 throw new TclException( interp, e.Message );
902 }
903 catch ( System.Security.SecurityException e )
904 {
905 throw new TclException( interp, e.Message );
906 }
907 if ( !isDeleted )
908 {
909 throw new TclPosixException( interp, TclPosixException.EACCES, true, "error deleting \"" + fileName + "\": best guess at reason" );
910 }
911 }
912 private static void fileCopyRename( Interp interp, TclObject[] argv, bool copyFlag )
913 {
914 int firstSource = 2;
915 bool force = false;
916  
917 for ( bool last = false; ( firstSource < argv.Length ) && ( !last ); firstSource++ )
918 {
919  
920  
921 if ( !argv[firstSource].ToString().StartsWith( "-" ) )
922 {
923 break;
924 }
925 int opt = TclIndex.get( interp, argv[firstSource], validOptions, "option", 1 );
926 switch ( opt )
927 {
928  
929 case OPT_FORCE:
930 force = true;
931 break;
932  
933 case OPT_LAST:
934 last = true;
935 break;
936  
937 default:
938 throw new TclRuntimeError( "FileCmd.cmdProc: bad option " + opt + " index to validOptions" );
939  
940 }
941 }
942  
943 if ( firstSource >= ( argv.Length - 1 ) )
944 {
945 throw new TclNumArgsException( interp, firstSource, argv, "?options? source ?source ...? target" );
946 }
947  
948 // WARNING: ignoring links because Java does not support them.
949  
950 int target = argv.Length - 1;
951  
952 string targetName = argv[target].ToString();
953  
954 FileInfo targetObj = FileUtil.getNewFileObj( interp, targetName );
955 if ( Directory.Exists( targetObj.FullName ) )
956 {
957 // If the target is a directory, move each source file into target
958 // directory. Extract the tailname from each source, and append it to
959 // the end of the target path.
960  
961 for ( int source = firstSource; source < target; source++ )
962 {
963  
964  
965 string sourceName = argv[source].ToString();
966  
967 if ( targetName.Length == 0 )
968 {
969 copyRenameOneFile( interp, sourceName, targetName, copyFlag, force );
970 }
971 else
972 {
973 string tailName = getTail( interp, sourceName );
974  
975 TclObject[] joinArrayObj = new TclObject[2];
976 joinArrayObj[0] = TclString.newInstance( targetName );
977 joinArrayObj[1] = TclString.newInstance( tailName );
978  
979 string fullTargetName = FileUtil.joinPath( interp, joinArrayObj, 0, 2 );
980  
981 copyRenameOneFile( interp, sourceName, fullTargetName, copyFlag, force );
982 }
983 }
984 }
985 else
986 {
987 // If there is more than 1 source file and the target is not a
988 // directory, then throw an exception.
989  
990 if ( firstSource + 1 != target )
991 {
992 string action;
993 if ( copyFlag )
994 {
995 action = "copying";
996 }
997 else
998 {
999 action = "renaming";
1000 }
1001  
1002 throw new TclPosixException( interp, TclPosixException.ENOTDIR, "error " + action + ": target \"" + argv[target].ToString() + "\" is not a directory" );
1003 }
1004  
1005 string sourceName = argv[firstSource].ToString();
1006 copyRenameOneFile( interp, sourceName, targetName, copyFlag, force );
1007 }
1008 }
1009 private static void copyRenameOneFile( Interp interp, string sourceName, string targetName, bool copyFlag, bool force )
1010 {
1011 // Copying or renaming a file onto itself is a no-op if force is chosen,
1012 // otherwise, it will be caught later as an EEXISTS error.
1013  
1014 if ( force && sourceName.Equals( targetName ) )
1015 {
1016 return;
1017 }
1018  
1019 // Check that the source exists and that if -force was not specified, the
1020 // target doesn't exist.
1021 //
1022 // Prevent copying/renaming a file onto a directory and
1023 // vice-versa. This is a policy decision based on the fact that
1024 // existing implementations of copy and rename on all platforms
1025 // also prevent this.
1026  
1027 string action;
1028 if ( copyFlag )
1029 {
1030 action = "copying";
1031 }
1032 else
1033 {
1034 action = "renaming";
1035 }
1036  
1037 FileInfo sourceFileObj = FileUtil.getNewFileObj( interp, sourceName );
1038 bool tmpBool;
1039 if ( File.Exists( sourceFileObj.FullName ) )
1040 tmpBool = true;
1041 else
1042 tmpBool = Directory.Exists( sourceFileObj.FullName );
1043 if ( ( !tmpBool ) || ( sourceName.Length == 0 ) )
1044 {
1045 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "error " + action + " \"" + sourceName + "\"" );
1046 }
1047  
1048 if ( targetName.Length == 0 )
1049 {
1050 throw new TclPosixException( interp, TclPosixException.ENOENT, true, "error " + action + " \"" + sourceName + "\" to \"" + targetName + "\"" );
1051 }
1052 FileInfo targetFileObj = FileUtil.getNewFileObj( interp, targetName );
1053 bool tmpBool2;
1054 if ( File.Exists( targetFileObj.FullName ) )
1055 tmpBool2 = true;
1056 else
1057 tmpBool2 = Directory.Exists( targetFileObj.FullName );
1058 if ( tmpBool2 && !force )
1059 {
1060 throw new TclPosixException( interp, TclPosixException.EEXIST, true, "error " + action + " \"" + sourceName + "\" to \"" + targetName + "\"" );
1061 }
1062  
1063 if ( Directory.Exists( sourceFileObj.FullName ) && !Directory.Exists( targetFileObj.FullName ) )
1064 {
1065 throw new TclPosixException( interp, TclPosixException.EISDIR, "can't overwrite file \"" + targetName + "\" with directory \"" + sourceName + "\"" );
1066 }
1067 if ( Directory.Exists( targetFileObj.FullName ) && !Directory.Exists( sourceFileObj.FullName ) )
1068 {
1069 throw new TclPosixException( interp, TclPosixException.EISDIR, "can't overwrite directory \"" + targetName + "\" with file \"" + sourceName + "\"" );
1070 }
1071  
1072 if ( !copyFlag )
1073 {
1074 // Perform the rename procedure.
1075  
1076 try
1077 {
1078 sourceFileObj.MoveTo( targetFileObj.FullName );
1079 }
1080 catch ( Exception e )
1081 {
1082 throw new TclPosixException( interp, TclPosixException.EACCES, true, "error renaming \"" + sourceName + "\" to \"" + targetName + "\"" );
1083 }
1084 // {
1085 //
1086 // if (Directory.Exists(targetFileObj.FullName))
1087 // {
1088 // throw new TclPosixException(interp, TclPosixException.EEXIST, true, "error renaming \"" + sourceName + "\" to \"" + targetName + "\"");
1089 // }
1090 //
1091 // throw new TclPosixException(interp, TclPosixException.EACCES, true, "error renaming \"" + sourceName + "\" to \"" + targetName + "\": best guess at reason");
1092 // }
1093 }
1094 else
1095 {
1096 // Perform the copy procedure.
1097  
1098 try
1099 {
1100 sourceFileObj.CopyTo( targetFileObj.FullName, true );
1101 }
1102 catch ( IOException e )
1103 {
1104 throw new TclException( interp, "error copying: " + e.Message );
1105 }
1106 }
1107 }
1108 private static void fileSetReadOnly( Interp interp, TclObject[] argv )
1109 {
1110 int firstSource = 2;
1111  
1112 for ( bool last = false; ( firstSource < argv.Length ) && ( !last ); firstSource++ )
1113 {
1114 if ( !argv[firstSource].ToString().StartsWith( "-" ) )
1115 {
1116 break;
1117 }
1118 }
1119  
1120 if ( firstSource >= argv.Length )
1121 {
1122 throw new TclNumArgsException( interp, 2, argv, "?options? file ?file ...?" );
1123 }
1124  
1125 for ( int i = firstSource; i < argv.Length; i++ )
1126 {
1127  
1128 setReadOnlyOneFile( interp, argv[i].ToString() );
1129 }
1130 }
1131 private static void setReadOnlyOneFile( Interp interp, string fileName )
1132 {
1133 FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );
1134 try
1135 {
1136 fileObj.Attributes = FileAttributes.ReadOnly;
1137 }
1138 catch ( IOException e )
1139 {
1140 throw new TclException( interp, e.Message );
1141 }
1142 catch ( System.Security.SecurityException e )
1143 {
1144 throw new TclException( interp, e.Message );
1145 }
1146 }
1147 static FileCmd()
1148 {
1149 {
1150 // File.listRoots()
1151 Type[] parameterTypes = new Type[0];
1152 try
1153 {
1154 listRootsMethod = typeof( FileInfo ).GetMethod( "listRoots", (System.Type[])parameterTypes );
1155 }
1156 catch ( System.MethodAccessException e )
1157 {
1158 listRootsMethod = null;
1159 }
1160 }
1161 }
1162 } // end FileCmd class
1163 }