internal HResult GetPlaceholderInfoCallback(
            int commandId,
            string relativePath,
            uint triggeringProcessId,
            string triggeringProcessImageFileName)
        {
            Log.Information("----> GetPlaceholderInfoCallback [{Path}]", relativePath);
            Log.Information("  Placeholder creation triggered by [{ProcName} {PID}]", triggeringProcessImageFileName, triggeringProcessId);

            HResult           hr       = HResult.Ok;
            ProjectedFileInfo fileInfo = this.GetFileInfoInLayer(relativePath);

            if (fileInfo == null)
            {
                hr = HResult.FileNotFound;
            }
            else
            {
                hr = this.virtualizationInstance.WritePlaceholderInfo(
                    relativePath: Path.Combine(Path.GetDirectoryName(relativePath), fileInfo.Name),
                    creationTime: fileInfo.CreationTime,
                    lastAccessTime: fileInfo.LastAccessTime,
                    lastWriteTime: fileInfo.LastWriteTime,
                    changeTime: fileInfo.ChangeTime,
                    fileAttributes: fileInfo.Attributes,
                    endOfFile: fileInfo.Size,
                    isDirectory: fileInfo.IsDirectory,
                    contentId: new byte[] { 0 },
                    providerId: new byte[] { 1 });
            }

            Log.Information("<---- GetPlaceholderInfoCallback {Result}", hr);
            return(hr);
        }
        private bool FileOrDirectoryExistsInLayer(string layerParentPath, string layerName, out ProjectedFileInfo fileInfo)
        {
            fileInfo = null;

            // Check whether the parent directory exists in the layer.
            DirectoryInfo dirInfo = new DirectoryInfo(layerParentPath);

            if (!dirInfo.Exists)
            {
                return(false);
            }

            // Get the FileSystemInfo for the entry in the layer that matches the name, using ProjFS's
            // name matching rules.
            FileSystemInfo fileSystemInfo =
                dirInfo
                .GetFileSystemInfos()
                .FirstOrDefault(fsInfo => Utils.IsFileNameMatch(fsInfo.Name, layerName));

            if (fileSystemInfo == null)
            {
                return(false);
            }

            bool isDirectory = ((fileSystemInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory);

            fileInfo = new ProjectedFileInfo(
                name: fileSystemInfo.Name,
                size: isDirectory ? 0 : new FileInfo(Path.Combine(layerParentPath, layerName)).Length,
                isDirectory: isDirectory,
                creationTime: fileSystemInfo.CreationTime,
                lastAccessTime: fileSystemInfo.LastAccessTime,
                lastWriteTime: fileSystemInfo.LastWriteTime,
                changeTime: fileSystemInfo.LastWriteTime,
                attributes: fileSystemInfo.Attributes);

            return(true);
        }
        internal HResult GetDirectoryEnumerationCallback(
            int commandId,
            Guid enumerationId,
            string filterFileName,
            bool restartScan,
            IDirectoryEnumerationResults enumResult)
        {
            Log.Information("----> GetDirectoryEnumerationCallback filterFileName [{Filter}]", filterFileName);

            // Find the requested enumeration.  It should have been put there by StartDirectoryEnumeration.
            if (!this.activeEnumerations.TryGetValue(enumerationId, out ActiveEnumeration enumeration))
            {
                return(HResult.InternalError);
            }

            if (restartScan)
            {
                // The caller is restarting the enumeration, so we reset our ActiveEnumeration to the
                // first item that matches filterFileName.  This also saves the value of filterFileName
                // into the ActiveEnumeration, overwriting its previous value.
                enumeration.RestartEnumeration(filterFileName);
            }
            else
            {
                // The caller is continuing a previous enumeration, or this is the first enumeration
                // so our ActiveEnumeration is already at the beginning.  TrySaveFilterString()
                // will save filterFileName if it hasn't already been saved (only if the enumeration
                // is restarting do we need to re-save filterFileName).
                enumeration.TrySaveFilterString(filterFileName);
            }

            bool    entryAdded = false;
            HResult hr         = HResult.Ok;

            while (enumeration.IsCurrentValid)
            {
                ProjectedFileInfo fileInfo = enumeration.Current;

                if (enumResult.Add(
                        fileName: fileInfo.Name,
                        fileSize: fileInfo.Size,
                        isDirectory: fileInfo.IsDirectory,
                        fileAttributes: fileInfo.Attributes,
                        creationTime: fileInfo.CreationTime,
                        lastAccessTime: fileInfo.LastAccessTime,
                        lastWriteTime: fileInfo.LastWriteTime,
                        changeTime: fileInfo.ChangeTime))
                {
                    entryAdded = true;
                    enumeration.MoveNext();
                }
                else
                {
                    if (entryAdded)
                    {
                        hr = HResult.Ok;
                    }
                    else
                    {
                        hr = HResult.InsufficientBuffer;
                    }

                    break;
                }
            }

            Log.Information("<---- GetDirectoryEnumerationCallback {Result}", hr);
            return(hr);
        }