示例#1
0
        // -----------------------------
        // ---- 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);
        }
示例#2
0
        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;
            }
        }
示例#3
0
        /// <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);
            }
        }
示例#4
0
        /// <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);
        }
示例#5
0
        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);
        }
示例#6
0
        /// <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);
        }
示例#7
0
        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);
        }
示例#8
0
        /// <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);
        }