1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
---|
2 | /* ***** BEGIN LICENSE BLOCK ***** |
---|
3 | * Version: NPL 1.1/GPL 2.0/LGPL 2.1 |
---|
4 | * |
---|
5 | * The contents of this file are subject to the Netscape Public License |
---|
6 | * Version 1.1 (the "License"); you may not use this file except in |
---|
7 | * compliance with the License. You may obtain a copy of the License at |
---|
8 | * http://www.mozilla.org/NPL/ |
---|
9 | * |
---|
10 | * Software distributed under the License is distributed on an "AS IS" basis, |
---|
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
---|
12 | * for the specific language governing rights and limitations under the |
---|
13 | * License. |
---|
14 | * |
---|
15 | * The Original Code is mozilla.org code. |
---|
16 | * |
---|
17 | * The Initial Developer of the Original Code is |
---|
18 | * Netscape Communications Corporation. |
---|
19 | * Portions created by the Initial Developer are Copyright (C) 1998 |
---|
20 | * the Initial Developer. All Rights Reserved. |
---|
21 | * |
---|
22 | * Contributor(s): |
---|
23 | * Modified by David.Gardiner@unisa.edu.au |
---|
24 | * |
---|
25 | * |
---|
26 | * Alternatively, the contents of this file may be used under the terms of |
---|
27 | * either the GNU General Public License Version 2 or later (the "GPL"), or |
---|
28 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
---|
29 | * in which case the provisions of the GPL or the LGPL are applicable instead |
---|
30 | * of those above. If you wish to allow use of your version of this file only |
---|
31 | * under the terms of either the GPL or the LGPL, and not to allow others to |
---|
32 | * use your version of this file under the terms of the NPL, indicate your |
---|
33 | * decision by deleting the provisions above and replace them with the notice |
---|
34 | * and other provisions required by the GPL or the LGPL. If you do not delete |
---|
35 | * the provisions above, a recipient may use your version of this file under |
---|
36 | * the terms of any one of the NPL, the GPL or the LGPL. |
---|
37 | * |
---|
38 | * ***** END LICENSE BLOCK ***** */ |
---|
39 | |
---|
40 | #include <windows.h> |
---|
41 | #include <stdio.h> |
---|
42 | #include <stdlib.h> |
---|
43 | #include <string.h> |
---|
44 | #include <direct.h> |
---|
45 | #include <sys/stat.h> |
---|
46 | #include <sys/utime.h> |
---|
47 | #include <io.h> |
---|
48 | #include <fcntl.h> |
---|
49 | |
---|
50 | /* |
---|
51 | Unicode calls are linked at run-time, so that the application can run under |
---|
52 | Windows NT and 95 (which doesn't support the Unicode calls) |
---|
53 | |
---|
54 | The following APIs are linked: |
---|
55 | BackupWrite |
---|
56 | CreateFileW |
---|
57 | GetFullPathNameW |
---|
58 | */ |
---|
59 | |
---|
60 | //static const char *prog; |
---|
61 | |
---|
62 | BOOL insertHashLine = FALSE; |
---|
63 | BOOL trySymlink = FALSE; |
---|
64 | BOOL recurse = FALSE; |
---|
65 | |
---|
66 | typedef WINBASEAPI BOOL (WINAPI* LPFNBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD, BOOL, BOOL, LPVOID *); |
---|
67 | typedef WINBASEAPI HANDLE (WINAPI* LPFNCreateFileW)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); |
---|
68 | typedef WINBASEAPI DWORD (WINAPI* LPFNGetFullPathNameW)(LPCWSTR, DWORD, LPWSTR, LPWSTR *); |
---|
69 | |
---|
70 | // Function pointers (used for NTFS hard links) |
---|
71 | LPFNBackupWrite lpfnDllBackupWrite = NULL; |
---|
72 | LPFNCreateFileW lpfnDllCreateFileW = NULL; |
---|
73 | LPFNGetFullPathNameW lpfnDllGetFullPathNameW = NULL; |
---|
74 | |
---|
75 | // Handle to DLL |
---|
76 | HINSTANCE hDLL = NULL; |
---|
77 | |
---|
78 | /* |
---|
79 | ** Flip any "unix style slashes" into "dos style backslashes" |
---|
80 | */ |
---|
81 | inline void FlipSlashes(char *name) |
---|
82 | { |
---|
83 | for( int i=0; name[i]; i++ ) { |
---|
84 | if( name[i] == '/' ) name[i] = '\\'; |
---|
85 | } |
---|
86 | } |
---|
87 | |
---|
88 | /* |
---|
89 | * Flip any "dos style backslashes" into "unix style slashes" |
---|
90 | */ |
---|
91 | inline void UnflipSlashes(char *name) |
---|
92 | { |
---|
93 | for( int i=0; name[i]; i++ ) { |
---|
94 | if( name[i] == '\\' ) name[i] = '/'; |
---|
95 | } |
---|
96 | } |
---|
97 | |
---|
98 | int MakeDir( char *path ) |
---|
99 | { |
---|
100 | char *cp, *pstr; |
---|
101 | struct stat sb; |
---|
102 | |
---|
103 | pstr = path; |
---|
104 | while( cp = strchr(pstr, '\\') ) { |
---|
105 | *cp = '\0'; |
---|
106 | |
---|
107 | if( !(stat(path, &sb) == 0 && (sb.st_mode & _S_IFDIR) )) { |
---|
108 | /* create the new sub-directory */ |
---|
109 | printf("+++ makecopy: creating directory %s\n", path); |
---|
110 | if( mkdir(path) < 0 ) { |
---|
111 | return -1; |
---|
112 | } |
---|
113 | } /* else sub-directory already exists.... */ |
---|
114 | |
---|
115 | *cp = '\\'; |
---|
116 | pstr = cp+1; |
---|
117 | } |
---|
118 | |
---|
119 | return 0; |
---|
120 | } |
---|
121 | |
---|
122 | /* |
---|
123 | * Display error code and message for last error |
---|
124 | */ |
---|
125 | int ReportError() |
---|
126 | { |
---|
127 | LPVOID lpMsgBuf = NULL; |
---|
128 | |
---|
129 | DWORD err = GetLastError(); |
---|
130 | |
---|
131 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, |
---|
132 | NULL, |
---|
133 | err, |
---|
134 | 0, |
---|
135 | (LPTSTR) &lpMsgBuf, |
---|
136 | 0, |
---|
137 | NULL); |
---|
138 | |
---|
139 | fprintf(stderr, "%u, %s\n", err, (LPCTSTR) lpMsgBuf ) ; |
---|
140 | |
---|
141 | LocalFree( lpMsgBuf ); |
---|
142 | |
---|
143 | return -1; |
---|
144 | } |
---|
145 | |
---|
146 | int ReportError(const char* msg) |
---|
147 | { |
---|
148 | fprintf(stderr, "Error: %s\n", msg); |
---|
149 | return ReportError(); |
---|
150 | } |
---|
151 | |
---|
152 | |
---|
153 | /* |
---|
154 | Creates an NTFS hard link of src at dest. |
---|
155 | NT5 will have a CreateHardLink API which will do the same thing, but a lot simpler |
---|
156 | This is based on the MSDN code sample Q153181 |
---|
157 | |
---|
158 | */ |
---|
159 | BOOL hardSymLink(LPCSTR src, LPCSTR dest) |
---|
160 | { |
---|
161 | WCHAR FileLink[ MAX_PATH + 1 ]; |
---|
162 | WCHAR FileSource[ MAX_PATH + 1 ]; |
---|
163 | WCHAR FileDest[ MAX_PATH + 1 ]; |
---|
164 | LPWSTR FilePart; |
---|
165 | |
---|
166 | WIN32_STREAM_ID StreamId; |
---|
167 | DWORD dwBytesWritten; |
---|
168 | DWORD cbPathLen; |
---|
169 | |
---|
170 | BOOL bSuccess; |
---|
171 | |
---|
172 | // Convert src and dest to Unicode |
---|
173 | if (!MultiByteToWideChar(CP_ACP, 0, src, -1, FileSource, MAX_PATH)) { |
---|
174 | ReportError("Convert to WCHAR (source)"); |
---|
175 | return FALSE; |
---|
176 | } |
---|
177 | |
---|
178 | if (!MultiByteToWideChar(CP_ACP, 0, dest, -1, FileDest, MAX_PATH)) { |
---|
179 | ReportError("Convert to WCHAR (destination)"); |
---|
180 | return FALSE; |
---|
181 | } |
---|
182 | |
---|
183 | // |
---|
184 | // open existing file that we link to |
---|
185 | // |
---|
186 | |
---|
187 | HANDLE hFileSource = lpfnDllCreateFileW( |
---|
188 | FileSource, |
---|
189 | FILE_WRITE_ATTRIBUTES, |
---|
190 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
---|
191 | NULL, // sa |
---|
192 | OPEN_EXISTING, |
---|
193 | 0, |
---|
194 | NULL |
---|
195 | ); |
---|
196 | |
---|
197 | if(hFileSource == INVALID_HANDLE_VALUE) { |
---|
198 | ReportError("CreateFile (source)"); |
---|
199 | return FALSE; |
---|
200 | } |
---|
201 | |
---|
202 | // |
---|
203 | // validate and sanitize supplied link path and use the result |
---|
204 | // the full path MUST be Unicode for BackupWrite |
---|
205 | // |
---|
206 | |
---|
207 | cbPathLen = lpfnDllGetFullPathNameW( FileDest, MAX_PATH, FileLink, &FilePart); |
---|
208 | |
---|
209 | if(cbPathLen == 0) { |
---|
210 | ReportError("GetFullPathName"); |
---|
211 | return FALSE; |
---|
212 | } |
---|
213 | |
---|
214 | cbPathLen = (cbPathLen + 1) * sizeof(WCHAR); // adjust for byte count |
---|
215 | |
---|
216 | // |
---|
217 | // it might also be a good idea to verify the existence of the link, |
---|
218 | // (and possibly bail), as the file specified in FileLink will be |
---|
219 | // overwritten if it already exists |
---|
220 | // |
---|
221 | |
---|
222 | // |
---|
223 | // prepare and write the WIN32_STREAM_ID out |
---|
224 | // |
---|
225 | |
---|
226 | LPVOID lpContext = NULL; |
---|
227 | |
---|
228 | StreamId.dwStreamId = BACKUP_LINK; |
---|
229 | StreamId.dwStreamAttributes = 0; |
---|
230 | StreamId.dwStreamNameSize = 0; |
---|
231 | StreamId.Size.HighPart = 0; |
---|
232 | StreamId.Size.LowPart = cbPathLen; |
---|
233 | |
---|
234 | // |
---|
235 | // compute length of variable size WIN32_STREAM_ID |
---|
236 | // |
---|
237 | |
---|
238 | DWORD StreamHeaderSize = (LPBYTE)&StreamId.cStreamName - (LPBYTE)& |
---|
239 | StreamId+ StreamId.dwStreamNameSize ; |
---|
240 | |
---|
241 | bSuccess = lpfnDllBackupWrite( |
---|
242 | hFileSource, |
---|
243 | (LPBYTE)&StreamId, // buffer to write |
---|
244 | StreamHeaderSize, // number of bytes to write |
---|
245 | &dwBytesWritten, |
---|
246 | FALSE, // don't abort yet |
---|
247 | FALSE, // don't process security |
---|
248 | &lpContext |
---|
249 | ); |
---|
250 | |
---|
251 | if(bSuccess) { |
---|
252 | |
---|
253 | // |
---|
254 | // write out the buffer containing the path |
---|
255 | // |
---|
256 | |
---|
257 | bSuccess = lpfnDllBackupWrite( |
---|
258 | hFileSource, |
---|
259 | (LPBYTE)FileLink, // buffer to write |
---|
260 | cbPathLen, // number of bytes to write |
---|
261 | &dwBytesWritten, |
---|
262 | FALSE, // don't abort yet |
---|
263 | FALSE, // don't process security |
---|
264 | &lpContext |
---|
265 | ); |
---|
266 | |
---|
267 | // |
---|
268 | // free context |
---|
269 | // |
---|
270 | |
---|
271 | lpfnDllBackupWrite( |
---|
272 | hFileSource, |
---|
273 | NULL, // buffer to write |
---|
274 | 0, // number of bytes to write |
---|
275 | &dwBytesWritten, |
---|
276 | TRUE, // abort |
---|
277 | FALSE, // don't process security |
---|
278 | &lpContext |
---|
279 | ); |
---|
280 | } |
---|
281 | |
---|
282 | CloseHandle( hFileSource ); |
---|
283 | |
---|
284 | if(!bSuccess) { |
---|
285 | ReportError("BackupWrite"); |
---|
286 | return FALSE; |
---|
287 | } |
---|
288 | |
---|
289 | return TRUE; |
---|
290 | } |
---|
291 | |
---|
292 | int CopyIfNecessary(char *oldFile, char *newFile) |
---|
293 | { |
---|
294 | struct stat newsb; |
---|
295 | struct stat oldsb; |
---|
296 | |
---|
297 | // Use stat to find file details |
---|
298 | if (stat(oldFile, &oldsb)) { |
---|
299 | return -1; |
---|
300 | } |
---|
301 | |
---|
302 | // skip directories unless recursion flag is set |
---|
303 | if ( oldsb.st_mode & _S_IFDIR ) { |
---|
304 | if (!recurse) { |
---|
305 | printf(" Skipping directory %s\n", oldFile); |
---|
306 | return 0; |
---|
307 | } |
---|
308 | else { |
---|
309 | char *lastDir; |
---|
310 | char *oldFileName; // points to where file name starts in oldFile |
---|
311 | char *newFileName; // points to where file name starts in newFile |
---|
312 | WIN32_FIND_DATA findFileData; |
---|
313 | |
---|
314 | // weed out special "." and ".." directories |
---|
315 | lastDir = strrchr(oldFile, '\\'); |
---|
316 | if ( lastDir ) |
---|
317 | ++lastDir; |
---|
318 | else |
---|
319 | lastDir = oldFile; |
---|
320 | if ( strcmp( lastDir, "." ) == 0 || strcmp( lastDir, ".." ) == 0 ) |
---|
321 | return 0; |
---|
322 | |
---|
323 | // find and process the contents of the directory |
---|
324 | oldFileName = oldFile + strlen(oldFile); |
---|
325 | strcpy(oldFileName, "\\*"); |
---|
326 | ++oldFileName; |
---|
327 | |
---|
328 | newFileName = newFile + strlen(newFile); |
---|
329 | strcpy(newFileName, "\\"); |
---|
330 | ++newFileName; |
---|
331 | |
---|
332 | if( MakeDir(newFile) < 0 ) { |
---|
333 | fprintf(stderr, "\n+++ makecopy: unable to create directory %s\n", newFile); |
---|
334 | return 1; |
---|
335 | } |
---|
336 | |
---|
337 | HANDLE hFindFile = FindFirstFile(oldFile, &findFileData); |
---|
338 | if (hFindFile != INVALID_HANDLE_VALUE) { |
---|
339 | do { |
---|
340 | strcpy(oldFileName, findFileData.cFileName); |
---|
341 | strcpy(newFileName, findFileData.cFileName); |
---|
342 | CopyIfNecessary(oldFile, newFile); |
---|
343 | } while (FindNextFile(hFindFile, &findFileData) != 0); |
---|
344 | } else { |
---|
345 | fprintf(stderr, "\n+++ makecopy: no such file: %s\n", oldFile); |
---|
346 | } |
---|
347 | FindClose(hFindFile); |
---|
348 | } |
---|
349 | // nothing more we can do with a directory |
---|
350 | return 0; |
---|
351 | } |
---|
352 | |
---|
353 | if (!stat(newFile, &newsb)) { |
---|
354 | // If file times are equal, don't copy |
---|
355 | if (newsb.st_mtime == oldsb.st_mtime) { |
---|
356 | #if 0 |
---|
357 | printf("+++ makecopy: %s is up to date\n", newFile); |
---|
358 | #endif |
---|
359 | return 0; |
---|
360 | } |
---|
361 | } |
---|
362 | |
---|
363 | |
---|
364 | char fullPathName[ MAX_PATH + 1 ]; |
---|
365 | LPTSTR filenamePart = NULL; |
---|
366 | |
---|
367 | char buffer[8192]; |
---|
368 | DWORD bytesRead = 0; |
---|
369 | DWORD bytesWritten = 0; |
---|
370 | |
---|
371 | // find out required size |
---|
372 | GetFullPathName(oldFile, MAX_PATH, fullPathName, &filenamePart); |
---|
373 | |
---|
374 | // If we need to insert #line, the copying is a bit involved. |
---|
375 | if (insertHashLine == TRUE) { |
---|
376 | struct _utimbuf utim; |
---|
377 | |
---|
378 | printf(" #Installing %s into %s\n", oldFile, newFile); |
---|
379 | |
---|
380 | utim.actime = oldsb.st_atime; |
---|
381 | utim.modtime = oldsb.st_mtime; // modification time |
---|
382 | |
---|
383 | HANDLE hNewFile = CreateFile(newFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, |
---|
384 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, |
---|
385 | NULL); |
---|
386 | if (hNewFile == INVALID_HANDLE_VALUE) { |
---|
387 | return ReportError("CreateFile"); |
---|
388 | } |
---|
389 | |
---|
390 | HANDLE hOldFile = CreateFile(oldFile, GENERIC_READ, FILE_SHARE_READ, NULL, |
---|
391 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, |
---|
392 | NULL); |
---|
393 | if (hOldFile == INVALID_HANDLE_VALUE) { |
---|
394 | return ReportError("CreateFile"); |
---|
395 | } |
---|
396 | |
---|
397 | // Insert first line. |
---|
398 | sprintf(buffer, "#line 1 \"%s\"\r\n", fullPathName); |
---|
399 | |
---|
400 | // convert to unix. |
---|
401 | UnflipSlashes(buffer); |
---|
402 | |
---|
403 | WriteFile(hNewFile, buffer, strlen(buffer), &bytesWritten, NULL); |
---|
404 | |
---|
405 | // Copy file. |
---|
406 | do { |
---|
407 | if (!ReadFile(hOldFile, buffer, sizeof(buffer), &bytesRead, NULL)) { |
---|
408 | return ReportError("ReadFile"); |
---|
409 | } |
---|
410 | |
---|
411 | if (!WriteFile(hNewFile, buffer, bytesRead, &bytesWritten, NULL)) { |
---|
412 | return ReportError("WriteFile"); |
---|
413 | } |
---|
414 | |
---|
415 | } while (bytesRead > 0); |
---|
416 | |
---|
417 | CloseHandle(hNewFile); |
---|
418 | CloseHandle(hOldFile); |
---|
419 | |
---|
420 | // make copy have same time |
---|
421 | _utime(newFile, &utim); |
---|
422 | |
---|
423 | // If we don't need to do a #line, use an API to copy the file.. |
---|
424 | } else { |
---|
425 | |
---|
426 | BOOL isNTFS = FALSE; |
---|
427 | |
---|
428 | // Find out what kind of volume this is. |
---|
429 | if ( trySymlink ) { |
---|
430 | char rootPathName[MAX_PATH]; |
---|
431 | char *c = strchr(fullPathName, '\\'); |
---|
432 | |
---|
433 | if (c != NULL) { |
---|
434 | TCHAR fileSystemName[50]; |
---|
435 | |
---|
436 | strncpy(rootPathName, fullPathName, (c - fullPathName) + 1); |
---|
437 | |
---|
438 | if (!GetVolumeInformation(rootPathName, NULL, 0, NULL, NULL, NULL, fileSystemName, sizeof(rootPathName))) { |
---|
439 | return ReportError("GetVolumeInformation"); |
---|
440 | } |
---|
441 | |
---|
442 | isNTFS = (strcmp(fileSystemName, "NTFS") == 0); |
---|
443 | } |
---|
444 | } |
---|
445 | |
---|
446 | if (isNTFS) { |
---|
447 | printf(" Symlinking %s into %s\n", oldFile, newFile); |
---|
448 | |
---|
449 | if (! hardSymLink(oldFile, newFile) ) { |
---|
450 | return 1; |
---|
451 | } |
---|
452 | } else { |
---|
453 | printf(" Installing %s into %s\n", oldFile, newFile); |
---|
454 | |
---|
455 | if( ! CopyFile(oldFile, newFile, FALSE) ) { |
---|
456 | ReportError("CopyFile"); |
---|
457 | return 1; |
---|
458 | } |
---|
459 | } |
---|
460 | } |
---|
461 | |
---|
462 | return 0; |
---|
463 | } |
---|
464 | |
---|
465 | void Usage(void) |
---|
466 | { |
---|
467 | fprintf(stderr, "makecopy: [-cisx] <file1> [file2 ... fileN] <dir-path>\n"); |
---|
468 | fprintf(stderr, " -c copy [default], cancels -s\n"); |
---|
469 | fprintf(stderr, " -i add #line directive\n"); |
---|
470 | fprintf(stderr, " -r recurse subdirectories\n"); |
---|
471 | fprintf(stderr, " -s use symlinks on NT when possible\n"); |
---|
472 | fprintf(stderr, " -x cancel -i\n"); |
---|
473 | } |
---|
474 | |
---|
475 | |
---|
476 | int main( int argc, char *argv[] ) |
---|
477 | { |
---|
478 | char old_path[4096]; |
---|
479 | char new_path[4096]; |
---|
480 | char *oldFileName; // points to where file name starts in old_path |
---|
481 | char *newFileName; // points to where file name starts in new_path |
---|
482 | WIN32_FIND_DATA findFileData; |
---|
483 | int rv = 0; |
---|
484 | int i = 1; |
---|
485 | |
---|
486 | if (argc < 3) { |
---|
487 | Usage(); |
---|
488 | return 2; |
---|
489 | } |
---|
490 | |
---|
491 | // parse option flags |
---|
492 | for ( ; *argv[i] == '-' ; ++i) { |
---|
493 | char *opt = argv[i]+1; |
---|
494 | for ( ; *opt; ++opt) { |
---|
495 | switch (*opt) { |
---|
496 | case 'c': |
---|
497 | trySymlink = FALSE; |
---|
498 | break; |
---|
499 | case 'i': |
---|
500 | insertHashLine = TRUE; |
---|
501 | break; |
---|
502 | case 'r': |
---|
503 | recurse = TRUE; |
---|
504 | break; |
---|
505 | case 's': |
---|
506 | trySymlink = TRUE; |
---|
507 | break; |
---|
508 | case 'x': |
---|
509 | insertHashLine = FALSE; |
---|
510 | break; |
---|
511 | default: |
---|
512 | Usage(); |
---|
513 | return 2; |
---|
514 | } |
---|
515 | } |
---|
516 | } |
---|
517 | |
---|
518 | if ( trySymlink ) { |
---|
519 | OSVERSIONINFO osvi; |
---|
520 | |
---|
521 | // Symlinking supported only on WinNT, not Win9x |
---|
522 | // Is this Windows NT? |
---|
523 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
---|
524 | |
---|
525 | if (!GetVersionEx(&osvi)) { |
---|
526 | return ReportError(); |
---|
527 | } |
---|
528 | |
---|
529 | trySymlink = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT); |
---|
530 | |
---|
531 | if ( trySymlink ) { |
---|
532 | |
---|
533 | hDLL = LoadLibrary("Kernel32"); |
---|
534 | if (hDLL != NULL) |
---|
535 | { |
---|
536 | lpfnDllBackupWrite = (LPFNBackupWrite)GetProcAddress(hDLL, "BackupWrite"); |
---|
537 | lpfnDllCreateFileW = (LPFNCreateFileW)GetProcAddress(hDLL, "CreateFileW"); |
---|
538 | lpfnDllGetFullPathNameW = (LPFNGetFullPathNameW) GetProcAddress(hDLL, "GetFullPathNameW"); |
---|
539 | |
---|
540 | if ((!lpfnDllBackupWrite) || (!lpfnDllCreateFileW) || (!lpfnDllGetFullPathNameW)) |
---|
541 | { |
---|
542 | // handle the error |
---|
543 | int r = ReportError("GetProcAddress"); |
---|
544 | |
---|
545 | FreeLibrary(hDLL); |
---|
546 | return r; |
---|
547 | } |
---|
548 | } else { |
---|
549 | return ReportError(); |
---|
550 | } |
---|
551 | } |
---|
552 | } |
---|
553 | |
---|
554 | // destination path is last argument |
---|
555 | strcpy(new_path, argv[argc-1]); |
---|
556 | |
---|
557 | // append backslash to path if not already there |
---|
558 | if (new_path[strlen(new_path)] != '\\') { |
---|
559 | strcat(new_path, "\\"); |
---|
560 | } |
---|
561 | |
---|
562 | //sprintf(new_path, "%s\\", argv[i+1]); |
---|
563 | FlipSlashes(new_path); |
---|
564 | newFileName = new_path + strlen(new_path); |
---|
565 | |
---|
566 | if( MakeDir(new_path) < 0 ) { |
---|
567 | fprintf(stderr, "\n+++ makecopy: unable to create directory %s\n", new_path); |
---|
568 | return 1; |
---|
569 | } |
---|
570 | |
---|
571 | // copy all named source files |
---|
572 | while (i < (argc - 1)) { |
---|
573 | strcpy(old_path, argv[i]); |
---|
574 | |
---|
575 | FlipSlashes(old_path); |
---|
576 | oldFileName = strrchr(old_path, '\\'); |
---|
577 | if (oldFileName) { |
---|
578 | oldFileName++; |
---|
579 | } else { |
---|
580 | oldFileName = old_path; |
---|
581 | } |
---|
582 | |
---|
583 | HANDLE hFindFile = FindFirstFile(old_path, &findFileData); |
---|
584 | |
---|
585 | if (hFindFile != INVALID_HANDLE_VALUE) { |
---|
586 | do { |
---|
587 | strcpy(oldFileName, findFileData.cFileName); |
---|
588 | strcpy(newFileName, findFileData.cFileName); |
---|
589 | rv = CopyIfNecessary(old_path, new_path); |
---|
590 | |
---|
591 | } while (FindNextFile(hFindFile, &findFileData) != 0); |
---|
592 | } else { |
---|
593 | fprintf(stderr, "\n+++ makecopy: no such file: %s\n", old_path); |
---|
594 | } |
---|
595 | |
---|
596 | FindClose(hFindFile); |
---|
597 | i++; |
---|
598 | } |
---|
599 | if ( trySymlink ) { |
---|
600 | FreeLibrary(hDLL); |
---|
601 | } |
---|
602 | return 0; |
---|
603 | } |
---|