// ----------------------------- // ---- PAL layer ends here ---- // ----------------------------- internal static Interop.libc.OpenFlags TranslateFlags(PipeDirection direction, PipeOptions options, HandleInheritability inheritability) { // Translate direction Interop.libc.OpenFlags flags = direction == PipeDirection.InOut ? Interop.libc.OpenFlags.O_RDWR : direction == PipeDirection.Out ? Interop.libc.OpenFlags.O_WRONLY : Interop.libc.OpenFlags.O_RDONLY; // Translate options if ((options & PipeOptions.WriteThrough) != 0) { flags |= Interop.libc.OpenFlags.O_SYNC; } // Translate inheritability. if ((inheritability & HandleInheritability.Inheritable) == 0) { flags |= Interop.libc.OpenFlags.O_CLOEXEC; } // PipeOptions.Asynchronous is ignored, at least for now. Asynchronous processing // is handling just by queueing a work item to do the work synchronously on a pool thread. return(flags); }
private static FileStream CreateSharedBackingObject( Interop.libc.MemoryMappedProtections protections, long capacity) { // The POSIX shared memory object name must begin with '/'. After that we just want something short and unique. string mapName = "/corefx_map_" + Guid.NewGuid().ToString("N"); // Determine the flags to use when creating the shared memory object Interop.libc.OpenFlags flags = (protections & Interop.libc.MemoryMappedProtections.PROT_WRITE) != 0 ? Interop.libc.OpenFlags.O_RDWR : Interop.libc.OpenFlags.O_RDONLY; flags |= Interop.libc.OpenFlags.O_CREAT | Interop.libc.OpenFlags.O_EXCL; // CreateNew // Determine the permissions with which to create the file Interop.libc.Permissions perms = default(Interop.libc.Permissions); if ((protections & Interop.libc.MemoryMappedProtections.PROT_READ) != 0) { perms |= Interop.libc.Permissions.S_IRUSR; } if ((protections & Interop.libc.MemoryMappedProtections.PROT_WRITE) != 0) { perms |= Interop.libc.Permissions.S_IWUSR; } if ((protections & Interop.libc.MemoryMappedProtections.PROT_EXEC) != 0) { perms |= Interop.libc.Permissions.S_IXUSR; } // Create the shared memory object. int fd; Interop.CheckIo(fd = Interop.libc.shm_open(mapName, flags, (int)perms), mapName); SafeFileHandle fileHandle = new SafeFileHandle((IntPtr)fd, ownsHandle: true); try { // Unlink the shared memory object immediatley so that it'll go away once all handles // to it are closed (as with opened then unlinked files, it'll remain usable via // the open handles even though it's unlinked and can't be opened anew via its name). Interop.CheckIo(Interop.libc.shm_unlink(mapName)); // Give it the right capacity. We do this directly with ftruncate rather // than via FileStream.SetLength after the FileStream is created because, on some systems, // lseek fails on shared memory objects, causing the FileStream to think it's unseekable, // causing it to preemptively throw from SetLength. Interop.CheckIo(Interop.libc.ftruncate(fd, capacity)); // Wrap the file descriptor in a stream and return it. return(new FileStream(fileHandle, TranslateProtectionsToFileAccess(protections))); } catch { fileHandle.Dispose(); throw; } }
/// <summary>Initializes a stream for reading or writing a Unix file.</summary> /// <param name="path">The path to the file.</param> /// <param name="mode">How the file should be opened.</param> /// <param name="access">Whether the file will be read, written, or both.</param> /// <param name="share">What other access to the file should be allowed. This is currently ignored.</param> /// <param name="bufferSize">The size of the buffer to use when buffering.</param> /// <param name="options">Additional options for working with the file.</param> internal UnixFileStream(String path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent) : base(parent) { // FileStream performs most of the general argument validation. We can assume here that the arguments // are all checked and consistent (e.g. non-null-or-empty path; valid enums in mode, access, share, and options; etc.) // Store the arguments _path = path; _access = access; _mode = mode; _options = options; _bufferLength = bufferSize; _useAsyncIO = (options & FileOptions.Asynchronous) != 0; // Translate the arguments into arguments for an open call Interop.libc.OpenFlags openFlags = PreOpenConfigurationFromOptions(mode, access, options); // FileShare currently ignored Interop.libc.Permissions openPermissions = Interop.libc.Permissions.S_IRWXU; // creator has read/write/execute permissions; no permissions for anyone else // Open the file and store the safe handle. Subsequent code in this method expects the safe handle to be initialized. _fileHandle = SafeFileHandle.Open(path, openFlags, (int)openPermissions); _fileHandle.IsAsync = _useAsyncIO; // Lock the file if requested via FileShare. This is only advisory locking. FileShare.None implies an exclusive // lock on the file and all other modes use a shared lock. While this is not as granular as Windows, not mandatory, // and not atomic with file opening, it's better than nothing. try { Interop.libc.LockOperations lockOperation = (share == FileShare.None) ? Interop.libc.LockOperations.LOCK_EX : Interop.libc.LockOperations.LOCK_SH; SysCall <Interop.libc.LockOperations, int>((fd, op, _) => Interop.libc.flock(fd, op), lockOperation | Interop.libc.LockOperations.LOCK_NB); } catch { _fileHandle.Dispose(); throw; } // Support additional options after the file has been opened. // These provide hints around how the file will be accessed. Interop.libc.Advice fadv = _options == FileOptions.RandomAccess ? Interop.libc.Advice.POSIX_FADV_RANDOM : _options == FileOptions.SequentialScan ? Interop.libc.Advice.POSIX_FADV_SEQUENTIAL : 0; if (fadv != 0) { SysCall <Interop.libc.Advice, int>((fd, advice, _) => Interop.libc.posix_fadvise(fd, 0, 0, advice), fadv); } // Jump to the end of the file if opened as Append. if (_mode == FileMode.Append) { _appendStart = SeekCore(0, SeekOrigin.End); } }
/// <summary>Opens the specified file with the requested flags and mode.</summary> /// <param name="path">The path to the file.</param> /// <param name="flags">The flags with which to open the file.</param> /// <param name="mode">The mode for opening the file.</param> /// <returns>A SafeFileHandle for the opened file.</returns> internal static SafeFileHandle Open(string path, Interop.libc.OpenFlags flags, int mode) { Debug.Assert(path != null); // SafeFileHandle wraps a file descriptor rather than a pointer, and a file descriptor is always 4 bytes // rather than being pointer sized, which means we can't utilize the runtime's ability to marshal safe handles. // Ideally this would be a constrained execution region, but we don't have access to PrepareConstrainedRegions. // We still use a finally block to house the code that opens the file and stores the handle in hopes // of making it as non-interruptable as possible. The SafeFileHandle is also allocated first to avoid // the allocation after getting the file descriptor but before storing it. SafeFileHandle handle = new SafeFileHandle(ownsHandle: true); try { } finally { // If we fail to open the file due to a path not existing, we need to know whether to blame // the file itself or its directory. If we're creating the file, then we blame the directory, // otherwise we blame the file. bool enoentDueToDirectory = (flags & Interop.libc.OpenFlags.O_CREAT) != 0; // Open the file. int fd; while (Interop.CheckIo(fd = Interop.libc.open(path, flags, mode), path, isDirectory: enoentDueToDirectory, errorRewriter: errno => (errno == Interop.Errors.EISDIR) ? Interop.Errors.EACCES : errno)) { ; } Debug.Assert(fd >= 0); handle.SetHandle((IntPtr)fd); Debug.Assert(!handle.IsInvalid); // Make sure it's not a directory; we do this after opening it once we have a file descriptor // to avoid race conditions. Interop.libcoreclrpal.fileinfo buf; if (Interop.libcoreclrpal.GetFileInformationFromFd(fd, out buf) != 0) { handle.Dispose(); throw Interop.GetExceptionForIoErrno(Marshal.GetLastWin32Error(), path); } if ((buf.mode & Interop.libcoreclrpal.FileTypes.S_IFMT) == Interop.libcoreclrpal.FileTypes.S_IFDIR) { handle.Dispose(); throw Interop.GetExceptionForIoErrno(Interop.Errors.EACCES, path, isDirectory: true); } } return(handle); }
private static FileStream CreateSharedBackingObject( Interop.libc.MemoryMappedProtections protections, long capacity, out string mapName, out SafeMemoryMappedFileHandle.FileStreamSource fileStreamSource) { // The POSIX shared memory object name must begin with '/'. After that we just want something short and unique. mapName = "/" + MemoryMapObjectFilePrefix + Guid.NewGuid().ToString("N"); fileStreamSource = SafeMemoryMappedFileHandle.FileStreamSource.ManufacturedSharedMemory; // Determine the flags to use when creating the shared memory object Interop.libc.OpenFlags flags = (protections & Interop.libc.MemoryMappedProtections.PROT_WRITE) != 0 ? Interop.libc.OpenFlags.O_RDWR : Interop.libc.OpenFlags.O_RDONLY; flags |= Interop.libc.OpenFlags.O_CREAT | Interop.libc.OpenFlags.O_EXCL; // CreateNew // Determine the permissions with which to create the file Interop.libc.Permissions perms = default(Interop.libc.Permissions); if ((protections & Interop.libc.MemoryMappedProtections.PROT_READ) != 0) { perms |= Interop.libc.Permissions.S_IRUSR; } if ((protections & Interop.libc.MemoryMappedProtections.PROT_WRITE) != 0) { perms |= Interop.libc.Permissions.S_IWUSR; } if ((protections & Interop.libc.MemoryMappedProtections.PROT_EXEC) != 0) { perms |= Interop.libc.Permissions.S_IXUSR; } // Create the shared memory object. Then enlarge it to the requested capacity. int fd; Interop.CheckIo(fd = Interop.libc.shm_open(mapName, flags, (int)perms), mapName); SafeFileHandle fileHandle = new SafeFileHandle((IntPtr)fd, ownsHandle: true); // Wrap the handle in a stream and return it. var fs = new FileStream(fileHandle, TranslateProtectionsToFileAccess(protections)); fs.SetLength(capacity); return(fs); }
/// <summary>Opens the specified file with the requested flags and mode.</summary> /// <param name="path">The path to the file.</param> /// <param name="flags">The flags with which to open the file.</param> /// <param name="mode">The mode for opening the file.</param> /// <returns>A SafeFileHandle for the opened file.</returns> internal static SafeFileHandle Open(string path, Interop.libc.OpenFlags flags, int mode) { // SafeFileHandle wraps a file descriptor rather than a pointer, and a file descriptor is always 4 bytes // rather than being pointer sized, which means we can't utilize the runtime's ability to marshal safe handles. // Ideally this would be a constrained execution region, but we don't have access to PrepareConstrainedRegions. // We still use a finally block to house the code that opens the file and stores the handle in hopes // of making it as non-interruptable as possible. The SafeFileHandle is also allocated first to avoid // the allocation after getting the file descriptor but before storing it. SafeFileHandle handle = new SafeFileHandle(ownsHandle: true); try { } finally { int fd; while (Interop.CheckIo(fd = Interop.libc.open64(path, flags, mode))) { ; } Contract.Assert(fd >= 0); handle.SetHandle((IntPtr)fd); } return(handle); }
private static SafeFileHandle CreateNewSharedMemoryObject( string mapName, Interop.libc.MemoryMappedProtections protections, long capacity) { // Determine the flags to use when creating the shared memory object Interop.libc.OpenFlags flags = (protections & Interop.libc.MemoryMappedProtections.PROT_WRITE) != 0 ? Interop.libc.OpenFlags.O_RDWR : Interop.libc.OpenFlags.O_RDONLY; flags |= Interop.libc.OpenFlags.O_CREAT | Interop.libc.OpenFlags.O_EXCL; // CreateNew // Create the shared memory object int fd; Interop.CheckIo(fd = Interop.libc.shm_open(mapName, flags, (int)Interop.libc.Permissions.S_IRWXU), mapName); SafeFileHandle fileHandle = new SafeFileHandle((IntPtr)fd, ownsHandle: true); // Then enlarge it to the requested capacity bool gotFd = false; fileHandle.DangerousAddRef(ref gotFd); try { while (Interop.CheckIo(Interop.libc.ftruncate((int)fileHandle.DangerousGetHandle(), capacity), mapName)) { ; } } finally { if (gotFd) { fileHandle.DangerousRelease(); } } // Return the fd for the object return(fileHandle); }
/// <summary>Translates the FileMode, FileAccess, and FileOptions values into flags to be passed when opening the file.</summary> /// <param name="mode">The FileMode provided to the stream's constructor.</param> /// <param name="access">The FileAccess provided to the stream's constructor</param> /// <param name="options">The FileOptions provided to the stream's constructor</param> /// <returns>The flags value to be passed to the open system call.</returns> private static Interop.libc.OpenFlags PreOpenConfigurationFromOptions(FileMode mode, FileAccess access, FileOptions options) { // Translate FileMode. Most of the values map cleanly to one or more options for open. Interop.libc.OpenFlags flags = Interop.libc.OpenFlags.O_LARGEFILE; switch (mode) { default: case FileMode.Open: // Open maps to the default behavior for open(...). No flags needed. break; case FileMode.Append: // Append is the same as OpenOrCreate, except that we'll also separately jump to the end later case FileMode.OpenOrCreate: flags |= Interop.libc.OpenFlags.O_CREAT; break; case FileMode.Create: flags |= (Interop.libc.OpenFlags.O_CREAT | Interop.libc.OpenFlags.O_TRUNC); break; case FileMode.CreateNew: flags |= (Interop.libc.OpenFlags.O_CREAT | Interop.libc.OpenFlags.O_EXCL); break; case FileMode.Truncate: flags |= Interop.libc.OpenFlags.O_TRUNC; break; } // Translate FileAccess. All possible values map cleanly to corresponding values for open. switch (access) { case FileAccess.Read: flags |= Interop.libc.OpenFlags.O_RDONLY; break; case FileAccess.ReadWrite: flags |= Interop.libc.OpenFlags.O_RDWR; break; case FileAccess.Write: flags |= Interop.libc.OpenFlags.O_WRONLY; break; } // Translate some FileOptions; some just aren't supported, and others will be handled after calling open. switch (options) { case FileOptions.Asynchronous: // Handled in ctor, setting _useAsync and SafeFileHandle.IsAsync to true case FileOptions.DeleteOnClose: // DeleteOnClose doesn't have a Unix equivalent, but we approximate it in Dispose case FileOptions.Encrypted: // Encrypted does not have an equivalent on Unix and is ignored. case FileOptions.RandomAccess: // Implemented after open via posix_fadvise case FileOptions.SequentialScan: // Implemented after open via posix_fadvise break; case FileOptions.WriteThrough: flags |= Interop.libc.OpenFlags.O_SYNC; break; } return(flags); }