Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 468 lines (392 sloc) 13.741 kB
094b07d @candera Initial add.
candera authored
1 /*
93cda4e @candera Updated copyright date to 2011.
candera authored
2 Copyright (c) 2011 Wangdera Corporation (hobocopy@wangdera.com)
094b07d @candera Initial add.
candera authored
3
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the
6 "Software"), to deal in the Software without restriction, including
7 without limitation the rights to use, copy, modify, merge, publish,
8 distribute, sublicense, and/or sell copies of the Software, and to
9 permit persons to whom the Software is furnished to do so, subject to
10 the following conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #pragma once
25
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
26 using namespace std;
27
28 #include "CHoboCopyException.h"
29
094b07d @candera Initial add.
candera authored
30 class Utilities
31 {
32 public:
33 //static LPCTSTR AllocateString(CString& s)
34 //{
35 // int length = s.GetLength();
36 // LPTSTR sz = new TCHAR[length + 1];
37 // s.CopyChars(sz, length, s.GetBuffer(), length);
38 // sz[length] = TEXT('\0');
39 // return sz;
40 //}
41 static bool AreEqual(LPCTSTR wsz1, LPCTSTR wsz2)
42 {
43 CString s1(wsz1);
44 CString s2(wsz2);
45 return (s1.Compare(wsz2) == 0);
46 }
47 static void CombinePath(LPCTSTR wszPath1, LPCTSTR wszPath2, CString& output)
48 {
49 output.Empty();
50 output.Append(wszPath1);
51
52 if (output.GetLength() > 0)
53 {
54 if (!EndsWith(wszPath1, MAX_PATH, TEXT('\\')))
55 {
56 output.Append(TEXT("\\"));
57 }
58 }
59
60 output.Append(wszPath2);
61 }
62
63 static LPCSTR ConvertToMultibyteString(LPCTSTR s)
64 {
65 CString s2(s);
66 LPSTR mbBuffer = new CHAR[s2.GetLength() + 1];
67 #ifdef _UNICODE
68 int result = ::WideCharToMultiByte(CP_OEMCP, 0, s2, s2.GetLength(), mbBuffer, s2.GetLength(), NULL, NULL);
69
70 if (result == 0)
71 {
72 return NULL;
73 }
74
75 return mbBuffer;
76 #else
77 return NULL;
78 #endif
79 }
80
adeb5fe @candera Fixed problem with recursively creating UNC directories. Closes #16.
candera authored
81 /* Test cases:
82 \\server\share\path\to\dir
83 C:\path\to\dir
84 C:\ - does nothing
85 \\server\share - does nothing
86 \path\to\dir - use current drive
87 */
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
88 static void CreateDirectory(LPCTSTR directory)
89 {
90 vector<CString> pathComponents;
91 CString path(directory);
92 GetPathComponents(path, pathComponents);
93
94 CString pathToCreate;
adeb5fe @candera Fixed problem with recursively creating UNC directories. Closes #16.
candera authored
95 unsigned int initialIndex = 0;
96 bool isUNC = path.Left(2) == _T("\\\\");
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
97
adeb5fe @candera Fixed problem with recursively creating UNC directories. Closes #16.
candera authored
98 if (isUNC)
99 {
100 initialIndex = 2;
101 pathToCreate.Append(__T("\\\\"));
102 pathToCreate.Append(pathComponents[0]);
103 pathToCreate.AppendChar(__T('\\'));
104 pathToCreate.Append(pathComponents[1]);
105 pathToCreate.AppendChar(__T('\\'));
106 }
107
108 for (unsigned int iComponent = initialIndex; iComponent < pathComponents.size(); ++iComponent)
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
109 {
110 pathToCreate.Append(pathComponents[iComponent]);
111 pathToCreate.AppendChar(TEXT('\\'));
112
113 if (!DirectoryExists(pathToCreate))
114 {
d927159 @candera Handle long directory names. Fixes #25.
candera authored
115 CString fixedPath(pathToCreate);
116 FixLongFilenames(fixedPath);
117 BOOL bWorked = ::CreateDirectory(fixedPath, NULL);
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
118
119 if (!bWorked)
319dbd4 @candera Consolidated directory creation code. Fixes #4.
candera authored
120 {
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
121 DWORD error = ::GetLastError();
122 CString errorMessage;
123 FormatErrorMessage(error, errorMessage);
124 CString message;
d927159 @candera Handle long directory names. Fixes #25.
candera authored
125 message.AppendFormat(TEXT("Failure creating directory %s (as %s) - %s"), pathToCreate, fixedPath, errorMessage);
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
126 throw new CHoboCopyException(message);
127 }
128 }
129 }
130 }
094b07d @candera Initial add.
candera authored
131 static bool DirectoryExists(LPCTSTR directory)
132 {
d927159 @candera Handle long directory names. Fixes #25.
candera authored
133 CString fixedPath(directory);
134 FixLongFilenames(fixedPath);
135
136 WIN32_FILE_ATTRIBUTE_DATA attributes;
137 BOOL bWorked = ::GetFileAttributesEx(fixedPath, GetFileExInfoStandard, &attributes);
094b07d @candera Initial add.
candera authored
138
139 if (!bWorked)
140 {
141 DWORD error = ::GetLastError();
142
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
143 if (error == 2 || error == 3)
094b07d @candera Initial add.
candera authored
144 {
145 return false;
146 }
147
148 CString errorMessage;
149 Utilities::FormatErrorMessage(error, errorMessage);
150 CString message;
d927159 @candera Handle long directory names. Fixes #25.
candera authored
151 message.AppendFormat(TEXT("Unable to determine if directory %s (as %s) exists. Error was %s."),
152 directory, fixedPath, errorMessage);
094b07d @candera Initial add.
candera authored
153 throw new CHoboCopyException(message);
154 }
155
156 if ((attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
157 {
158 return attributes.dwFileAttributes != -1;
159 }
160
161 return false;
162 }
163
164 static bool EndsWith(LPCTSTR wsz, size_t maxLength, TCHAR wchar)
165 {
166 CString s(wsz);
167
168 int length = s.GetLength();
169
170 if (length == 0)
171 {
172 return FALSE;
173 }
174
175 if (s.GetAt(length - 1) == wchar)
176 {
177 return TRUE;
178 }
179
180 return FALSE;
181 }
182 static void FixLongFilenames(CString& path)
183 {
184 // If it's a UNC path (i.e. starts with \\server), change it to
185 // \\?\UNC\server\path\to\file
186 if (Utilities::StartsWith(path, TEXT("\\\\")))
187 {
188 if (!Utilities::StartsWith(path, TEXT("\\\\?\\")))
189 {
190 path.Delete(0, 2);
191 path.Insert(0, TEXT("\\\\?\\UNC\\"));
192 }
193 }
194 // Otherwise, change it to \\?\X:\path\to\file
195 else
196 {
197 if (!Utilities::StartsWith(path, TEXT("\\\\?\\")))
198 {
199 path.Insert(0, TEXT("\\\\?\\"));
200 }
201 }
202 }
203 static void FormatDateTime(LPSYSTEMTIME utcTime, LPCTSTR separator, bool formatAsLocal, CString& output)
204 {
205 SYSTEMTIME displayTime;
206 if (formatAsLocal)
207 {
208 if (::SystemTimeToTzSpecificLocalTime(NULL, utcTime, &displayTime) == 0)
209 {
210 DWORD error = ::GetLastError();
211 CString errorMessage;
212 Utilities::FormatErrorMessage(error, errorMessage);
213 CString message;
214 message.AppendFormat(TEXT("Unable to convert UTC time to local time. Error was %s."),
215 errorMessage);
216 throw new CHoboCopyException(message);
217 }
218 }
219 else
220 {
221 displayTime = *utcTime;
222 }
223
224 TCHAR datepart[11];
225 int result = ::GetDateFormat(LOCALE_USER_DEFAULT, 0, &displayTime,
226 TEXT("yyyy'-'MM'-'dd"), datepart, 11);
227
228 if (result != 0)
229 {
230 output.Append(datepart);
231 output.Append(separator);
232
233 TCHAR timepart[9];
234 result = ::GetTimeFormat(LOCALE_USER_DEFAULT, 0, &displayTime,
235 TEXT("HH':'mm':'ss"), timepart, 9);
236
237 if (result != 0)
238 {
239 output.Append(timepart);
240 }
241 else
242 {
243 DWORD error = ::GetLastError();
244 CString errorMessage;
245 Utilities::FormatErrorMessage(error, errorMessage);
246 output.Empty();
247 output.AppendFormat(TEXT("Unable to retrieve time. Error was %s."), errorMessage);
248 }
249 }
250 else
251 {
252 DWORD error = ::GetLastError();
253 CString errorMessage;
254 Utilities::FormatErrorMessage(error, errorMessage);
255 output.Empty();
256 output.AppendFormat(TEXT("Unable to retrieve date. Error was %s."), errorMessage);
257 }
258
259
260 }
261
262
263 static void FormatErrorMessage(DWORD error, CString& output)
264 {
265 output.Empty();
266
267 LPVOID lpMsgBuf;
268
269 DWORD worked = ::FormatMessage(
270 FORMAT_MESSAGE_ALLOCATE_BUFFER |
271 FORMAT_MESSAGE_FROM_SYSTEM,
272 NULL,
273 error,
274 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
275 (LPTSTR) &lpMsgBuf,
276 0, NULL );
277
278 if (worked > 0)
279 {
280 CString message;
281 message.Append((LPTSTR) lpMsgBuf);
282
283 ::LocalFree(lpMsgBuf);
284
285 output.Format(TEXT("%s (Error number %d)"), message, error);
286 }
287 else
288 {
289 output.Format(TEXT("Error %d"), error);
290 }
291
292 }
293 static void Free(LPCSTR x)
294 {
295 delete x;
296 }
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
297
298 static void GetFileName(CString& path, CString& filename)
299 {
300 filename.Empty();
301
302 vector<CString> pathComponents;
303 GetPathComponents(path, pathComponents);
304
305 if (pathComponents.size() > 0)
306 {
307 filename = pathComponents[pathComponents.size() - 1];
308 }
309 }
310
094b07d @candera Initial add.
candera authored
311 static LONGLONG GetFileSize(LPCTSTR path)
312 {
313 HANDLE hFile = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
314
315 if (hFile == INVALID_HANDLE_VALUE)
316 {
317 DWORD error = ::GetLastError();
318
319 CString errorMessage;
320 Utilities::FormatErrorMessage(error, errorMessage);
321 CString message;
322 message.AppendFormat(TEXT("Unable to open file %s to retrieve file size. Error was %s."),
323 path, errorMessage);
324 throw new CHoboCopyException(message);
325 }
326
327 LARGE_INTEGER size;
328 BOOL bWorked = ::GetFileSizeEx(hFile, &size);
329
330 if (!bWorked)
331 {
332 DWORD error = ::GetLastError();
333
334 ::CloseHandle(hFile);
335
336 CString errorMessage;
337 Utilities::FormatErrorMessage(error, errorMessage);
338 CString message;
339 message.AppendFormat(TEXT("Unable to retrieve file size for file %s. Error was %s."),
340 path, errorMessage);
341 throw new CHoboCopyException(message);
342 }
343
344 ::CloseHandle(hFile);
345
346 return size.QuadPart;
347 }
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
348
349 static void GetPathComponents(CString& path, vector<CString>& pathComponents)
350 {
351 pathComponents.clear();
352
353 bool done = false;
354 int start = 0;
355 while (!done)
356 {
357 CString component = path.Tokenize(TEXT("\\"), start);
358
359 if (start == -1)
360 {
361 done = true;
362 }
363 else
364 {
365 pathComponents.push_back(component);
366 }
367 }
368
369 }
370
371 static bool IsMatch(CString& input, CString& pattern)
372 {
e0c5f80 @candera * Fixed problem with inability to read file size blowing up program
candera authored
373 // Short-circuit common cases
374 if (pattern.Compare(TEXT("*")) == 0)
375 {
376 return true;
377 }
378
379 if (pattern.Compare(TEXT("*.*")) == 0)
380 {
381 return true;
382
383 }
384
5c1dec1 @candera * Added support for Vista: HoboCopy will now prompt to run as an admi…
candera authored
385 int nStars = 0;
386 for (int iChar = 0; iChar < pattern.GetLength(); ++iChar)
387 {
388 if (pattern[iChar] == TEXT('*'))
389 {
390 ++nStars;
391 }
392 }
393
394 if (nStars > 1)
395 {
396 CString message;
397 message.AppendFormat(TEXT("The pattern %s is illegal: only a single wildcard is supported."), pattern);
398 throw new CHoboCopyException(message);
399 }
400
401 // No wildcard is present
402 if (nStars == 0)
403 {
404 return input.CompareNoCase(pattern) == 0;
405 }
406
407 // A wildcard is present
408 int index = pattern.Find(TEXT("*"));
409
410 if (index > 0)
411 {
412 if (index > input.GetLength())
413 {
414 return false;
415 }
416
417 CString prefix = pattern.Left(index);
418 CString inputStart = input.Left(index);
419
420 if (prefix.CompareNoCase(inputStart) != 0)
421 {
422 return false;
423 }
424 }
425
426 if (index < input.GetLength() - 1)
427 {
428 CString suffix = pattern.Mid(index + 1);
429 CString inputEnd = input.Right(suffix.GetLength());
430
431 if (suffix.CompareNoCase(inputEnd) != 0)
432 {
433 return false;
434 }
435 }
436
437 return true;
438
439 }
094b07d @candera Initial add.
candera authored
440 //static void FreeString(LPCTSTR s)
441 //{
442 // delete s;
443 //}
444 static void ParseDateTime(LPCTSTR szDateTime, LPCTSTR separator, LPSYSTEMTIME pTime)
445 {
446 int separatorLength = CString(separator).GetLength();
447
448 CString dateTimeString(szDateTime);
449 pTime->wYear = _ttoi(dateTimeString.Mid(0, 4));
450 pTime->wMonth = _ttoi(dateTimeString.Mid(5, 2));
451 pTime->wDay = _ttoi(dateTimeString.Mid(8, 2));
452 pTime->wHour = _ttoi(dateTimeString.Mid(10 + separatorLength, 2));
453 pTime->wMinute = _ttoi(dateTimeString.Mid(13 + separatorLength, 2));
454 pTime->wSecond = _ttoi(dateTimeString.Mid(16 + separatorLength, 2));
455 pTime->wMilliseconds = 0;
456 }
457 static bool StartsWith(CString& s1, LPCTSTR s2)
458 {
459 CString s2a(s2);
460 if (s1.Left(s2a.GetLength()).Compare(s2a) == 0)
461 {
462 return true;
463 }
464
465 return false;
466 }
467
468 };
Something went wrong with that request. Please try again.