Exemple #1
0
        public static void RemoveDirectory(string fullPath, bool recursive)
        {
            if (!recursive)
            {
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            Interop.Kernel32.WIN32_FIND_DATA findData = default;
            // FindFirstFile($path) (used by GetFindData) fails with ACCESS_DENIED when user has no ListDirectory rights
            // but FindFirstFile($path/*") (used by RemoveDirectoryRecursive) works fine in such scenario.
            // So we ignore it here and let RemoveDirectoryRecursive throw if FindFirstFile($path/*") fails with ACCESS_DENIED.
            GetFindData(fullPath, isDirectory: true, ignoreAccessDenied: true, ref findData);
            if (IsNameSurrogateReparsePoint(ref findData))
            {
                // Don't recurse
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            // We want extended syntax so we can delete "extended" subdirectories and files
            // (most notably ones with trailing whitespace or periods)
            fullPath = PathInternal.EnsureExtendedPrefix(fullPath);
            RemoveDirectoryRecursive(fullPath, ref findData, topLevel: true);
        }
Exemple #2
0
        public override void RemoveDirectory(string fullPath, bool recursive)
        {
            // Do not recursively delete through reparse points.  Perhaps in a
            // future version we will add a new flag to control this behavior,
            // but for now we're much safer if we err on the conservative side.
            // This applies to symbolic links and mount points.
            Interop.mincore.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.mincore.WIN32_FILE_ATTRIBUTE_DATA();
            int errorCode = FillAttributeInfo(fullPath, ref data, false, true);

            if (errorCode != 0)
            {
                // Ensure we throw a DirectoryNotFoundException.
                if (errorCode == Interop.mincore.Errors.ERROR_FILE_NOT_FOUND)
                {
                    errorCode = Interop.mincore.Errors.ERROR_PATH_NOT_FOUND;
                }
                throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
            }

            if (((FileAttributes)data.fileAttributes & FileAttributes.ReparsePoint) != 0)
            {
                recursive = false;
            }

            // We want extended syntax so we can delete "extended" subdirectories and files
            // (most notably ones with trailing whitespace or periods)
            RemoveDirectoryHelper(PathInternal.EnsureExtendedPrefix(fullPath), recursive, true);
        }
Exemple #3
0
        internal static void Move(String sourceDirName, String destDirName)
        {
            Contract.Requires(sourceDirName != null);
            Contract.Requires(destDirName != null);
            Contract.Requires(sourceDirName.Length != 0);
            Contract.Requires(destDirName.Length != 0);

            String fullsourceDirName = LongPath.NormalizePath(sourceDirName);
            String sourcePath        = GetDemandDir(fullsourceDirName, false);

            if (sourcePath.Length >= Path.MaxLongPath)
            {
                throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
            }

            String fulldestDirName = LongPath.NormalizePath(destDirName);
            String destPath        = GetDemandDir(fulldestDirName, false);

            if (destPath.Length >= Path.MaxLongPath)
            {
                throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
            }

            FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, sourcePath, false, false);
            FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, destPath, false, false);

            if (String.Compare(sourcePath, destPath, StringComparison.OrdinalIgnoreCase) == 0)
            {
                throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustBeDifferent"));
            }

            String sourceRoot      = LongPath.GetPathRoot(sourcePath);
            String destinationRoot = LongPath.GetPathRoot(destPath);

            if (String.Compare(sourceRoot, destinationRoot, StringComparison.OrdinalIgnoreCase) != 0)
            {
                throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustHaveSameRoot"));
            }


            String tempSourceDirName = PathInternal.EnsureExtendedPrefix(sourceDirName);
            String tempDestDirName   = PathInternal.EnsureExtendedPrefix(destDirName);

            if (!Win32Native.MoveFile(tempSourceDirName, tempDestDirName))
            {
                int hr = Marshal.GetLastWin32Error();
                if (hr == Win32Native.ERROR_FILE_NOT_FOUND) // Source dir not found
                {
                    hr = Win32Native.ERROR_PATH_NOT_FOUND;
                    __Error.WinIOError(hr, fullsourceDirName);
                }
                // This check was originally put in for Win9x (unfortunately without special casing it to be for Win9x only). We can't change the NT codepath now for backcomp reasons.
                if (hr == Win32Native.ERROR_ACCESS_DENIED) // WinNT throws IOException. This check is for Win9x. We can't change it for backcomp.
                {
                    throw new IOException(Environment.GetResourceString("UnauthorizedAccess_IODenied_Path", sourceDirName), Win32Native.MakeHRFromErrorCode(hr));
                }
                __Error.WinIOError(hr, String.Empty);
            }
        }
Exemple #4
0
        internal static void Move(string sourceDirName, string destDirName)
        {
            string text      = LongPath.NormalizePath(sourceDirName);
            string demandDir = LongPathDirectory.GetDemandDir(text, false);

            if (demandDir.Length >= 32767)
            {
                throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
            }
            string fullPath   = LongPath.NormalizePath(destDirName);
            string demandDir2 = LongPathDirectory.GetDemandDir(fullPath, false);

            if (demandDir2.Length >= 32767)
            {
                throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
            }
            FileIOPermission.QuickDemand(FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, demandDir, false, false);
            FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, demandDir2, false, false);
            if (string.Compare(demandDir, demandDir2, StringComparison.OrdinalIgnoreCase) == 0)
            {
                throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustBeDifferent"));
            }
            string pathRoot  = LongPath.GetPathRoot(demandDir);
            string pathRoot2 = LongPath.GetPathRoot(demandDir2);

            if (string.Compare(pathRoot, pathRoot2, StringComparison.OrdinalIgnoreCase) != 0)
            {
                throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustHaveSameRoot"));
            }
            string src = PathInternal.EnsureExtendedPrefix(sourceDirName);
            string dst = PathInternal.EnsureExtendedPrefix(destDirName);

            if (!Win32Native.MoveFile(src, dst))
            {
                int num = Marshal.GetLastWin32Error();
                if (num == 2)
                {
                    num = 3;
                    __Error.WinIOError(num, text);
                }
                if (num == 5)
                {
                    throw new IOException(Environment.GetResourceString("UnauthorizedAccess_IODenied_Path", new object[]
                    {
                        sourceDirName
                    }), Win32Native.MakeHRFromErrorCode(num));
                }
                __Error.WinIOError(num, string.Empty);
            }
        }
Exemple #5
0
        public static void RemoveDirectory(string fullPath, bool recursive)
        {
            // Do not recursively delete through reparse points.
            if (!recursive || IsReparsePoint(fullPath))
            {
                RemoveDirectoryInternal(fullPath, topLevel: true);
                return;
            }

            // We want extended syntax so we can delete "extended" subdirectories and files
            // (most notably ones with trailing whitespace or periods)
            fullPath = PathInternal.EnsureExtendedPrefix(fullPath);

            Interop.Kernel32.WIN32_FIND_DATA findData = new Interop.Kernel32.WIN32_FIND_DATA();
            RemoveDirectoryRecursive(fullPath, ref findData, topLevel: true);
        }
Exemple #6
0
        private unsafe static void InternalCreateDirectory(string fullPath, string path, object dirSecurityObj)
        {
            DirectorySecurity directorySecurity = (DirectorySecurity)dirSecurityObj;
            int num = fullPath.Length;

            if (num >= 2 && Path.IsDirectorySeparator(fullPath[num - 1]))
            {
                num--;
            }
            int rootLength = LongPath.GetRootLength(fullPath);

            if (num == 2 && Path.IsDirectorySeparator(fullPath[1]))
            {
                throw new IOException(Environment.GetResourceString("IO.IO_CannotCreateDirectory", new object[]
                {
                    path
                }));
            }
            List <string> list = new List <string>();
            bool          flag = false;

            if (num > rootLength)
            {
                int num2 = num - 1;
                while (num2 >= rootLength && !flag)
                {
                    string text = fullPath.Substring(0, num2 + 1);
                    if (!LongPathDirectory.InternalExists(text))
                    {
                        list.Add(text);
                    }
                    else
                    {
                        flag = true;
                    }
                    while (num2 > rootLength && fullPath[num2] != Path.DirectorySeparatorChar && fullPath[num2] != Path.AltDirectorySeparatorChar)
                    {
                        num2--;
                    }
                    num2--;
                }
            }
            int count = list.Count;

            if (list.Count != 0 && !CodeAccessSecurityEngine.QuickCheckForAllDemands())
            {
                string[] array = new string[list.Count];
                list.CopyTo(array, 0);
                for (int i = 0; i < array.Length; i++)
                {
                    string[] array2 = array;
                    int      num3   = i;
                    array2[num3] += "\\.";
                }
                AccessControlActions control = (directorySecurity == null) ? AccessControlActions.None : AccessControlActions.Change;
                FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, control, array, false, false);
            }
            Win32Native.SECURITY_ATTRIBUTES security_ATTRIBUTES = null;
            if (directorySecurity != null)
            {
                security_ATTRIBUTES         = new Win32Native.SECURITY_ATTRIBUTES();
                security_ATTRIBUTES.nLength = Marshal.SizeOf <Win32Native.SECURITY_ATTRIBUTES>(security_ATTRIBUTES);
                byte[] securityDescriptorBinaryForm = directorySecurity.GetSecurityDescriptorBinaryForm();
                byte * ptr = stackalloc byte[checked (unchecked ((UIntPtr)securityDescriptorBinaryForm.Length) * 1)];
                Buffer.Memcpy(ptr, 0, securityDescriptorBinaryForm, 0, securityDescriptorBinaryForm.Length);
                security_ATTRIBUTES.pSecurityDescriptor = ptr;
            }
            bool   flag2         = true;
            int    num4          = 0;
            string maybeFullPath = path;

            while (list.Count > 0)
            {
                string text2 = list[list.Count - 1];
                list.RemoveAt(list.Count - 1);
                if (text2.Length >= 32767)
                {
                    throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
                }
                flag2 = Win32Native.CreateDirectory(PathInternal.EnsureExtendedPrefix(text2), security_ATTRIBUTES);
                if (!flag2 && num4 == 0)
                {
                    int lastWin32Error = Marshal.GetLastWin32Error();
                    if (lastWin32Error != 183)
                    {
                        num4 = lastWin32Error;
                    }
                    else if (LongPathFile.InternalExists(text2) || (!LongPathDirectory.InternalExists(text2, out lastWin32Error) && lastWin32Error == 5))
                    {
                        num4 = lastWin32Error;
                        try
                        {
                            FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, LongPathDirectory.GetDemandDir(text2, true), false, false);
                            maybeFullPath = text2;
                        }
                        catch (SecurityException)
                        {
                        }
                    }
                }
            }
            if (count == 0 && !flag)
            {
                string path2 = LongPathDirectory.InternalGetDirectoryRoot(fullPath);
                if (!LongPathDirectory.InternalExists(path2))
                {
                    __Error.WinIOError(3, LongPathDirectory.InternalGetDirectoryRoot(path));
                }
                return;
            }
            if (!flag2 && num4 != 0)
            {
                __Error.WinIOError(num4, maybeFullPath);
            }
        }
        internal unsafe bool TryExpandShortFileName()
        {
            if (doNotTryExpandShortFileName)
            {
                return(false);
            }

            if (useStackAlloc)
            {
                NullTerminate();
                char *buffer = UnsafeGetArrayPtr();
                char *shortFileNameBuffer = stackalloc char[Path.MaxPath + 1];

                int r = Interop.mincore.GetLongPathNameUnsafe(buffer, shortFileNameBuffer, Path.MaxPath);

                // If success, the return buffer length does not account for the terminating null character.
                // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character.
                // If failure, the return buffer length is zero
                if (r >= Path.MaxPath)
                {
                    throw new PathTooLongException(SR.IO_PathTooLong);
                }

                if (r == 0)
                {
                    // Note: GetLongPathName will return ERROR_INVALID_FUNCTION on a
                    // path like \\.\PHYSICALDEVICE0 - some device driver doesn't
                    // support GetLongPathName on that string.  This behavior is
                    // by design, according to the Core File Services team.
                    // We also get ERROR_NOT_ENOUGH_QUOTA in SQL_CLR_STRESS runs
                    // intermittently on paths like D:\DOCUME~1\user\LOCALS~1\Temp\

                    // We do not need to call GetLongPathName if we know it will fail becasue the path does not exist:
                    int lastErr = Marshal.GetLastWin32Error();
                    if (lastErr == Interop.mincore.Errors.ERROR_FILE_NOT_FOUND || lastErr == Interop.mincore.Errors.ERROR_PATH_NOT_FOUND)
                    {
                        doNotTryExpandShortFileName = true;
                    }

                    return(false);
                }

                // Safe to copy as we have already done Path.MaxPath bound checking
                Wstrcpy(buffer, shortFileNameBuffer, r);
                Length = r;
                // We should explicitly null terminate as in some cases the long version of the path
                // might actually be shorter than what we started with because of Win32's normalization
                // Safe to write directly as bufferLength is guaranteed to be < Path.MaxPath
                NullTerminate();
                return(true);
            }
            else
            {
                StringBuilder sb = GetStringBuilder();

                String origName    = sb.ToString();
                String tempName    = origName;
                bool   addedPrefix = false;
                if (tempName.Length > Path.MaxPath)
                {
                    tempName    = PathInternal.EnsureExtendedPrefix(tempName);
                    addedPrefix = true;
                }
                sb.Capacity = m_capacity;
                sb.Length   = 0;
                int r = Interop.mincore.GetLongPathName(tempName, sb, m_capacity);

                if (r == 0)
                {
                    // Note: GetLongPathName will return ERROR_INVALID_FUNCTION on a
                    // path like \\.\PHYSICALDEVICE0 - some device driver doesn't
                    // support GetLongPathName on that string.  This behavior is
                    // by design, according to the Core File Services team.
                    // We also get ERROR_NOT_ENOUGH_QUOTA in SQL_CLR_STRESS runs
                    // intermittently on paths like D:\DOCUME~1\user\LOCALS~1\Temp\

                    // We do not need to call GetLongPathName if we know it will fail becasue the path does not exist:
                    int lastErr = Marshal.GetLastWin32Error();
                    if (Interop.mincore.Errors.ERROR_FILE_NOT_FOUND == lastErr || Interop.mincore.Errors.ERROR_PATH_NOT_FOUND == lastErr)
                    {
                        doNotTryExpandShortFileName = true;
                    }

                    sb.Length = 0;
                    sb.Append(origName);
                    return(false);
                }

                if (addedPrefix)
                {
                    r -= 4;
                    sb = PathInternal.RemoveExtendedPrefix(sb);
                }

                // If success, the return buffer length does not account for the terminating null character.
                // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character.
                // If failure, the return buffer length is zero
                if (r >= m_maxPath)
                {
                    throw new PathTooLongException(SR.IO_PathTooLong);
                }

                Length = sb.Length;
                return(true);
            }
        }
Exemple #8
0
        private unsafe static void InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj)
        {
#if FEATURE_MACL
            DirectorySecurity dirSecurity = (DirectorySecurity)dirSecurityObj;
#endif // FEATURE_MACL

            int length = fullPath.Length;

            // We need to trim the trailing slash or the code will try to create 2 directories of the same name.
            if (length >= 2 && Path.IsDirectorySeparator(fullPath[length - 1]))
            {
                length--;
            }

            int lengthRoot = LongPath.GetRootLength(fullPath);

            // For UNC paths that are only // or ///
            if (length == 2 && Path.IsDirectorySeparator(fullPath[1]))
            {
                throw new IOException(Environment.GetResourceString("IO.IO_CannotCreateDirectory", path));
            }

            List <string> stackDir = new List <string>();

            // Attempt to figure out which directories don't exist, and only
            // create the ones we need.  Note that InternalExists may fail due
            // to Win32 ACL's preventing us from seeing a directory, and this
            // isn't threadsafe.

            bool somepathexists = false;

            if (length > lengthRoot)
            { // Special case root (fullpath = X:\\)
                int i = length - 1;
                while (i >= lengthRoot && !somepathexists)
                {
                    String dir = fullPath.Substring(0, i + 1);

                    if (!InternalExists(dir)) // Create only the ones missing
                    {
                        stackDir.Add(dir);
                    }
                    else
                    {
                        somepathexists = true;
                    }

                    while (i > lengthRoot && fullPath[i] != Path.DirectorySeparatorChar && fullPath[i] != Path.AltDirectorySeparatorChar)
                    {
                        i--;
                    }
                    i--;
                }
            }

            int count = stackDir.Count;

            if (stackDir.Count != 0
#if FEATURE_CAS_POLICY
                // All demands in full trust domains are no-ops, so skip
                //
                // The full path went through validity checks by being passed through FileIOPermissions already.
                // As a sub string of the full path can't fail the checks if the full path passes.
                && !CodeAccessSecurityEngine.QuickCheckForAllDemands()
#endif
                )
            {
                String[] securityList = new String[stackDir.Count];
                stackDir.CopyTo(securityList, 0);
                for (int j = 0; j < securityList.Length; j++)
                {
                    securityList[j] += "\\."; // leaf will never have a slash at the end
                }
                // Security check for all directories not present only.
#if !FEATURE_PAL && FEATURE_MACL
                AccessControlActions control = (dirSecurity == null) ? AccessControlActions.None : AccessControlActions.Change;
                FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, control, securityList, false, false);
#else
                FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, securityList, false, false);
#endif
            }

            // If we were passed a DirectorySecurity, convert it to a security
            // descriptor and set it in he call to CreateDirectory.
            Win32Native.SECURITY_ATTRIBUTES secAttrs = null;
#if FEATURE_MACL
            if (dirSecurity != null)
            {
                secAttrs         = new Win32Native.SECURITY_ATTRIBUTES();
                secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);

                // For ACL's, get the security descriptor from the FileSecurity.
                byte[] sd           = dirSecurity.GetSecurityDescriptorBinaryForm();
                byte * bytesOnStack = stackalloc byte[sd.Length];
                Buffer.Memcpy(bytesOnStack, 0, sd, 0, sd.Length);
                secAttrs.pSecurityDescriptor = bytesOnStack;
            }
#endif

            bool   r           = true;
            int    firstError  = 0;
            String errorString = path;
            // If all the security checks succeeded create all the directories
            while (stackDir.Count > 0)
            {
                String name = stackDir[stackDir.Count - 1];
                stackDir.RemoveAt(stackDir.Count - 1);

                if (name.Length >= Path.MaxLongPath)
                {
                    throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
                }

                r = Win32Native.CreateDirectory(PathInternal.EnsureExtendedPrefix(name), secAttrs);
                if (!r && (firstError == 0))
                {
                    int currentError = Marshal.GetLastWin32Error();
                    // While we tried to avoid creating directories that don't
                    // exist above, there are at least two cases that will
                    // cause us to see ERROR_ALREADY_EXISTS here.  InternalExists
                    // can fail because we didn't have permission to the
                    // directory.  Secondly, another thread or process could
                    // create the directory between the time we check and the
                    // time we try using the directory.  Thirdly, it could
                    // fail because the target does exist, but is a file.
                    if (currentError != Win32Native.ERROR_ALREADY_EXISTS)
                    {
                        firstError = currentError;
                    }
                    else
                    {
                        // If there's a file in this directory's place, or if we have ERROR_ACCESS_DENIED when checking if the directory already exists throw.
                        if (LongPathFile.InternalExists(name) || (!InternalExists(name, out currentError) && currentError == Win32Native.ERROR_ACCESS_DENIED))
                        {
                            firstError = currentError;
                            // Give the user a nice error message, but don't leak path information.
                            try
                            {
                                FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true), false, false);
                                errorString = name;
                            }
                            catch (SecurityException) { }
                        }
                    }
                }
            }

            // We need this check to mask OS differences
            // Handle CreateDirectory("X:\\foo") when X: doesn't exist. Similarly for n/w paths.
            if ((count == 0) && !somepathexists)
            {
                String root = InternalGetDirectoryRoot(fullPath);
                if (!InternalExists(root))
                {
                    // Extract the root from the passed in path again for security.
                    __Error.WinIOError(Win32Native.ERROR_PATH_NOT_FOUND, InternalGetDirectoryRoot(path));
                }
                return;
            }

            // Only throw an exception if creating the exact directory we
            // wanted failed to work correctly.
            if (!r && (firstError != 0))
            {
                __Error.WinIOError(firstError, errorString);
            }
        }
 internal static string EnsureExtendedPrefixIfNeeded(string path)
 {
     return(path != null && (path.Length >= 260 || PathInternal.EndsWithPeriodOrSpace(path)) ? PathInternal.EnsureExtendedPrefix(path) : path);
 }