Ejemplo n.º 1
0
        /// <summary>
        /// Returns the full path for find results, based on the initially provided path.
        /// </summary>
        public string ToSpecifiedFullPath()
        {
            // We want to provide the enumerated segment of the path appended to the originally specified path. This is
            // the behavior of the various Directory APIs that return a list of strings.
            //
            // RootDirectory has the final separator trimmed, OriginalRootDirectory does not. Our legacy behavior would
            // effectively account for this by appending subdirectory names as it recursed. As such we need to trim one
            // separator when combining with the relative path (Directory.Slice(RootDirectory.Length)).
            //
            //   Original  =>  Root   => Directory    => FileName => relativePath => Specified
            //   C:\foo        C:\foo    C:\foo          bar         ""              C:\foo\bar
            //   C:\foo\       C:\foo    C:\foo          bar         ""              C:\foo\bar
            //   C:\foo/       C:\foo    C:\foo          bar         ""              C:\foo/bar
            //   C:\foo\\      C:\foo    C:\foo          bar         ""              C:\foo\\bar
            //   C:\foo        C:\foo    C:\foo\bar      jar         "bar"           C:\foo\bar\jar
            //   C:\foo\       C:\foo    C:\foo\bar      jar         "bar"           C:\foo\bar\jar
            //   C:\foo/       C:\foo    C:\foo\bar      jar         "bar"           C:\foo/bar\jar


            // If we're at the top level directory the Directory and RootDirectory will be identical. As there are no
            // trailing slashes in play, once we're in a subdirectory, slicing off the root will leave us with an
            // initial separator. We need to trim that off if it exists, but it isn't needed if the original root
            // didn't have a separator. Join() would handle it if we did trim it, not doing so is an optimization.

            ReadOnlySpan <char> relativePath = Directory.Slice(RootDirectory.Length);

            if (PathInternal.EndsInDirectorySeparator(OriginalRootDirectory) && PathInternal.StartsWithDirectorySeparator(relativePath))
            {
                relativePath = relativePath.Slice(1);
            }

            return(Path.Join(OriginalRootDirectory, relativePath, FileName));
        }
Ejemplo n.º 2
0
        private static string?GetBaseDirectoryCore()
        {
            // Fallback path for hosts that do not set APP_CONTEXT_BASE_DIRECTORY explicitly
            string?directory = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);

            if (directory != null && !PathInternal.EndsInDirectorySeparator(directory))
            {
                directory += Path.DirectorySeparatorChar;
            }
            return(directory);
        }
Ejemplo n.º 3
0
        public void Refresh(ReadOnlySpan <char> path)
        {
            // This should not throw, instead we store the result so that we can throw it
            // when someone actually accesses a property.

            // Use lstat to get the details on the object, without following symlinks.
            // If it is a symlink, then subsequently get details on the target of the symlink,
            // storing those results separately.  We only report failure if the initial
            // lstat fails, as a broken symlink should still report info on exists, attributes, etc.
            _isDirectory = false;
            if (PathInternal.EndsInDirectorySeparator(path))
            {
                path = path.Slice(0, path.Length - 1);
            }
            int result = Interop.Sys.LStat(path, out _fileStatus);

            if (result < 0)
            {
                Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();

                // This should never set the error if the file can't be found.
                // (see the Windows refresh passing returnErrorOnNotFound: false).
                if (errorInfo.Error == Interop.Error.ENOENT ||
                    errorInfo.Error == Interop.Error.ENOTDIR)
                {
                    _fileStatusInitialized = 0;
                    _exists = false;
                }
                else
                {
                    _fileStatusInitialized = errorInfo.RawErrno;
                }
                return;
            }

            _exists      = true;
            _isDirectory = (_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;

            // If we're a symlink, attempt to check the target to see if it is a directory
            if ((_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK &&
                Interop.Sys.Stat(path, out Interop.Sys.FileStatus targetStatus) >= 0)
            {
                _isDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
            }

            _fileStatusInitialized = 0;
        }
Ejemplo n.º 4
0
        public static void CreateDirectory(string fullPath)
        {
            // We can save a bunch of work if the directory we want to create already exists.  This also
            // saves us in the case where sub paths are inaccessible (due to ERROR_ACCESS_DENIED) but the
            // final path is accessible and the directory already exists.  For example, consider trying
            // to create c:\Foo\Bar\Baz, where everything already exists but ACLS prevent access to c:\Foo
            // and c:\Foo\Bar.  In that case, this code will think it needs to create c:\Foo, and c:\Foo\Bar
            // and fail to due so, causing an exception to be thrown.  This is not what we want.
            if (DirectoryExists(fullPath))
            {
                return;
            }

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

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

            bool somepathexists = false;

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

            int lengthRoot = PathInternal.GetRootLength(fullPath.AsSpan());

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

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

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

            int count = stackDir.Count;

            // If we were passed a DirectorySecurity, convert it to a security
            // descriptor and set it in he call to CreateDirectory.
            Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default;

            bool   r           = true;
            int    firstError  = 0;
            string errorString = fullPath;

            // 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);

                r = Interop.Kernel32.CreateDirectory(name, ref 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.  FileExists
                    // 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 != Interop.Errors.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 (FileExists(name) || (!DirectoryExists(name, out currentError) && currentError == Interop.Errors.ERROR_ACCESS_DENIED))
                        {
                            firstError  = currentError;
                            errorString = name;
                        }
                    }
                }
            }

            // We need this check to mask OS differences
            // Handle CreateDirectory("X:\\") when X: doesn't exist. Similarly for n/w paths.
            if ((count == 0) && !somepathexists)
            {
                string root = Directory.InternalGetDirectoryRoot(fullPath);
                if (!DirectoryExists(root))
                {
                    throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_PATH_NOT_FOUND, root);
                }
                return;
            }

            // Only throw an exception if creating the exact directory we
            // wanted failed to work correctly.
            if (!r && (firstError != 0))
            {
                throw Win32Marshal.GetExceptionForWin32Error(firstError, errorString);
            }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Trims the ending directory separator if present.
 /// </summary>
 /// <param name="path"></param>
 internal static ReadOnlySpan <char> TrimEndingDirectorySeparator(ReadOnlySpan <char> path) =>
 PathInternal.EndsInDirectorySeparator(path) ?
 path.Slice(0, path.Length - 1) :
 path;