File: PhysicalDirectoryInfo.cs
Web Access
Project: src\src\libraries\Microsoft.Extensions.FileProviders.Physical\src\Microsoft.Extensions.FileProviders.Physical.csproj (Microsoft.Extensions.FileProviders.Physical)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
 
namespace Microsoft.Extensions.FileProviders.Physical
{
    /// <summary>
    /// Represents a directory on a physical file system.
    /// </summary>
    public class PhysicalDirectoryInfo : IFileInfo, IDirectoryContents
    {
        private readonly DirectoryInfo _info;
        private IEnumerable<IFileInfo>? _entries;
        private readonly ExclusionFilters _filters;
 
        /// <summary>
        /// Initializes an instance of <see cref="PhysicalDirectoryInfo"/> that wraps an instance of <see cref="System.IO.DirectoryInfo"/>.
        /// </summary>
        /// <param name="info">The directory to represent.</param>
        public PhysicalDirectoryInfo(DirectoryInfo info)
        {
            _info = info;
        }
 
        internal PhysicalDirectoryInfo(DirectoryInfo info, ExclusionFilters filters)
        {
            _info = info;
            _filters = filters;
        }
 
        /// <inheritdoc />
        public bool Exists => _info.Exists;
 
        /// <summary>
        /// Gets a value that's always -1.
        /// </summary>
        public long Length => -1;
 
        /// <inheritdoc />
        public string PhysicalPath => _info.FullName;
 
        /// <inheritdoc />
        public string Name => _info.Name;
 
        /// <summary>
        /// Gets the time when the directory was last written to.
        /// </summary>
        public DateTimeOffset LastModified => _info.LastWriteTimeUtc;
 
        /// <summary>
        /// Gets a value that's always <see langword="true"/>.
        /// </summary>
        public bool IsDirectory => true;
 
        /// <summary>
        /// Always throws an exception because read streams are not support on directories.
        /// </summary>
        /// <exception cref="InvalidOperationException">In all cases.</exception>
        /// <returns>Never returns.</returns>
        public Stream CreateReadStream()
        {
            throw new InvalidOperationException(SR.CannotCreateStream);
        }
 
        /// <inheritdoc/>
        public IEnumerator<IFileInfo> GetEnumerator()
        {
            EnsureInitialized();
            return _entries.GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            EnsureInitialized();
            return _entries.GetEnumerator();
        }
 
        [MemberNotNull(nameof(_entries))]
        private void EnsureInitialized()
        {
            try
            {
                _entries = _info
                    .EnumerateFileSystemInfos()
                    .Where(info => !FileSystemInfoHelper.IsExcluded(info, _filters))
                    .Select<FileSystemInfo, IFileInfo>(info => info switch
                    {
                        FileInfo file => new PhysicalFileInfo(file),
                        DirectoryInfo dir => new PhysicalDirectoryInfo(dir),
                        // shouldn't happen unless BCL introduces new implementation of base type
                        _ => throw new InvalidOperationException(SR.UnexpectedFileSystemInfo)
                    });
            }
            catch (Exception ex) when (ex is DirectoryNotFoundException or IOException)
            {
                _entries = Enumerable.Empty<IFileInfo>();
            }
        }
    }
}