wasCSharpSQLite – Rev 1
?pathlinks?
/*
* FileCmd.java --
*
* This file contains the Jacl implementation of the built-in Tcl "file"
* command.
*
* Copyright (c) 1997 Cornell University.
* Copyright (c) 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.
*
* Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
*
* RCS @(#) $Id: FileCmd.java,v 1.9 2003/02/03 01:39:02 mdejong Exp $
*
*/
using System;
using System.IO;
namespace tcl.lang
{
/*
* This class implements the built-in "file" command in Tcl.
*/
class FileCmd : Command
{
/// <summary> Reference to File.listRoots, null when JDK < 1.2</summary>
private static System.Reflection.MethodInfo listRootsMethod;
internal static Type procClass = null;
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" };
private const int OPT_ATIME = 0;
private const int OPT_ATTRIBUTES = 1;
private const int OPT_CHANNELS = 2;
private const int OPT_COPY = 3;
private const int OPT_DELETE = 4;
private const int OPT_DIRNAME = 5;
private const int OPT_EXECUTABLE = 6;
private const int OPT_EXISTS = 7;
private const int OPT_EXTENSION = 8;
private const int OPT_ISDIRECTORY = 9;
private const int OPT_ISFILE = 10;
private const int OPT_JOIN = 11;
private const int OPT_LINK = 12;
private const int OPT_LSTAT = 13;
private const int OPT_MTIME = 14;
private const int OPT_MKDIR = 15;
private const int OPT_NATIVENAME = 16;
private const int OPT_NORMALIZE = 17;
private const int OPT_OWNED = 18;
private const int OPT_PATHTYPE = 19;
private const int OPT_READABLE = 20;
private const int OPT_READLINK = 21;
private const int OPT_RENAME = 22;
private const int OPT_ROOTNAME = 23;
private const int OPT_SEPARATOR = 24;
private const int OPT_SIZE = 25;
private const int OPT_SPLIT = 26;
private const int OPT_STAT = 27;
private const int OPT_SYSTEM = 28;
private const int OPT_TAIL = 29;
private const int OPT_TYPE = 30;
private const int OPT_VOLUMES = 31;
private const int OPT_WRITABLE = 32;
private static readonly string[] validOptions = new string[] { "-force", "--" };
private const int OPT_FORCE = 0;
private const int OPT_LAST = 1;
public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
{
if ( argv.Length < 2 )
{
throw new TclNumArgsException( interp, 1, argv, "option ?arg ...?" );
}
int opt = TclIndex.get( interp, argv[1], validCmds, "option", 0 );
string path;
FileInfo fileObj = null;
switch ( opt )
{
case OPT_ATIME:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
// FIXME: Currently returns the same thing as MTIME.
// Java does not support retrieval of access time.
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
interp.setResult( getMtime( interp, argv[2].ToString(), fileObj ) );
return TCL.CompletionCode.RETURN;
case OPT_ATTRIBUTES:
if ( argv[3].ToString() == "-readonly" )
fileSetReadOnly( interp, argv );
else
throw new TclException( interp, "sorry, \"file attributes\" is not implemented yet" );
return TCL.CompletionCode.RETURN;
case OPT_CHANNELS:
throw new TclException( interp, "sorry, \"file channels\" is not implemented yet" );
case OPT_COPY:
fileCopyRename( interp, argv, true );
return TCL.CompletionCode.RETURN;
case OPT_DELETE:
fileDelete( interp, argv );
return TCL.CompletionCode.RETURN;
case OPT_DIRNAME:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
path = argv[2].ToString();
// Return all but the last component. If there is only one
// component, return it if the path was non-relative, otherwise
// return the current directory.
TclObject[] splitArrayObj = TclList.getElements( interp, FileUtil.splitAndTranslate( interp, path ) );
if ( splitArrayObj.Length > 1 )
{
interp.setResult( FileUtil.joinPath( interp, splitArrayObj, 0, splitArrayObj.Length - 1 ) );
}
else if ( ( splitArrayObj.Length == 0 ) || ( FileUtil.getPathType( path ) == FileUtil.PATH_RELATIVE ) )
{
if ( JACL.PLATFORM == JACL.PLATFORM_MAC )
{
interp.setResult( ":" );
}
else
{
interp.setResult( "." );
}
}
else
{
interp.setResult( splitArrayObj[0].ToString() );
}
return TCL.CompletionCode.RETURN;
case OPT_EXECUTABLE:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
bool isExe = false;
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
// A file must exist to be executable. Directories are always
// executable.
bool tmpBool;
if ( File.Exists( fileObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( fileObj.FullName );
if ( tmpBool )
{
isExe = Directory.Exists( fileObj.FullName );
if ( isExe )
{
interp.setResult( isExe );
return TCL.CompletionCode.RETURN;
}
if ( Util.Windows )
{
// File that ends with .exe, .com, or .bat is executable.
string fileName = argv[2].ToString();
isExe = ( fileName.EndsWith( ".exe" ) || fileName.EndsWith( ".com" ) || fileName.EndsWith( ".bat" ) );
}
else if ( Util.Mac )
{
// FIXME: Not yet implemented on Mac. For now, return true.
// Java does not support executability checking.
isExe = true;
}
else
{
// FIXME: Not yet implemented on Unix. For now, return true.
// Java does not support executability checking.
isExe = true;
}
}
interp.setResult( isExe );
return TCL.CompletionCode.RETURN;
case OPT_EXISTS:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
bool tmpBool2;
if ( File.Exists( fileObj.FullName ) )
tmpBool2 = true;
else
tmpBool2 = Directory.Exists( fileObj.FullName );
interp.setResult( tmpBool2 );
return TCL.CompletionCode.RETURN;
case OPT_EXTENSION:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
interp.setResult( getExtension( argv[2].ToString() ) );
return TCL.CompletionCode.RETURN;
case OPT_ISDIRECTORY:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
interp.setResult( Directory.Exists( fileObj.FullName ) );
return TCL.CompletionCode.RETURN;
case OPT_ISFILE:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
interp.setResult( File.Exists( fileObj.FullName ) );
return TCL.CompletionCode.RETURN;
case OPT_JOIN:
if ( argv.Length < 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name ?name ...?" );
}
interp.setResult( FileUtil.joinPath( interp, argv, 2, argv.Length ) );
return TCL.CompletionCode.RETURN;
case OPT_LINK:
throw new TclException( interp, "sorry, \"file link\" is not implemented yet" );
case OPT_LSTAT:
if ( argv.Length != 4 )
{
throw new TclNumArgsException( interp, 2, argv, "name varName" );
}
// FIXME: Not yet implemented.
// Java does not support link access.
throw new TclException( interp, "file command with opt " + argv[1].ToString() + " is not yet implemented" );
case OPT_MTIME:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
interp.setResult( getMtime( interp, argv[2].ToString(), fileObj ) );
return TCL.CompletionCode.RETURN;
case OPT_MKDIR:
fileMakeDirs( interp, argv );
return TCL.CompletionCode.RETURN;
case OPT_NATIVENAME:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
interp.setResult( FileUtil.translateFileName( interp, argv[2].ToString() ) );
return TCL.CompletionCode.RETURN;
case OPT_NORMALIZE:
throw new TclException( interp, "sorry, \"file normalize\" is not implemented yet" );
case OPT_OWNED:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
interp.setResult( isOwner( interp, fileObj ) );
return TCL.CompletionCode.RETURN;
case OPT_PATHTYPE:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
switch ( FileUtil.getPathType( argv[2].ToString() ) )
{
case FileUtil.PATH_RELATIVE:
interp.setResult( "relative" );
return TCL.CompletionCode.RETURN;
case FileUtil.PATH_VOLUME_RELATIVE:
interp.setResult( "volumerelative" );
return TCL.CompletionCode.RETURN;
case FileUtil.PATH_ABSOLUTE:
interp.setResult( "absolute" );
break;
}
return TCL.CompletionCode.RETURN;
case OPT_READABLE:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
// interp.setResult(fileObj.canRead());
// HACK
interp.setResult( true );
return TCL.CompletionCode.RETURN;
case OPT_READLINK:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
// FIXME: Not yet implemented.
// Java does not support link access.
throw new TclException( interp, "file command with opt " + argv[1].ToString() + " is not yet implemented" );
case OPT_RENAME:
fileCopyRename( interp, argv, false );
return TCL.CompletionCode.RETURN;
case OPT_ROOTNAME:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
string fileName2 = argv[2].ToString();
string extension = getExtension( fileName2 );
int diffLength = fileName2.Length - extension.Length;
interp.setResult( fileName2.Substring( 0, ( diffLength ) - ( 0 ) ) );
return TCL.CompletionCode.RETURN;
case OPT_SEPARATOR:
throw new TclException( interp, "sorry, \"file separator\" is not implemented yet" );
case OPT_SIZE:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
bool tmpBool3;
if ( File.Exists( fileObj.FullName ) )
tmpBool3 = true;
else
tmpBool3 = Directory.Exists( fileObj.FullName );
if ( !tmpBool3 )
{
throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + argv[2].ToString() + "\"" );
}
interp.setResult( (int)SupportClass.FileLength( fileObj ) );
return TCL.CompletionCode.RETURN;
case OPT_SPLIT:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
interp.setResult( FileUtil.splitPath( interp, argv[2].ToString() ) );
return TCL.CompletionCode.RETURN;
case OPT_STAT:
if ( argv.Length != 4 )
{
throw new TclNumArgsException( interp, 2, argv, "name varName" );
}
getAndStoreStatData( interp, argv[2].ToString(), argv[3].ToString() );
return TCL.CompletionCode.RETURN;
case OPT_SYSTEM:
throw new TclException( interp, "sorry, \"file system\" is not implemented yet" );
case OPT_TAIL:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
interp.setResult( getTail( interp, argv[2].ToString() ) );
return TCL.CompletionCode.RETURN;
case OPT_TYPE:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
interp.setResult( getType( interp, argv[2].ToString(), fileObj ) );
return TCL.CompletionCode.RETURN;
case OPT_VOLUMES:
if ( argv.Length != 2 )
{
throw new TclNumArgsException( interp, 2, argv, null );
}
// use Java 1.2's File.listRoots() method if available
if ( listRootsMethod == null )
throw new TclException( interp, "\"file volumes\" is not supported" );
try
{
FileInfo[] roots = (FileInfo[])listRootsMethod.Invoke( null, (System.Object[])new System.Object[0] );
if ( roots != null )
{
TclObject list = TclList.newInstance();
for ( int i = 0; i < roots.Length; i++ )
{
string root = roots[i].FullName;
TclList.append( interp, list, TclString.newInstance( root ) );
}
interp.setResult( list );
}
}
catch ( System.UnauthorizedAccessException ex )
{
throw new TclRuntimeError( "IllegalAccessException in volumes cmd" );
}
catch ( System.ArgumentException ex )
{
throw new TclRuntimeError( "IllegalArgumentException in volumes cmd" );
}
catch ( System.Reflection.TargetInvocationException ex )
{
System.Exception t = ex.GetBaseException();
if ( t is System.ApplicationException )
{
throw (System.ApplicationException)t;
}
else
{
throw new TclRuntimeError( "unexected exception in volumes cmd" );
}
}
return TCL.CompletionCode.RETURN;
case OPT_WRITABLE:
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "name" );
}
fileObj = FileUtil.getNewFileObj( interp, argv[2].ToString() );
interp.setResult( SupportClass.FileCanWrite( fileObj ) );
return TCL.CompletionCode.RETURN;
default:
throw new TclRuntimeError( "file command with opt " + argv[1].ToString() + " is not implemented" );
}
}
private static bool isOwner( Interp interp, FileInfo fileObj )
{
// If the file doesn't exist, return false;
bool tmpBool;
if ( File.Exists( fileObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( fileObj.FullName );
if ( !tmpBool )
{
return false;
}
bool owner = true;
// For Windows and Macintosh, there are no user ids
// associated with a file, so we always return 1.
if ( Util.Unix )
{
// FIXME: Not yet implemented on Unix. Do no checking, for now.
// Java does not support ownership checking.
}
return owner;
}
private static int getMtime( Interp interp, string fileName, FileInfo fileObj )
{
bool tmpBool;
if ( File.Exists( fileObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( fileObj.FullName );
if ( !tmpBool )
{
throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + fileName + "\"" );
}
// Divide to convert msecs to seconds
return (int)( fileObj.LastWriteTime.Ticks / 1000 );
}
private static string getType( Interp interp, string fileName, FileInfo fileObj )
{
bool tmpBool;
if ( File.Exists( fileObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( fileObj.FullName );
if ( !tmpBool )
{
throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + fileName + "\"" );
}
if ( File.Exists( fileObj.FullName ) )
{
return "file";
}
else if ( Directory.Exists( fileObj.FullName ) )
{
return "directory";
}
return "link";
}
private static void getAndStoreStatData( Interp interp, string fileName, string varName )
{
FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );
bool tmpBool;
if ( File.Exists( fileObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( fileObj.FullName );
if ( !tmpBool )
{
throw new TclPosixException( interp, TclPosixException.ENOENT, true, "could not read \"" + fileName + "\"" );
}
try
{
int mtime = getMtime( interp, fileName, fileObj );
TclObject mtimeObj = TclInteger.newInstance( mtime );
TclObject atimeObj = TclInteger.newInstance( mtime );
TclObject ctimeObj = TclInteger.newInstance( mtime );
interp.setVar( varName, "atime", atimeObj, 0 );
interp.setVar( varName, "ctime", ctimeObj, 0 );
interp.setVar( varName, "mtime", mtimeObj, 0 );
}
catch ( System.Security.SecurityException e )
{
throw new TclException( interp, e.Message );
}
catch ( TclException e )
{
throw new TclException( interp, "can't set \"" + varName + "(dev)\": variable isn't array" );
}
try
{
TclObject sizeObj = TclInteger.newInstance( (int)SupportClass.FileLength( fileObj ) );
interp.setVar( varName, "size", sizeObj, 0 );
}
catch ( System.Exception e )
{
// Do nothing.
}
try
{
TclObject typeObj = TclString.newInstance( getType( interp, fileName, fileObj ) );
interp.setVar( varName, "type", typeObj, 0 );
}
catch ( System.Exception e )
{
}
try
{
TclObject uidObj = TclBoolean.newInstance( isOwner( interp, fileObj ) );
interp.setVar( varName, "uid", uidObj, 0 );
}
catch ( TclException e )
{
// Do nothing.
}
}
private static string getExtension( string path )
// Path for which we find extension.
{
if ( path.Length < 1 )
{
return "";
}
// Set lastSepIndex to the first index in the last component of the path.
int lastSepIndex = -1;
switch ( JACL.PLATFORM )
{
case JACL.PLATFORM_WINDOWS:
string tmpPath = path.Replace( '\\', '/' ).Replace( ':', '/' );
lastSepIndex = tmpPath.LastIndexOf( (System.Char)'/' );
break;
case JACL.PLATFORM_MAC:
lastSepIndex = path.LastIndexOf( (System.Char)':' );
if ( lastSepIndex == -1 )
{
lastSepIndex = path.LastIndexOf( (System.Char)'/' );
}
break;
default:
lastSepIndex = path.LastIndexOf( (System.Char)'/' );
break;
}
++lastSepIndex;
// Return "" if the last character is a separator.
if ( lastSepIndex >= path.Length )
{
return ( "" );
}
// Find the last dot in the last component of the path.
string lastSep = path.Substring( lastSepIndex );
int dotIndex = lastSep.LastIndexOf( (System.Char)'.' );
// Return "" if no dot was found in the file's name.
if ( dotIndex == -1 )
{
return "";
}
// In earlier versions, we used to back up to the first period in a series
// so that "foo..o" would be split into "foo" and "..o". This is a
// confusing and usually incorrect behavior, so now we split at the last
// period in the name.
return ( lastSep.Substring( dotIndex ) );
}
private static string getTail( Interp interp, string path )
{
// Split the path and return the string form of the last component,
// unless there is only one component which is the root or an absolute
// path.
TclObject splitResult = FileUtil.splitAndTranslate( interp, path );
int last = TclList.getLength( interp, splitResult ) - 1;
if ( last >= 0 )
{
if ( ( last > 0 ) || ( FileUtil.getPathType( path ) == FileUtil.PATH_RELATIVE ) )
{
TclObject tailObj = TclList.index( interp, splitResult, last );
return tailObj.ToString();
}
}
return "";
}
private static void fileMakeDirs( Interp interp, TclObject[] argv )
{
bool madeDir = false;
for ( int currentDir = 2; currentDir < argv.Length; currentDir++ )
{
string dirName = argv[currentDir].ToString();
if ( dirName.Length == 0 )
{
throw new TclPosixException( interp, TclPosixException.ENOENT, true, "can't create directory \"\"" );
}
FileInfo dirObj = FileUtil.getNewFileObj( interp, dirName );
bool tmpBool;
if ( File.Exists( dirObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( dirObj.FullName );
if ( tmpBool )
{
// If the directory already exists, do nothing.
if ( Directory.Exists( dirObj.FullName ) )
{
continue;
}
throw new TclPosixException( interp, TclPosixException.EEXIST, true, "can't create directory \"" + dirName + "\"" );
}
try
{
Directory.CreateDirectory( dirObj.FullName );
madeDir = true;
}
catch ( Exception e )
{
throw new TclException( interp, e.Message );
}
if ( !madeDir )
{
throw new TclPosixException( interp, TclPosixException.EACCES, true, "can't create directory \"" + dirName + "\": best guess at reason" );
}
}
}
private static void fileDelete( Interp interp, TclObject[] argv )
{
bool force = false;
int firstSource = 2;
for ( bool last = false; ( firstSource < argv.Length ) && ( !last ); firstSource++ )
{
if ( !argv[firstSource].ToString().StartsWith( "-" ) )
{
break;
}
int opt = TclIndex.get( interp, argv[firstSource], validOptions, "option", 1 );
switch ( opt )
{
case OPT_FORCE:
force = true;
break;
case OPT_LAST:
last = true;
break;
default:
throw new TclRuntimeError( "FileCmd.cmdProc: bad option " + opt + " index to validOptions" );
}
}
if ( firstSource >= argv.Length )
{
throw new TclNumArgsException( interp, 2, argv, "?options? file ?file ...?" );
}
for ( int i = firstSource; i < argv.Length; i++ )
{
deleteOneFile( interp, argv[i].ToString(), force );
}
}
private static void deleteOneFile( Interp interp, string fileName, bool force )
{
if ( fileName == ":memory:" )
return;
bool isDeleted = true;
FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );
// Trying to delete a file that does not exist is not
// considered an error, just a no-op
bool tmpBool;
if ( File.Exists( fileObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( fileObj.FullName );
if ( ( !tmpBool ) || ( fileName.Length == 0 ) )
{
return;
}
// If the file is a non-empty directory, recursively delete its children if
// the -force option was chosen. Otherwise, throw an error.
if ( Directory.Exists( fileObj.FullName ) && ( Directory.GetFileSystemEntries( fileObj.FullName ).Length > 0 ) )
{
if ( force )
{
string[] fileList = Directory.GetFileSystemEntries( fileObj.FullName );
for ( int i = 0; i < fileList.Length; i++ )
{
TclObject[] joinArrayObj = new TclObject[2];
joinArrayObj[0] = TclString.newInstance( fileName );
joinArrayObj[1] = TclString.newInstance( fileList[i] );
string child = FileUtil.joinPath( interp, joinArrayObj, 0, 2 );
deleteOneFile( interp, child, force );
}
}
else
{
throw new TclPosixException( interp, TclPosixException.ENOTEMPTY, "error deleting \"" + fileName + "\": directory not empty" );
}
}
try
{
bool tmpBool2;
if ( File.Exists( fileObj.FullName ) )
{
fileObj.Attributes = FileAttributes.Normal;
File.Delete( fileObj.FullName );
tmpBool2 = true;
}
else if ( Directory.Exists( fileObj.FullName ) )
{
Directory.Delete( fileObj.FullName );
tmpBool2 = true;
}
else
tmpBool2 = false;
isDeleted = tmpBool2;
}
catch ( IOException e )
{
throw new TclException( interp, e.Message );
}
catch ( System.Security.SecurityException e )
{
throw new TclException( interp, e.Message );
}
if ( !isDeleted )
{
throw new TclPosixException( interp, TclPosixException.EACCES, true, "error deleting \"" + fileName + "\": best guess at reason" );
}
}
private static void fileCopyRename( Interp interp, TclObject[] argv, bool copyFlag )
{
int firstSource = 2;
bool force = false;
for ( bool last = false; ( firstSource < argv.Length ) && ( !last ); firstSource++ )
{
if ( !argv[firstSource].ToString().StartsWith( "-" ) )
{
break;
}
int opt = TclIndex.get( interp, argv[firstSource], validOptions, "option", 1 );
switch ( opt )
{
case OPT_FORCE:
force = true;
break;
case OPT_LAST:
last = true;
break;
default:
throw new TclRuntimeError( "FileCmd.cmdProc: bad option " + opt + " index to validOptions" );
}
}
if ( firstSource >= ( argv.Length - 1 ) )
{
throw new TclNumArgsException( interp, firstSource, argv, "?options? source ?source ...? target" );
}
// WARNING: ignoring links because Java does not support them.
int target = argv.Length - 1;
string targetName = argv[target].ToString();
FileInfo targetObj = FileUtil.getNewFileObj( interp, targetName );
if ( Directory.Exists( targetObj.FullName ) )
{
// If the target is a directory, move each source file into target
// directory. Extract the tailname from each source, and append it to
// the end of the target path.
for ( int source = firstSource; source < target; source++ )
{
string sourceName = argv[source].ToString();
if ( targetName.Length == 0 )
{
copyRenameOneFile( interp, sourceName, targetName, copyFlag, force );
}
else
{
string tailName = getTail( interp, sourceName );
TclObject[] joinArrayObj = new TclObject[2];
joinArrayObj[0] = TclString.newInstance( targetName );
joinArrayObj[1] = TclString.newInstance( tailName );
string fullTargetName = FileUtil.joinPath( interp, joinArrayObj, 0, 2 );
copyRenameOneFile( interp, sourceName, fullTargetName, copyFlag, force );
}
}
}
else
{
// If there is more than 1 source file and the target is not a
// directory, then throw an exception.
if ( firstSource + 1 != target )
{
string action;
if ( copyFlag )
{
action = "copying";
}
else
{
action = "renaming";
}
throw new TclPosixException( interp, TclPosixException.ENOTDIR, "error " + action + ": target \"" + argv[target].ToString() + "\" is not a directory" );
}
string sourceName = argv[firstSource].ToString();
copyRenameOneFile( interp, sourceName, targetName, copyFlag, force );
}
}
private static void copyRenameOneFile( Interp interp, string sourceName, string targetName, bool copyFlag, bool force )
{
// Copying or renaming a file onto itself is a no-op if force is chosen,
// otherwise, it will be caught later as an EEXISTS error.
if ( force && sourceName.Equals( targetName ) )
{
return;
}
// Check that the source exists and that if -force was not specified, the
// target doesn't exist.
//
// Prevent copying/renaming a file onto a directory and
// vice-versa. This is a policy decision based on the fact that
// existing implementations of copy and rename on all platforms
// also prevent this.
string action;
if ( copyFlag )
{
action = "copying";
}
else
{
action = "renaming";
}
FileInfo sourceFileObj = FileUtil.getNewFileObj( interp, sourceName );
bool tmpBool;
if ( File.Exists( sourceFileObj.FullName ) )
tmpBool = true;
else
tmpBool = Directory.Exists( sourceFileObj.FullName );
if ( ( !tmpBool ) || ( sourceName.Length == 0 ) )
{
throw new TclPosixException( interp, TclPosixException.ENOENT, true, "error " + action + " \"" + sourceName + "\"" );
}
if ( targetName.Length == 0 )
{
throw new TclPosixException( interp, TclPosixException.ENOENT, true, "error " + action + " \"" + sourceName + "\" to \"" + targetName + "\"" );
}
FileInfo targetFileObj = FileUtil.getNewFileObj( interp, targetName );
bool tmpBool2;
if ( File.Exists( targetFileObj.FullName ) )
tmpBool2 = true;
else
tmpBool2 = Directory.Exists( targetFileObj.FullName );
if ( tmpBool2 && !force )
{
throw new TclPosixException( interp, TclPosixException.EEXIST, true, "error " + action + " \"" + sourceName + "\" to \"" + targetName + "\"" );
}
if ( Directory.Exists( sourceFileObj.FullName ) && !Directory.Exists( targetFileObj.FullName ) )
{
throw new TclPosixException( interp, TclPosixException.EISDIR, "can't overwrite file \"" + targetName + "\" with directory \"" + sourceName + "\"" );
}
if ( Directory.Exists( targetFileObj.FullName ) && !Directory.Exists( sourceFileObj.FullName ) )
{
throw new TclPosixException( interp, TclPosixException.EISDIR, "can't overwrite directory \"" + targetName + "\" with file \"" + sourceName + "\"" );
}
if ( !copyFlag )
{
// Perform the rename procedure.
try
{
sourceFileObj.MoveTo( targetFileObj.FullName );
}
catch ( Exception e )
{
throw new TclPosixException( interp, TclPosixException.EACCES, true, "error renaming \"" + sourceName + "\" to \"" + targetName + "\"" );
}
// {
//
// if (Directory.Exists(targetFileObj.FullName))
// {
// throw new TclPosixException(interp, TclPosixException.EEXIST, true, "error renaming \"" + sourceName + "\" to \"" + targetName + "\"");
// }
//
// throw new TclPosixException(interp, TclPosixException.EACCES, true, "error renaming \"" + sourceName + "\" to \"" + targetName + "\": best guess at reason");
// }
}
else
{
// Perform the copy procedure.
try
{
sourceFileObj.CopyTo( targetFileObj.FullName, true );
}
catch ( IOException e )
{
throw new TclException( interp, "error copying: " + e.Message );
}
}
}
private static void fileSetReadOnly( Interp interp, TclObject[] argv )
{
int firstSource = 2;
for ( bool last = false; ( firstSource < argv.Length ) && ( !last ); firstSource++ )
{
if ( !argv[firstSource].ToString().StartsWith( "-" ) )
{
break;
}
}
if ( firstSource >= argv.Length )
{
throw new TclNumArgsException( interp, 2, argv, "?options? file ?file ...?" );
}
for ( int i = firstSource; i < argv.Length; i++ )
{
setReadOnlyOneFile( interp, argv[i].ToString() );
}
}
private static void setReadOnlyOneFile( Interp interp, string fileName )
{
FileInfo fileObj = FileUtil.getNewFileObj( interp, fileName );
try
{
fileObj.Attributes = FileAttributes.ReadOnly;
}
catch ( IOException e )
{
throw new TclException( interp, e.Message );
}
catch ( System.Security.SecurityException e )
{
throw new TclException( interp, e.Message );
}
}
static FileCmd()
{
{
// File.listRoots()
Type[] parameterTypes = new Type[0];
try
{
listRootsMethod = typeof( FileInfo ).GetMethod( "listRoots", (System.Type[])parameterTypes );
}
catch ( System.MethodAccessException e )
{
listRootsMethod = null;
}
}
}
} // end FileCmd class
}