Exemple #1
0
        public static void MoveDirectory(string sourceFullPath, string destFullPath)
        {
            // Windows doesn't care if you try and copy a file via "MoveDirectory"...
            if (FileExists(sourceFullPath))
            {
                // ... but it doesn't like the source to have a trailing slash ...

                // On Windows we end up with ERROR_INVALID_NAME, which is
                // "The filename, directory name, or volume label syntax is incorrect."
                //
                // This surfaces as a IOException, if we let it go beyond here it would
                // give DirectoryNotFound.

                if (Path.EndsInDirectorySeparator(sourceFullPath))
                {
                    throw new IOException(SR.Format(SR.IO_PathNotFound_Path, sourceFullPath));
                }

                // ... but it doesn't care if the destination has a trailing separator.
                destFullPath = Path.TrimEndingDirectorySeparator(destFullPath);
            }

            if (FileExists(destFullPath))
            {
                // Some Unix distros will overwrite the destination file if it already exists.
                // Throwing IOException to match Windows behavior.
                throw new IOException(SR.Format(SR.IO_AlreadyExists_Name, destFullPath));
            }

            if (Interop.Sys.Rename(sourceFullPath, destFullPath) < 0)
            {
                Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
                switch (errorInfo.Error)
                {
                case Interop.Error.EACCES:     // match Win32 exception
                    throw new IOException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, sourceFullPath), errorInfo.RawErrno);

                default:
                    throw Interop.GetExceptionForIoErrno(errorInfo, sourceFullPath, isDirectory: true);
                }
            }
        }
Exemple #2
0
        public static void CreateDirectory(string fullPath)
        {
            // NOTE: This logic is primarily just carried forward from Win32FileSystem.CreateDirectory.

            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.EndsInDirectorySeparator(fullPath))
            {
                length--;
            }

            // For paths that are only // or ///
            if (length == 2 && PathInternal.IsDirectorySeparator(fullPath[1]))
            {
                throw new IOException(SR.Format(SR.IO_CannotCreateDirectory, fullPath));
            }

            // We can save a bunch of work if the directory we want to create already exists.
            if (DirectoryExists(fullPath))
            {
                return;
            }

            // Attempt to figure out which directories don't exist, and only create the ones we need.
            bool           somepathexists = false;
            Stack <string> stackDir       = new Stack <string>();
            int            lengthRoot     = PathInternal.GetRootLength(fullPath);

            if (length > lengthRoot)
            {
                int i = length - 1;
                while (i >= lengthRoot && !somepathexists)
                {
                    if (!DirectoryExists(fullPath.AsSpan(0, i + 1))) // Create only the ones missing
                    {
                        stackDir.Push(fullPath.Substring(0, i + 1));
                    }
                    else
                    {
                        somepathexists = true;
                    }

                    while (i > lengthRoot && !PathInternal.IsDirectorySeparator(fullPath[i]))
                    {
                        i--;
                    }
                    i--;
                }
            }

            int count = stackDir.Count;

            if (count == 0 && !somepathexists)
            {
                ReadOnlySpan <char> root = Path.GetPathRoot(fullPath.AsSpan());
                if (!DirectoryExists(root))
                {
                    throw Interop.GetExceptionForIoErrno(Interop.Error.ENOENT.Info(), fullPath, isDirectory: true);
                }
                return;
            }

            // Create all the directories
            int result = 0;

            Interop.ErrorInfo firstError  = default(Interop.ErrorInfo);
            string            errorString = fullPath;

            while (stackDir.Count > 0)
            {
                string name = stackDir.Pop();

                // The mkdir command uses 0777 by default (it'll be AND'd with the process umask internally).
                // We do the same.
                result = Interop.Sys.MkDir(name, (int)Interop.Sys.Permissions.Mask);
                if (result < 0 && firstError.Error == 0)
                {
                    Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();

                    // While we tried to avoid creating directories that don't
                    // exist above, there are a few cases that can fail, e.g.
                    // a race condition where another process or thread creates
                    // the directory first, or there's a file at the location.
                    if (errorInfo.Error != Interop.Error.EEXIST)
                    {
                        firstError = errorInfo;
                    }
                    else if (FileExists(name) || (!DirectoryExists(name, out errorInfo) && errorInfo.Error == Interop.Error.EACCES))
                    {
                        // 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.
                        firstError  = errorInfo;
                        errorString = name;
                    }
                }
            }

            // Only throw an exception if creating the exact directory we wanted failed to work correctly.
            if (result < 0 && firstError.Error != 0)
            {
                throw Interop.GetExceptionForIoErrno(firstError, errorString, isDirectory: true);
            }
        }
Exemple #3
0
 internal static string EnsureTrailingSeparator(string path)
 => Path.EndsInDirectorySeparator(path.AsSpan()) ? path : path + DirectorySeparatorCharAsString;