1   package org.metricshub.winrm;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  import java.util.Objects;
24  import java.util.Optional;
25  import java.util.concurrent.TimeoutException;
26  import org.metricshub.winrm.exceptions.WindowsRemoteException;
27  import org.metricshub.winrm.exceptions.WqlQuerySyntaxException;
28  
29  public class WindowsTempShare {
30  
31  	
32  	private final String shareName;
33  
34  	
35  	private final String uncSharePath;
36  
37  	
38  	private final String remotePath;
39  
40  	
41  	private final WindowsRemoteExecutor windowsRemoteExecutor;
42  
43  	
44  
45  
46  
47  
48  
49  
50  
51  	public WindowsTempShare(
52  		final WindowsRemoteExecutor windowsRemoteExecutor,
53  		final String shareNameOrUnc,
54  		final String remotePath
55  	) {
56  		Utils.checkNonNull(windowsRemoteExecutor, "windowsRemoteExecutor");
57  		Utils.checkNonNull(shareNameOrUnc, "shareNameOrUnc");
58  
59  		if (shareNameOrUnc.startsWith("\\\\")) {
60  			this.uncSharePath = shareNameOrUnc;
61  			final String[] uncElements = shareNameOrUnc.split("\\\\");
62  			this.shareName = uncElements[3];
63  		} else {
64  			this.uncSharePath = buildUncPath(windowsRemoteExecutor.getHostname(), shareNameOrUnc);
65  			this.shareName = shareNameOrUnc;
66  		}
67  
68  		this.remotePath = remotePath;
69  		this.windowsRemoteExecutor = windowsRemoteExecutor;
70  	}
71  
72  	
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  	public static WindowsTempShare getOrCreateShare(
85  		final WindowsRemoteExecutor windowsRemoteExecutor,
86  		final long timeout,
87  		final ShareRemoteDirectoryConsumer<WindowsRemoteExecutor, String, String, Long> shareRemoteDirectory
88  	) throws TimeoutException, WindowsRemoteException {
89  		Utils.checkNonNull(windowsRemoteExecutor, "windowsRemoteExecutor");
90  		Utils.checkArgumentNotZeroOrNegative(timeout, "timeout");
91  		Utils.checkNonNull(shareRemoteDirectory, "shareRemoteDirectory");
92  
93  		final long start = Utils.getCurrentTimeMillis();
94  
95  		
96  		
97  
98  		
99  		final Optional<WindowsTempShare> clusterShare = getClusterShare(
100 			windowsRemoteExecutor,
101 			TimeoutHelper.getRemainingTime(timeout, start, "No time left to check for cluster share"),
102 			start
103 		);
104 
105 		if (clusterShare.isPresent()) {
106 			return clusterShare.get();
107 		}
108 
109 		
110 		final String shareName = buildShareName();
111 		final Optional<WindowsTempShare> share = getShare(
112 			windowsRemoteExecutor,
113 			shareName,
114 			TimeoutHelper.getRemainingTime(timeout, start, "No time left to get a normal temporary share")
115 		);
116 		if (share.isPresent()) {
117 			return share.get();
118 		}
119 
120 		return createTempShare(
121 			windowsRemoteExecutor,
122 			shareName,
123 			TimeoutHelper.getRemainingTime(timeout, start, "No time left to create the temporary share"),
124 			shareRemoteDirectory
125 		);
126 	}
127 
128 	
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 	public static String getWindowsDirectory(final WindowsRemoteExecutor windowsRemoteExecutor, final long timeout)
144 		throws WindowsRemoteException, TimeoutException {
145 		Utils.checkNonNull(windowsRemoteExecutor, "windowsRemoteExecutor");
146 		Utils.checkArgumentNotZeroOrNegative(timeout, "timeout");
147 
148 		try {
149 			
150 			return windowsRemoteExecutor
151 				.executeWql("SELECT WindowsDirectory FROM Win32_OperatingSystem", timeout)
152 				.stream()
153 				.limit(1)
154 				.map(row -> (String) row.get("WindowsDirectory"))
155 				.filter(Objects::nonNull)
156 				.findFirst()
157 				.orElseThrow(() ->
158 					new WindowsRemoteException(
159 						String.format("Couldn't identify the Windows root directory on %s.", windowsRemoteExecutor.getHostname())
160 					)
161 				);
162 		} catch (final WqlQuerySyntaxException e) {
163 			throw new WindowsRemoteException(e); 
164 		}
165 	}
166 
167 	
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 	public static void createRemoteDirectory(
179 		final WindowsRemoteExecutor windowsRemoteExecutor,
180 		final String remotePath,
181 		final long timeout,
182 		final long start
183 	) throws WindowsRemoteException, TimeoutException {
184 		Utils.checkNonNull(windowsRemoteExecutor, "windowsRemoteExecutor");
185 
186 		windowsRemoteExecutor.executeCommand(buildCreateRemoteDirectoryCommand(remotePath), null, null, timeout);
187 	}
188 
189 	
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 	static String buildUncPath(final String hostname, final String share) {
200 		Utils.checkNonNull(hostname, "hostname");
201 
202 		return hostname.contains(":")
203 			? String.format("\\\\%s.ipv6-literal.net\\%s", hostname.replace(":", "-").replace("%", "s"), share)
204 			: String.format("\\\\%s\\%s", hostname, share);
205 	}
206 
207 	
208 
209 
210 
211 
212 
213 
214 	static String buildCreateRemoteDirectoryCommand(final String remotePath) {
215 		Utils.checkNonBlank(remotePath, "remotePath");
216 
217 		return String.format("CMD.EXE /C IF NOT EXIST \"%s\" MKDIR %s", remotePath, remotePath);
218 	}
219 
220 	
221 
222 
223 
224 
225 	static String buildPathOnCluster(final String path) {
226 		Utils.checkNonNull(path, "path");
227 
228 		return String.format("%s\\Temp\\SEN_TempFor_%s", path, Utils.getComputerName());
229 	}
230 
231 	
232 
233 
234 
235 
236 
237 
238 
239 	static String buildRemotePath(final String folder, final String shareName) {
240 		Utils.checkNonNull(folder, "folder");
241 		Utils.checkNonBlank(shareName, "shareName");
242 
243 		return String.format("%s\\Temp\\%s", folder, shareName);
244 	}
245 
246 	
247 
248 
249 
250 
251 	static String buildShareName() {
252 		return String.format("SEN_ShareFor_%s$", Utils.getComputerName());
253 	}
254 
255 	
256 
257 
258 
259 
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 	static Optional<WindowsTempShare> getClusterShare(
270 		final WindowsRemoteExecutor windowsRemoteExecutor,
271 		final long timeout,
272 		final long start
273 	) throws TimeoutException, WindowsRemoteException {
274 		try {
275 			final Optional<WindowsTempShare> clusterShare = windowsRemoteExecutor
276 				.executeWql(
277 					"SELECT Name,Path FROM Win32_ClusterShare WHERE " +
278 					"ServerName <> '*' AND (Type = 2147483648 OR Type = 3221225472) AND Name LIKE '%\\\\_$'",
279 					timeout
280 				)
281 				.stream()
282 				.limit(1)
283 				.map(row -> 
284 					new WindowsTempShare(
285 						windowsRemoteExecutor,
286 						buildPathOnCluster((String) row.get("Name")),
287 						buildPathOnCluster((String) row.get("Path"))
288 					)
289 				)
290 				.findFirst();
291 
292 			if (clusterShare.isPresent()) {
293 				
294 				createRemoteDirectory(windowsRemoteExecutor, clusterShare.get().getRemotePath(), timeout, start);
295 			}
296 
297 			return clusterShare;
298 		} catch (final WqlQuerySyntaxException e) {
299 			throw new WindowsRemoteException(e); 
300 		}
301 	}
302 
303 	
304 
305 
306 
307 
308 
309 
310 
311 
312 
313 
314 
315 	static Optional<WindowsTempShare> getShare(
316 		final WindowsRemoteExecutor windowsRemoteExecutor,
317 		final String shareName,
318 		final long timeout
319 	) throws TimeoutException, WindowsRemoteException {
320 		try {
321 			return windowsRemoteExecutor
322 				.executeWql(String.format("SELECT Name,Path FROM Win32_Share WHERE Name = '%s'", shareName), timeout)
323 				.stream()
324 				.limit(1)
325 				.map(row -> new WindowsTempShare(windowsRemoteExecutor, (String) row.get("Name"), (String) row.get("Path")))
326 				.findFirst();
327 		} catch (final WqlQuerySyntaxException e) {
328 			throw new WindowsRemoteException(e); 
329 		}
330 	}
331 
332 	
333 
334 
335 
336 
337 
338 
339 
340 
341 
342 
343 
344 
345 	static WindowsTempShare createTempShare(
346 		final WindowsRemoteExecutor windowsRemoteExecutor,
347 		final String shareName,
348 		final long timeout,
349 		final ShareRemoteDirectoryConsumer<WindowsRemoteExecutor, String, String, Long> shareRemoteDirectory
350 	) throws WindowsRemoteException, TimeoutException {
351 		final long start = Utils.getCurrentTimeMillis();
352 
353 		
354 		final String folder = getWindowsDirectory(windowsRemoteExecutor, timeout);
355 
356 		
357 		final String remotePath = buildRemotePath(folder, shareName);
358 		createRemoteDirectory(
359 			windowsRemoteExecutor,
360 			remotePath,
361 			TimeoutHelper.getRemainingTime(timeout, start, "No time left to create the temporary directory"),
362 			start
363 		);
364 
365 		
366 		shareRemoteDirectory.apply(windowsRemoteExecutor, remotePath, shareName, timeout);
367 
368 		return new WindowsTempShare(windowsRemoteExecutor, shareName, remotePath);
369 	}
370 
371 	
372 	public String getShareName() {
373 		return shareName;
374 	}
375 
376 	
377 	public String getUncSharePath() {
378 		return uncSharePath;
379 	}
380 
381 	
382 	public String getRemotePath() {
383 		return remotePath;
384 	}
385 
386 	
387 	public WindowsRemoteExecutor getWindowsRemoteExecutor() {
388 		return windowsRemoteExecutor;
389 	}
390 }