/// <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)); }
// 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(); } } }