dotgnu-pnet-commits
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]