// Tries to refresh the lstat cache (_fileCache). // This method should not throw. Instead, we store the results, and we will throw when the user attempts to access any of the properties when there was a failure internal void RefreshCaches(ReadOnlySpan <char> path) { path = Path.TrimEndingDirectorySeparator(path); #if !TARGET_BROWSER _isReadOnlyCache = -1; #endif int rv = Interop.Sys.LStat(path, out _fileCache); if (rv < 0) { Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); if (errorInfo.Error == Interop.Error.ENOENT || // A component of the path does not exist, or path is an empty string errorInfo.Error == Interop.Error.ENOTDIR) // A component of the path prefix of path is not a directory { _state = InitializedNotExists; } else { Debug.Assert(errorInfo.RawErrno > 0); // Expect a positive integer _state = errorInfo.RawErrno; // Initialized with error. } return; } // Check if the main path is a directory, or a link to a directory. int fileType = _fileCache.Mode & Interop.Sys.FileTypes.S_IFMT; bool isDirectory = fileType == Interop.Sys.FileTypes.S_IFDIR || (fileType == Interop.Sys.FileTypes.S_IFLNK && Interop.Sys.Stat(path, out Interop.Sys.FileStatus target) == 0 && (target.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR); _state = isDirectory ? InitializedExistsDir : InitializedExistsFile; }
/// <summary>Wrapper for getpwuid_r.</summary> /// <param name="buf">The scratch buffer to pass into getpwuid_r.</param> /// <param name="bufLen">The length of <paramref name="buf"/>.</param> /// <param name="path">The resulting path; null if the user didn't have an entry.</param> /// <returns>true if the call was successful (path may still be null); false is a larger buffer is needed.</returns> private static unsafe bool TryGetHomeDirectoryFromPasswd(byte* buf, int bufLen, out string path) { // Call getpwuid_r to get the passwd struct Interop.Sys.Passwd passwd; int error = Interop.Sys.GetPwUidR(Interop.Sys.GetEUid(), out passwd, buf, bufLen); // If the call succeeds, give back the home directory path retrieved if (error == 0) { Debug.Assert(passwd.HomeDirectory != null); path = Marshal.PtrToStringAnsi((IntPtr)passwd.HomeDirectory); return true; } // If the current user's entry could not be found, give back null // path, but still return true as false indicates the buffer was // too small. if (error == -1) { path = null; return true; } var errorInfo = new Interop.ErrorInfo(error); // If the call failed because the buffer was too small, return false to // indicate the caller should try again with a larger buffer. if (errorInfo.Error == Interop.Error.ERANGE) { path = null; return false; } // Otherwise, fail. throw new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno); }
private void EnsureStatInitialized() { if (_fileStatusInitialized == -1) { Refresh(); } if (_fileStatusInitialized != 0) { int errno = _fileStatusInitialized; _fileStatusInitialized = -1; var errorInfo = new Interop.ErrorInfo(errno); // Windows distinguishes between whether the directory or the file isn't found, // and throws a different exception in these cases. We attempt to approximate that // here; there is a race condition here, where something could change between // when the error occurs and our checks, but it's the best we can do, and the // worst case in such a race condition (which could occur if the file system is // being manipulated concurrently with these checks) is that we throw a // FileNotFoundException instead of DirectoryNotFoundexception. // directoryError is true only if a FileNotExists error was provided and the parent // directory of the file represented by _fullPath is nonexistent bool directoryError = (errorInfo.Error == Interop.Error.ENOENT && !Directory.Exists(Path.GetDirectoryName(PathHelpers.TrimEndingDirectorySeparator(FullPath)))); // The destFile's path is invalid throw Interop.GetExceptionForIoErrno(errorInfo, FullPath, directoryError); } }