/// <summary>
        /// Encapsulates a find operation.
        /// </summary>
        /// <param name="directory">The directory to search in.</param>
        /// <param name="options">Enumeration options to use.</param>
        public FileSystemEnumerator(string directory, EnumerationOptions options = null)
        {
            _originalRootDirectory = directory ?? throw new ArgumentNullException(nameof(directory));
            _rootDirectory         = Path.GetFullPath(directory).TrimEnd(Path.DirectorySeparatorChar);
            _options = options ?? EnumerationOptions.Default;

            // We need to initialize the directory handle up front to ensure
            // we immediately throw IO exceptions for missing directory/etc.
            _directoryHandle = CreateDirectoryHandle(_rootDirectory);
            if (_directoryHandle == null)
            {
                _lastEntryFound = true;
            }

            _currentPath = _rootDirectory;

            try
            {
                _pathBuffer = ArrayPool <char> .Shared.Rent(StandardBufferSize);

                int size = Interop.Sys.ReadBufferSize;
                _entryBuffer = size > 0 ? ArrayPool <byte> .Shared.Rent(size) : null;
            }
            catch
            {
                // Close the directory handle right away if we fail to allocate
                CloseDirectoryHandle();
                throw;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Get the next directory entry for the given handle. **Note** the actual memory used may be allocated
        /// by the OS and will be freed when the handle is closed. As such, the handle lifespan MUST be kept tightly
        /// controlled. The DirectoryEntry name cannot be accessed after the handle is closed.
        ///
        /// Call <see cref="ReadBufferSize"/> to see what size buffer to allocate.
        /// </summary>
        internal static int ReadDir(SafeDirectoryHandle dir, Span <byte> buffer, ref DirectoryEntry entry)
        {
            // The calling pattern for ReadDir is described in src/Native/Unix/System.Native/pal_io.cpp|.h
            Debug.Assert(buffer.Length >= ReadBufferSize, "should have a big enough buffer for the raw data");

            // ReadBufferSize is zero when the native implementation does not support reading into a buffer.
            return(ReadDirR(dir.DangerousGetHandle(), ref MemoryMarshal.GetReference(buffer), ReadBufferSize, ref entry));
        }
Beispiel #3
0
        // The calling pattern for ReadDir is described in src/Native/System.Native/pal_readdir.cpp
        internal static int ReadDir(SafeDirectoryHandle dir, out DirectoryEntry outputEntry)
        {
            unsafe
            {
                // To reduce strcpys, alloc a buffer here and get the result from OS, then copy it over for the caller.
                byte *buffer = stackalloc byte[s_direntSize];
                InternalDirectoryEntry temp;
                int ret = ReadDirR(dir, buffer, s_direntSize, out temp);
                outputEntry = ret == 0 ?
                              new DirectoryEntry()
                {
                    InodeName = GetDirectoryEntryName(temp), InodeType = temp.InodeType
                } :
                default(DirectoryEntry);

                return(ret);
            }
        }
        private SafeDirectoryHandle CreateDirectoryHandle(string path)
        {
            // TODO: https://github.com/dotnet/corefx/issues/26715
            // - Use IntPtr handle directly
            SafeDirectoryHandle handle = Interop.Sys.OpenDir(path);

            if (handle.IsInvalid)
            {
                Interop.ErrorInfo info = Interop.Sys.GetLastErrorInfo();
                if ((_options.IgnoreInaccessible && IsAccessError(info.RawErrno)) ||
                    ContinueOnError(info.RawErrno))
                {
                    return(null);
                }
                throw Interop.GetExceptionForIoErrno(info, path, isDirectory: true);
            }
            return(handle);
        }
        // The calling pattern for ReadDir is described in src/Native/System.Native/pal_readdir.cpp
        internal static int ReadDir(SafeDirectoryHandle dir, out DirectoryEntry outputEntry)
        {
            bool addedRef = false;

            try
            {
                // We avoid a native string copy into InternalDirectoryEntry.
                // - If the platform suppors reading into a buffer, the data is read directly into the buffer. The
                //   data can be read as long as the buffer is valid.
                // - If the platform does not support reading into a buffer, the information returned in
                //   InternalDirectoryEntry points to native memory owned by the SafeDirectoryHandle. The data is only
                //   valid until the next call to CloseDir/ReadDir. We extend the reference until we have copied all data
                //   to ensure it does not become invalid by a CloseDir; and we copy the data so our caller does not
                //   use the native memory held by the SafeDirectoryHandle.
                dir.DangerousAddRef(ref addedRef);

                unsafe
                {
                    // s_readBufferSize is zero when the native implementation does not support reading into a buffer.
                    byte *buffer = stackalloc byte[s_readBufferSize];
                    InternalDirectoryEntry temp;
                    int ret = ReadDirR(dir.DangerousGetHandle(), buffer, s_readBufferSize, out temp);
                    // We copy data into DirectoryEntry to ensure there are no dangling references.
                    outputEntry = ret == 0 ?
                                  new DirectoryEntry()
                    {
                        InodeName = GetDirectoryEntryName(temp), InodeType = temp.InodeType
                    } :
                    default(DirectoryEntry);

                    return(ret);
                }
            }
            finally
            {
                if (addedRef)
                {
                    dir.DangerousRelease();
                }
            }
        }
Beispiel #6
0
 private static unsafe extern int ReadDirR(SafeDirectoryHandle dir, byte *buffer, int bufferSize, out InternalDirectoryEntry outputEntry);
 private void CloseDirectoryHandle()
 {
     _directoryHandle?.Dispose();
     _directoryHandle = null;
 }
 private void DequeueNextDirectory()
 {
     _currentPath     = _pending.Dequeue();
     _directoryHandle = CreateDirectoryHandle(_currentPath);
 }