1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5
6//
7// This header provides general directory-related file system services.
8
9#ifndef _clr_fs_Dir_h_
10#define _clr_fs_Dir_h_
11
12#include "clrtypes.h"
13#include "clr/str.h"
14#include "strsafe.h"
15
16#ifndef countof
17 #define countof(x) (sizeof(x) / sizeof(x[0]))
18#endif // !countof
19
20namespace clr
21{
22 namespace fs
23 {
24 class Dir
25 {
26 public:
27 static inline bool Exists(
28 LPCWSTR wzDirPath)
29 {
30 DWORD attrs = WszGetFileAttributes(wzDirPath);
31 return (attrs != INVALID_FILE_ATTRIBUTES) && (attrs & FILE_ATTRIBUTE_DIRECTORY);
32 }
33
34 //-----------------------------------------------------------------------------------------
35 // Creates new directory indicated by wzDirPath.
36 //
37 // Returns:
38 // S_OK - on success directory creation
39 // S_FALSE - when directory previously existed
40 // HR(ERROR_PATH_NOT_FOUND) - when creation of dir fails.
41 static inline HRESULT Create(
42 LPCWSTR wzDirPath)
43 {
44 HRESULT hr = S_OK;
45
46 if (!WszCreateDirectory(wzDirPath, nullptr))
47 {
48 hr = HRESULT_FROM_GetLastError();
49 if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
50 {
51 hr = S_FALSE;
52 }
53 }
54 return hr;
55 }
56
57 //-----------------------------------------------------------------------------------------
58 // Creates the specified directory and all required subdirectories. wzDirPath will be
59 // temporarily modified in the process.
60 //
61 // Returns:
62 // S_OK - on success directory creation
63 // S_FALSE - when directory previously existed
64 // HR(ERROR_PATH_NOT_FOUND) - when creation of any dir fails.
65 static inline HRESULT CreateRecursively(
66 __inout_z LPWSTR wzDirPath,
67 size_t cchDirPath = 0)
68 {
69 HRESULT hr = S_OK;
70
71 if (wzDirPath == nullptr)
72 {
73 return E_POINTER;
74 }
75
76 if (cchDirPath == 0)
77 {
78 cchDirPath = wcslen(wzDirPath);
79 }
80
81 // Try to create the path. If it fails, assume that's because the parent folder does
82 // not exist. Try to create the parent then re-attempt.
83 WCHAR chOrig = wzDirPath[cchDirPath];
84 hr = Create(wzDirPath);
85 if (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
86 {
87 for (WCHAR* pCurCh = wzDirPath + cchDirPath - 1; pCurCh != wzDirPath; --pCurCh)
88 {
89 if (*pCurCh == W('\\') || *pCurCh == W('\0'))
90 {
91 WCHAR chOrig = *pCurCh;
92 *pCurCh = W('\0');
93 IfFailRet(CreateRecursively(wzDirPath, pCurCh - wzDirPath));
94 *pCurCh = chOrig;
95 break;
96 }
97 }
98 IfFailRet(Create(wzDirPath));
99 }
100
101 return hr;
102 }
103
104 //-----------------------------------------------------------------------------------------
105 // Creates the specified directory and all required subdirectories.
106 static inline HRESULT CreateRecursively(
107 LPCWSTR wzDirPath)
108 {
109 HRESULT hr = S_OK;
110
111 if (wzDirPath == nullptr)
112 {
113 return E_POINTER;
114 }
115
116 // Make a writable copy of wzDirPath
117 size_t cchDirPath = wcslen(wzDirPath);
118 CQuickWSTR wzBuffer;
119 IfFailRet(wzBuffer.ReSizeNoThrow(cchDirPath + 1));
120 wcscpy_s(wzBuffer.Ptr(), wzBuffer.Size(), wzDirPath);
121 IfFailRet(CreateRecursively(wzBuffer.Ptr(), cchDirPath));
122
123 return hr;
124 }
125 };
126 }
127}
128
129#endif // _clr_fs_Dir_h_
130