public override 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 && PathHelpers.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) { string dir = fullPath.Substring(0, i + 1); if (!DirectoryExists(dir)) // Create only the ones missing { stackDir.Push(dir); } else { somepathexists = true; } while (i > lengthRoot && !PathInternal.IsDirectorySeparator(fullPath[i])) { i--; } i--; } } int count = stackDir.Count; if (count == 0 && !somepathexists) { string root = Directory.InternalGetDirectoryRoot(fullPath); 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(); if (name.Length >= MaxDirectoryPath) { throw new PathTooLongException(SR.IO_PathTooLong); } // 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); } }
private async Task <FileStreamBase> OpenAsync(string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) { // When trying to open the root directory, we need to throw an Access Denied if (PathInternal.GetRootLength(fullPath) == fullPath.Length) { throw Win32Marshal.GetExceptionForWin32Error(Interop.mincore.Errors.ERROR_ACCESS_DENIED, fullPath); } // Win32 CreateFile returns ERROR_PATH_NOT_FOUND when given a path that ends with '\' if (PathHelpers.EndsInDirectorySeparator(fullPath)) { throw Win32Marshal.GetExceptionForWin32Error(Interop.mincore.Errors.ERROR_PATH_NOT_FOUND, fullPath); } StorageFile file = null; // FileMode if (mode == FileMode.Open || mode == FileMode.Truncate) { file = await StorageFile.GetFileFromPathAsync(fullPath).TranslateWinRTTask(fullPath); } else { CreationCollisionOption collisionOptions; switch (mode) { case FileMode.Create: collisionOptions = CreationCollisionOption.ReplaceExisting; break; case FileMode.CreateNew: collisionOptions = CreationCollisionOption.FailIfExists; break; case FileMode.Append: case FileMode.OpenOrCreate: default: collisionOptions = CreationCollisionOption.OpenIfExists; break; } string directoryPath, fileName; PathHelpers.SplitDirectoryFile(fullPath, out directoryPath, out fileName); StorageFolder directory = await StorageFolder.GetFolderFromPathAsync(directoryPath).TranslateWinRTTask(directoryPath, isDirectory: true); file = await directory.CreateFileAsync(fileName, collisionOptions).TranslateWinRTTask(fullPath); } // FileAccess: WinRT doesn't support FileAccessMode.Write so we upgrade to ReadWrite FileAccessMode accessMode = ((access & FileAccess.Write) != 0) ? FileAccessMode.ReadWrite : FileAccessMode.Read; // FileShare: cannot translate StorageFile uses a different sharing model (oplocks) that is controlled via FileAccessMode // FileOptions: ignore most values of FileOptions as they are hints and are not supported by WinRT. // FileOptions.Encrypted is not a hint, and not supported by WinRT, but there is precedent for ignoring this (FAT). // FileOptions.DeleteOnClose should result in an UnauthorizedAccessException when // opening a file that can only be read, but we cannot safely reproduce that behavior // in WinRT without actually deleting the file. // Instead the failure will occur in the finalizer for WinRTFileStream and be ignored. // open our stream Stream stream = (await file.OpenAsync(accessMode).TranslateWinRTTask(fullPath)).AsStream(bufferSize); if (mode == FileMode.Append) { // seek to end. stream.Seek(0, SeekOrigin.End); } else if (mode == FileMode.Truncate) { // truncate stream to 0 stream.SetLength(0); } return(new WinRTFileStream(stream, file, access, options, parent)); }