44#pragma once
55
66#include " IDirectoryEnumerationResults.h"
7+ #include " ApiHelper.h"
8+
9+ using namespace System ;
10+ using namespace System ::Globalization;
11+ using namespace System ::IO;
712
813namespace Microsoft {
914namespace Windows {
@@ -18,10 +23,9 @@ namespace ProjFS {
1823public ref class DirectoryEnumerationResults : public IDirectoryEnumerationResults {
1924internal:
2025
21- DirectoryEnumerationResults (PRJ_DIR_ENTRY_BUFFER_HANDLE bufferHandle)
22- {
23- m_dirEntryBufferHandle = bufferHandle;
24- }
26+ DirectoryEnumerationResults (PRJ_DIR_ENTRY_BUFFER_HANDLE bufferHandle, ApiHelper^ apiHelper) :
27+ m_dirEntryBufferHandle (bufferHandle), m_apiHelper(apiHelper)
28+ { }
2529
2630 // Provides access to the native handle to the directory entry buffer.
2731 // Used internally by VirtualizationInstance::CompleteCommand(int, IDirectoryEnumerationResults^).
@@ -139,14 +143,137 @@ public ref class DirectoryEnumerationResults : public IDirectoryEnumerationResul
139143 System::DateTime lastAccessTime,
140144 System::DateTime lastWriteTime,
141145 System::DateTime changeTime) sealed
146+ {
147+ ValidateFileName (fileName);
148+
149+ pin_ptr<const WCHAR> pFileName = PtrToStringChars (fileName);
150+ PRJ_FILE_BASIC_INFO basicInfo = BuildFileBasicInfo (fileSize,
151+ isDirectory,
152+ fileAttributes,
153+ creationTime,
154+ lastAccessTime,
155+ lastWriteTime,
156+ changeTime);
157+
158+ auto hr = ::PrjFillDirEntryBuffer (pFileName,
159+ &basicInfo,
160+ m_dirEntryBufferHandle);
161+
162+ if FAILED (hr)
163+ {
164+ return false ;
165+ }
166+
167+ return true ;
168+ }
169+
170+ // / <summary>Adds one entry to a directory enumeration result.</summary>
171+ // / <remarks>
172+ // / <para>
173+ // / In its implementation of a <c>GetDirectoryEnumerationCallback</c> delegate the provider
174+ // / calls this method for each matching file or directory in the enumeration.
175+ // / </para>
176+ // / <para>
177+ // / If this method returns <c>false</c>, the provider returns <see cref="HResult::Ok"/> and waits for
178+ // / the next <c>GetDirectoryEnumerationCallback</c>. Then it resumes filling the enumeration with
179+ // / the entry it was trying to add when it got <c>false</c>.
180+ // / </para>
181+ // / <para>
182+ // / If the method returns <c>false</c> for the first file or directory in the enumeration, the
183+ // / provider returns <see cref="HResult::InsufficientBuffer"/> from the <c>GetDirectoryEnumerationCallback</c>
184+ // / method.
185+ // / </para>
186+ // / </remarks>
187+ // / <param name="fileName">The name of the file or directory.</param>
188+ // / <param name="fileSize">The size of the file.</param>
189+ // / <param name="isDirectory"><c>true</c> if this item is a directory, <c>false</c> if it is a file.</param>
190+ // / <param name="fileAttributes">The file attributes.</param>
191+ // / <param name="creationTime">The time the file was created.</param>
192+ // / <param name="lastAccessTime">The time the file was last accessed.</param>
193+ // / <param name="lastWriteTime">The time the file was last written to.</param>
194+ // / <param name="changeTime">The time the file was last changed.</param>
195+ // / <param name="symlinkTargetOrNull">Specifies the symlink target path if the file is a symlink.</param>
196+ // / <returns>
197+ // / <para>
198+ // / <c>true</c> if the entry was successfully added to the enumeration buffer, <c>false</c> otherwise.
199+ // / </para>
200+ // / </returns>
201+ // / <exception cref="System::ArgumentException">
202+ // / <paramref name="fileName"/> is null or empty.
203+ // / </exception>
204+ virtual bool Add (
205+ System::String^ fileName,
206+ long long fileSize,
207+ bool isDirectory,
208+ System::IO::FileAttributes fileAttributes,
209+ System::DateTime creationTime,
210+ System::DateTime lastAccessTime,
211+ System::DateTime lastWriteTime,
212+ System::DateTime changeTime,
213+ System::String^ symlinkTargetOrNull) sealed
214+ {
215+ // This API is supported in Windows 10 version 2004 and above.
216+ if ((symlinkTargetOrNull != nullptr ) &&
217+ (m_apiHelper->SupportedApi < ApiLevel::v2004))
218+ {
219+ throw gcnew NotImplementedException (" PrjFillDirEntryBuffer2 is not supported in this version of Windows." );
220+ }
221+
222+ ValidateFileName (fileName);
223+
224+ pin_ptr<const WCHAR> pFileName = PtrToStringChars (fileName);
225+ PRJ_FILE_BASIC_INFO basicInfo = BuildFileBasicInfo (fileSize,
226+ isDirectory,
227+ fileAttributes,
228+ creationTime,
229+ lastAccessTime,
230+ lastWriteTime,
231+ changeTime);
232+
233+ PRJ_EXTENDED_INFO extendedInfo = {};
234+ if (symlinkTargetOrNull != nullptr )
235+ {
236+ extendedInfo.InfoType = PRJ_EXT_INFO_TYPE_SYMLINK;
237+ pin_ptr<const WCHAR> targetPath = PtrToStringChars (symlinkTargetOrNull);
238+ extendedInfo.Symlink .TargetName = targetPath;
239+ }
240+
241+ HRESULT hr;
242+ hr = m_apiHelper->_PrjFillDirEntryBuffer2 (m_dirEntryBufferHandle,
243+ pFileName,
244+ &basicInfo,
245+ (symlinkTargetOrNull != nullptr ) ? &extendedInfo : nullptr );
246+
247+ if FAILED (hr)
248+ {
249+ return false ;
250+ }
251+
252+ return true ;
253+ }
254+
255+ private:
256+
257+ PRJ_DIR_ENTRY_BUFFER_HANDLE m_dirEntryBufferHandle;
258+ ApiHelper^ m_apiHelper;
259+
260+ void ValidateFileName (System::String^ fileName)
142261 {
143262 if (System::String::IsNullOrEmpty (fileName))
144263 {
145264 throw gcnew System::ArgumentException (System::String::Format (System::Globalization::CultureInfo::InvariantCulture,
146- " fileName cannot be empty." ));
265+ " fileName cannot be empty." ));
147266 }
267+ }
148268
149- pin_ptr<const WCHAR> pFileName = PtrToStringChars (fileName);
269+ PRJ_FILE_BASIC_INFO BuildFileBasicInfo (long long fileSize,
270+ bool isDirectory,
271+ System::IO::FileAttributes fileAttributes,
272+ System::DateTime creationTime,
273+ System::DateTime lastAccessTime,
274+ System::DateTime lastWriteTime,
275+ System::DateTime changeTime)
276+ {
150277 PRJ_FILE_BASIC_INFO basicInfo = { 0 };
151278
152279 if (creationTime != System::DateTime::MinValue)
@@ -173,20 +300,7 @@ public ref class DirectoryEnumerationResults : public IDirectoryEnumerationResul
173300 basicInfo.IsDirectory = isDirectory;
174301 basicInfo.FileSize = fileSize;
175302
176- auto hr = ::PrjFillDirEntryBuffer (pFileName,
177- &basicInfo,
178- m_dirEntryBufferHandle);
179-
180- if FAILED (hr)
181- {
182- return false ;
183- }
184-
185- return true ;
303+ return basicInfo;
186304 }
187-
188- private:
189-
190- PRJ_DIR_ENTRY_BUFFER_HANDLE m_dirEntryBufferHandle;
191305};
192306}}} // namespace Microsoft.Windows.ProjFS
0 commit comments