[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Dotgnu-pnet-commits] pnetlib/runtime/System/IO SymbolicLinks.cs, NONE,
From: |
Rhys Weatherley <address@hidden> |
Subject: |
[Dotgnu-pnet-commits] pnetlib/runtime/System/IO SymbolicLinks.cs, NONE, 1.1 |
Date: |
Tue, 02 Dec 2003 02:17:59 +0000 |
Update of /cvsroot/dotgnu-pnet/pnetlib/runtime/System/IO
In directory subversions:/tmp/cvs-serv27973/runtime/System/IO
Added Files:
SymbolicLinks.cs
Log Message:
Add "System.IO.SymbolicLinks" to the library, to support getting symbolic
link information in the file dialog classes.
--- NEW FILE: SymbolicLinks.cs ---
/*
* SymbolicLinks.cs - Implementation of the "System.IO.SymbolicLinks" class.
*
* Copyright (C) 2003 Southern Storm Software, Pty Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
namespace System.IO
{
using System;
using System.Text;
using Platform;
// This is a private extension API, for accessing information about symbolic
// links and Windows shortcuts in the underlying filesystem. We need it for
// the file dialogs in "System.Windows.Forms". Use with care elsewhere.
//
// Information about the ".lnk" format can be found at "myfileformats.com".
[NonStandardExtra]
public sealed class SymbolicLinks
{
// Cannot instantiate this class.
private SymbolicLinks() {}
// Determine if we appear to be running on Windows.
private static bool IsWindows()
{
#if !ECMA_COMPAT
return (InfoMethods.GetPlatformID() !=
(PlatformID)128);
#else
return (Path.DirectorySeparatorChar == '\\');
#endif
}
// Determine if a pathname ends in ".lnk".
private static bool EndsInLnk(String pathname)
{
int len = pathname.Length;
if(len < 4)
{
return false;
}
if(pathname[len - 4] == '.' &&
(pathname[len - 3] == 'l' || pathname[len -
3] == 'L') &&
(pathname[len - 2] == 'n' || pathname[len -
2] == 'N') &&
(pathname[len - 1] == 'k' || pathname[len -
1] == 'K'))
{
return true;
}
return false;
}
// Determine if a pathname is a symbolic link.
public static bool IsSymbolicLink(String pathname)
{
// Validate the parameter and normalize it.
if(pathname == null)
{
throw new
ArgumentNullException("pathname");
}
pathname = Path.NormalizeSeparators(pathname);
// If we are on Windows, then check for a
".lnk" file.
if(IsWindows())
{
if(!EndsInLnk(pathname))
{
// We need to add ".lnk" to the
pathname first.
if(FileMethods.GetFileType(pathname)
!=
FileType.unknown)
{
// The path exists, so
it cannot be a symlink.
return false;
}
pathname += ".lnk";
}
if(FileMethods.GetFileType(pathname)
!= FileType.regularFile)
{
// The path does not exist or
is not a regular file.
return false;
}
return true;
}
// Get the file type from the engine and check
it.
FileType type =
FileMethods.GetFileType(pathname);
return (type == FileType.symbolicLink);
}
// Read the contents of a symbolic link. Returns null if not a
// symbolic link, or throws an exception if the pathname is invalid.
public static String ReadLink(String pathname)
{
// Validate the parameter and normalize it.
Directory.ValidatePath(pathname);
pathname = Path.NormalizeSeparators(pathname);
// Read the contents of the symlink using the
engine.
String contents;
Errno error = FileMethods.ReadLink(pathname,
out contents);
if(error != Errno.Success)
{
Directory.HandleErrorsFile(error);
}
if(contents != null)
{
return contents;
}
// Bail out if we aren't on Windows.
if(!IsWindows())
{
return null;
}
// Make sure that we have ".lnk" on the end of
the name.
if(!EndsInLnk(pathname))
{
if(FileMethods.GetFileType(pathname) !=
FileType.unknown)
{
// Something exists here and it
does not have a ".lnk"
// extension, so it cannot
possibly be a symlink.
return null;
}
pathname += ".lnk";
}
FileType type =
FileMethods.GetFileType(pathname);
if(type == FileType.unknown)
{
// The pathname does not exist.
Directory.HandleErrorsFile(Errno.ENOENT);
}
else if(type != FileType.regularFile)
{
// The pathname exists but it is not a
regular file,
// so it cannot possibly be a symbolic
link.
return null;
}
// Read the contents of the Windows shortcut
file.
ShortcutInformation info =
ReadShortcut(pathname);
if(info == null)
{
return null;
}
else
{
return info.RelativePath;
}
}
// Create a symbolic link at "newpath" that points to "oldpath".
// Throws "NotSupportedException" if the filesystem does not
// support the creation of symbolic links or ".lnk" files.
public static void CreateLink(String oldpath, String newpath)
{
// Validate and normalize the parameters.
Directory.ValidatePath(oldpath);
Directory.ValidatePath(newpath);
oldpath = Path.NormalizeSeparators(oldpath);
newpath = Path.NormalizeSeparators(newpath);
// Try to create the symlink using the engine.
Errno error = FileMethods.CreateLink(oldpath,
newpath);
if(error == Errno.Success)
{
return;
}
else if(error != Errno.EPERM)
{
Directory.HandleErrorsFile(error);
}
// Bail out if we are not on Windows.
if(!IsWindows())
{
throw new
NotSupportedException(_("IO_NotSupp_Symlinks"));
}
// Make sure that we have ".lnk" on the end of
the pathname.
if(!EndsInLnk(newpath))
{
if(FileMethods.GetFileType(newpath) !=
FileType.unknown)
{
// There already exists
something at this location.
Directory.HandleErrorsFile(Errno.EEXIST);
}
newpath += ".lnk";
}
if(FileMethods.GetFileType(newpath) !=
FileType.unknown)
{
// There already exists something at
this location.
Directory.HandleErrorsFile(Errno.EEXIST);
}
// Create the shortcut information to place in
the file.
ShortcutInformation info = new
ShortcutInformation();
info.Description = oldpath;
info.RelativePath = oldpath;
info.ShowWindow = ShowWindow.Normal;
// Write the shortcut information to the file.
WriteShortcut(newpath, info, false);
}
// Attribute information for a Windows shortcut file.
[Flags]
public enum ShortcutAttributes
{
ReadOnly = 0x0001,
Hidden = 0x0002,
System = 0x0004,
Volume = 0x0008,
Directory = 0x0010,
Archive = 0x0020,
Encrypted = 0x0040,
Normal = 0x0080,
Temporary = 0x0100,
Sparse = 0x0200,
PointData = 0x0400,
Compressed = 0x0800,
Offline = 0x1000
}; // enum ShortcutAttributes
// "Show window" values for a Windows shortcut file.
private enum ShowWindow
{
Hide = 0,
Normal = 1,
ShowMinimized = 2,
ShowMaximized = 3,
ShowNoActive = 4,
Show = 5,
Minimize = 6,
ShowMinNoActive = 7,
ShowNa = 8,
Restore = 9,
ShowDefault = 10
}; // enum ShowWindow
// Information that may be stored in a Windows shortcut file.
public class ShortcutInformation
{
// Internal state.
private ShortcutAttributes attributes;
private String description;
private String relativePath;
private String workingDirectory;
private String commandLineArguments;
private String icon;
private DateTime creationTime;
private DateTime modificationTime;
private DateTime lastAccessTime;
private uint fileLength;
private uint iconNumber;
private ShowWindow showWindow;
private uint hotkey;
private byte[] shellIdInfo;
private byte[] fileLocationInfo;
private byte[] rest;
// Constructor.
public ShortcutInformation() {}
// Get or set this object's properties.
public ShortcutAttributes Attributes
{
get
{
return attributes;
}
set
{
attributes = value;
}
}
public String Description
{
get
{
return description;
}
set
{
description = value;
}
}
public String RelativePath
{
get
{
return relativePath;
}
set
{
relativePath = value;
}
}
public String WorkingDirectory
{
get
{
return workingDirectory;
}
set
{
workingDirectory = value;
}
}
public String CommandLineArguments
{
get
{
return commandLineArguments;
}
set
{
commandLineArguments = value;
}
}
public String Icon
{
get
{
return icon;
}
set
{
icon = value;
}
}
public DateTime CreationTime
{
get
{
return creationTime;
}
set
{
creationTime = value;
}
}
public DateTime ModificationTime
{
get
{
return modificationTime;
}
set
{
modificationTime = value;
}
}
public DateTime LastAccessTime
{
get
{
return lastAccessTime;
}
set
{
lastAccessTime = value;
}
}
public uint FileLength
{
get
{
return fileLength;
}
set
{
fileLength = value;
}
}
public uint IconNumber
{
get
{
return iconNumber;
}
set
{
iconNumber = value;
}
}
public ShowWindow ShowWindow
{
get
{
return showWindow;
}
set
{
showWindow = value;
}
}
public uint Hotkey
{
get
{
return hotkey;
}
set
{
hotkey = value;
}
}
public byte[] ShellIdInfo
{
get
{
return shellIdInfo;
}
set
{
shellIdInfo = value;
}
}
public byte[] FileLocationInfo
{
get
{
return fileLocationInfo;
}
set
{
fileLocationInfo = value;
}
}
public byte[] Rest
{
get
{
return rest;
}
set
{
rest = value;
}
}
}; // class ShortcutInformation
// Magic number for Windows shortcut files.
private static readonly byte[] magic =
{0x4C, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x46};
// Read a 16-bit value from a stream.
private static int ReadInt16(Stream stream, byte[] buffer)
{
if(stream.Read(buffer, 0, 2) != 2)
{
return 0;
}
return (int)(buffer[0] | (buffer[1] << 8));
}
// Read a 32-bit value from a stream.
private static uint ReadUInt32(Stream stream, byte[] buffer)
{
if(stream.Read(buffer, 0, 4) != 4)
{
return 0;
}
return (uint)(buffer[0] | (buffer[1] << 8) |
(buffer[2] << 16) |
(buffer[3] << 24));
}
// Base value to turn a FILETIME into a DateTime.
private static readonly DateTime FileTimeBase = new DateTime(1601, 1,
1);
// Read a FILETIME value from a stream as a DateTime object.
private static DateTime ReadFileTime(Stream stream, byte[] buffer)
{
uint low = ReadUInt32(stream, buffer);
uint high = ReadUInt32(stream, buffer);
long combined = (((long)high) << 32) |
((long)low);
if(combined == 0)
{
return DateTime.MinValue;
}
else
{
return new DateTime(combined +
FileTimeBase.Ticks);
}
}
// Read an ASCII string value from a stream.
private static String ReadString(Stream stream, byte[] buffer)
{
int len = ReadInt16(stream, buffer);
byte[] data = new byte [len];
stream.Read(data, 0, len);
return Encoding.Default.GetString(data);
}
// Read the contents of a Windows shortcut file. Returns null if
// the file does not appear to be a shortcut, or throws an exception
// if the pathname is invalid in some fashion.
public static ShortcutInformation ReadShortcut(String pathname)
{
byte[] buffer = new byte [64];
ShortcutInformation info = new
ShortcutInformation();
int posn;
// Open the shortcut file.
FileStream stream = new FileStream
(pathname, FileMode.Open,
FileAccess.Read);
try
{
// Check the magic number in the header.
if(stream.Read(buffer, 0, 20) != 20)
{
return null;
}
for(posn = 0; posn < 20; ++posn)
{
if(buffer[posn] != magic[posn])
{
return null;
}
}
// Read the rest of the header and
decode it.
uint flags = ReadUInt32(stream, buffer);
info.Attributes =
(ShortcutAttributes)(ReadUInt32(stream, buffer));
info.CreationTime =
ReadFileTime(stream, buffer);
info.ModificationTime =
ReadFileTime(stream, buffer);
info.LastAccessTime =
ReadFileTime(stream, buffer);
info.FileLength = ReadUInt32(stream,
buffer);
info.IconNumber = ReadUInt32(stream,
buffer);
info.ShowWindow =
(ShowWindow)(ReadUInt32(stream,
buffer));
info.Hotkey = ReadUInt32(stream,
buffer);
ReadUInt32(stream, buffer);
// reserved
ReadUInt32(stream, buffer);
// reserved
// Read the shell item id list as an
opaque blob.
int dataLen;
byte[] data;
if((flags & 0x0001) != 0)
{
dataLen = ReadInt16(stream,
buffer);
data = new byte [dataLen];
stream.Read(data, 0, dataLen);
info.ShellIdInfo = data;
}
// Read the file location information
as an opaque blob.
if((flags & 0x0002) != 0)
{
dataLen =
(int)(ReadUInt32(stream, buffer));
data = new byte [dataLen + 4];
Array.Copy(buffer, 0, data, 0,
4);
stream.Read(data, 4, dataLen -
4);
info.FileLocationInfo = data;
}
// Read the string information that is
present.
if((flags & 0x0004) != 0)
{
info.Description =
ReadString(stream, buffer);
}
if((flags & 0x0008) != 0)
{
info.RelativePath =
ReadString(stream, buffer);
}
if((flags & 0x0010) != 0)
{
info.WorkingDirectory =
ReadString(stream, buffer);
}
if((flags & 0x0020) != 0)
{
info.CommandLineArguments =
ReadString(stream, buffer);
}
if((flags & 0x0040) != 0)
{
info.Icon = ReadString(stream,
buffer);
}
// Read the rest of the file as an
opaque blob.
if((flags & 0x0080) != 0 &&
stream.CanSeek)
{
dataLen = (int)(stream.Length -
stream.Position);
if(dataLen > 0)
{
data = new byte
[dataLen];
stream.Read(data, 0,
dataLen);
info.Rest = data;
}
}
}
finally
{
stream.Close();
}
return info;
}
// Write a 16-bit value to a stream.
private static void WriteInt16(Stream stream, byte[] buffer, int value)
{
buffer[0] = (byte)value;
buffer[1] = (byte)(value >> 8);
stream.Write(buffer, 0, 2);
}
// Write a 32-bit value to a stream.
private static void WriteUInt32(Stream stream, byte[] buffer, uint
value)
{
buffer[0] = (byte)value;
buffer[1] = (byte)(value >> 8);
buffer[2] = (byte)(value >> 16);
buffer[3] = (byte)(value >> 24);
stream.Write(buffer, 0, 4);
}
// Write a DateTime object from a stream as a FILETIME value.
private static void WriteFileTime
(Stream stream, byte[] buffer, DateTime value)
{
long ticks = value.Ticks;
if(ticks != 0)
{
ticks -= FileTimeBase.Ticks;
}
buffer[0] = (byte)ticks;
buffer[1] = (byte)(ticks >> 8);
buffer[2] = (byte)(ticks >> 16);
buffer[3] = (byte)(ticks >> 24);
buffer[4] = (byte)(ticks >> 32);
buffer[5] = (byte)(ticks >> 40);
buffer[6] = (byte)(ticks >> 48);
buffer[7] = (byte)(ticks >> 56);
stream.Write(buffer, 0, 8);
}
// Write an ASCII string value to a stream.
private static void WriteString(Stream stream, byte[] buffer, String
value)
{
byte[] data = Encoding.Default.GetBytes(value);
WriteInt16(stream, buffer, data.Length);
stream.Write(data, 0, data.Length);
}
// Write a Windows shortcut file. If "createIfExists" is "false",
// then an exception will be thrown if "pathname" already exists.
public static void WriteShortcut(String pathname, ShortcutInformation
info,
bool
createIfExists)
{
// Validate the "info" parameter.
if(info == null)
{
throw new ArgumentNullException("info");
}
// Create the shortcut file stream.
FileStream stream = new FileStream
(pathname, (createIfExists ?
FileMode.Create
: FileMode.CreateNew),
FileAccess.Write);
byte[] buffer = new byte [64];
try
{
// Write the magic number to the file.
stream.Write(magic, 0, 20);
// Determine the flags to put in the
file header.
uint flags = 0;
if(info.ShellIdInfo != null)
{
flags |= 0x0001;
}
if(info.FileLocationInfo != null)
{
flags |= 0x0002;
}
if(info.Description != null)
{
flags |= 0x0004;
}
if(info.RelativePath != null)
{
flags |= 0x0008;
}
if(info.WorkingDirectory != null)
{
flags |= 0x0010;
}
if(info.CommandLineArguments != null)
{
flags |= 0x0020;
}
if(info.Icon != null)
{
flags |= 0x0040;
}
if(info.Rest != null)
{
flags |= 0x0080;
}
// Write out the file header.
WriteUInt32(stream, buffer, flags);
WriteUInt32(stream, buffer,
(uint)(info.Attributes));
WriteFileTime(stream, buffer,
info.CreationTime);
WriteFileTime(stream, buffer,
info.ModificationTime);
WriteFileTime(stream, buffer,
info.LastAccessTime);
WriteUInt32(stream, buffer,
info.FileLength);
WriteUInt32(stream, buffer,
info.IconNumber);
WriteUInt32(stream, buffer,
(uint)(info.ShowWindow));
WriteUInt32(stream, buffer,
info.Hotkey);
WriteUInt32(stream, buffer, 0); //
reserved
WriteUInt32(stream, buffer, 0); //
reserved
// Write the shell item id information.
if(info.ShellIdInfo != null)
{
WriteInt16(stream, buffer,
info.ShellIdInfo.Length);
stream.Write(info.ShellIdInfo,
0,
info.ShellIdInfo.Length);
}
// Write the file location information.
if(info.FileLocationInfo != null)
{
stream.Write(info.FileLocationInfo, 0,
info.FileLocationInfo.Length);
}
// Write the string information.
if(info.Description != null)
{
WriteString(stream, buffer,
info.Description);
}
if(info.RelativePath != null)
{
WriteString(stream, buffer,
info.RelativePath);
}
if(info.WorkingDirectory != null)
{
WriteString(stream, buffer,
info.WorkingDirectory);
}
if(info.CommandLineArguments != null)
{
WriteString(stream, buffer,
info.CommandLineArguments);
}
if(info.Icon != null)
{
WriteString(stream, buffer,
info.Icon);
}
// Write the rest of the data for the
shortcut file.
if(info.Rest != null)
{
stream.Write(info.Rest, 0,
info.Rest.Length);
}
}
finally
{
stream.Close();
}
}
}; // class SymbolicLinks
}; // namespace System.IO
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Dotgnu-pnet-commits] pnetlib/runtime/System/IO SymbolicLinks.cs, NONE, 1.1,
Rhys Weatherley <address@hidden> <=
- Prev by Date:
[Dotgnu-pnet-commits] pnet ChangeLog,1.2815,1.2816
- Next by Date:
[Dotgnu-pnet-commits] pnet/engine int_proto.h, 1.92, 1.93 int_table.c, 1.95, 1.96 lib_file.c, 1.11, 1.12
- Previous by thread:
[Dotgnu-pnet-commits] pnet ChangeLog,1.2815,1.2816
- Next by thread:
[Dotgnu-pnet-commits] pnet/engine int_proto.h, 1.92, 1.93 int_table.c, 1.95, 1.96 lib_file.c, 1.11, 1.12
- Index(es):