PageRenderTime 32ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/dlls/setupapi/queue.c

https://github.com/mirrors/wine
C | 1473 lines | 1180 code | 168 blank | 125 comment | 185 complexity | b2dc72f6f91808a7145043ea7fa0bad1 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, LGPL-2.0, CC-BY-SA-3.0, BSD-3-Clause
  1. /*
  2. * Setupapi file queue routines
  3. *
  4. * Copyright 2002 Alexandre Julliard for CodeWeavers
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include <stdarg.h>
  21. #include <stdlib.h>
  22. #include "windef.h"
  23. #include "winbase.h"
  24. #include "winreg.h"
  25. #include "winternl.h"
  26. #include "winerror.h"
  27. #include "wingdi.h"
  28. #include "winuser.h"
  29. #include "winnls.h"
  30. #include "setupapi.h"
  31. #include "setupapi_private.h"
  32. #include "winver.h"
  33. #include "wine/debug.h"
  34. #include "wine/heap.h"
  35. WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
  36. /* context structure for the default queue callback */
  37. struct default_callback_context
  38. {
  39. DWORD magic;
  40. HWND owner;
  41. DWORD unk1[4];
  42. DWORD_PTR unk2[7];
  43. HWND progress;
  44. UINT message;
  45. DWORD_PTR unk3[5];
  46. };
  47. struct source_media
  48. {
  49. WCHAR root[MAX_PATH];
  50. WCHAR *desc, *tag;
  51. BOOL resolved;
  52. BOOL cabinet;
  53. };
  54. struct file_op
  55. {
  56. struct file_op *next;
  57. UINT style;
  58. WCHAR *src_path;
  59. WCHAR *src_file;
  60. WCHAR *dst_path;
  61. WCHAR *dst_file;
  62. struct source_media *media;
  63. };
  64. struct file_op_queue
  65. {
  66. struct file_op *head;
  67. struct file_op *tail;
  68. unsigned int count;
  69. };
  70. struct file_queue
  71. {
  72. DWORD magic;
  73. struct file_op_queue copy_queue;
  74. struct file_op_queue delete_queue;
  75. struct file_op_queue rename_queue;
  76. DWORD flags;
  77. struct source_media **sources;
  78. unsigned int source_count;
  79. };
  80. #define FILE_QUEUE_MAGIC 0x21514653
  81. /* append a file operation to a queue */
  82. static inline void queue_file_op( struct file_op_queue *queue, struct file_op *op )
  83. {
  84. op->next = NULL;
  85. if (queue->tail) queue->tail->next = op;
  86. else queue->head = op;
  87. queue->tail = op;
  88. queue->count++;
  89. }
  90. /* free all the file operations on a given queue */
  91. static void free_file_op_queue( struct file_op_queue *queue )
  92. {
  93. struct file_op *t, *op = queue->head;
  94. while( op )
  95. {
  96. HeapFree( GetProcessHeap(), 0, op->src_path );
  97. HeapFree( GetProcessHeap(), 0, op->src_file );
  98. HeapFree( GetProcessHeap(), 0, op->dst_path );
  99. if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
  100. t = op;
  101. op = op->next;
  102. HeapFree( GetProcessHeap(), 0, t );
  103. }
  104. }
  105. /* concat 3 strings to make a path, handling separators correctly */
  106. static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
  107. {
  108. *buffer = 0;
  109. if (src1 && *src1)
  110. {
  111. lstrcpyW( buffer, src1 );
  112. buffer += lstrlenW(buffer );
  113. if (buffer[-1] != '\\') *buffer++ = '\\';
  114. *buffer = 0;
  115. if (src2) while (*src2 == '\\') src2++;
  116. }
  117. if (src2)
  118. {
  119. lstrcpyW( buffer, src2 );
  120. buffer += lstrlenW(buffer );
  121. if (buffer[-1] != '\\') *buffer++ = '\\';
  122. *buffer = 0;
  123. if (src3) while (*src3 == '\\') src3++;
  124. }
  125. if (src3)
  126. lstrcpyW( buffer, src3 );
  127. }
  128. /***********************************************************************
  129. * build_filepathsW
  130. *
  131. * Build a FILEPATHS_W structure for a given file operation.
  132. */
  133. static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
  134. {
  135. unsigned int src_len = 1, dst_len = 1;
  136. WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
  137. if (!op->src_file || op->src_file[0] != '@')
  138. {
  139. if (op->media) src_len += lstrlenW(op->media->root) + 1;
  140. if (op->src_path) src_len += lstrlenW(op->src_path) + 1;
  141. }
  142. if (op->src_file) src_len += lstrlenW(op->src_file) + 1;
  143. if (op->dst_path) dst_len += lstrlenW(op->dst_path) + 1;
  144. if (op->dst_file) dst_len += lstrlenW(op->dst_file) + 1;
  145. src_len *= sizeof(WCHAR);
  146. dst_len *= sizeof(WCHAR);
  147. if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
  148. {
  149. HeapFree( GetProcessHeap(), 0, source );
  150. paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
  151. }
  152. if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
  153. {
  154. HeapFree( GetProcessHeap(), 0, target );
  155. paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
  156. }
  157. if (!source || !target) return FALSE;
  158. if (!op->src_file || op->src_file[0] != '@')
  159. concat_W( source, op->media ? op->media->root : NULL, op->src_path, op->src_file );
  160. else
  161. lstrcpyW( source, op->src_file );
  162. concat_W( target, NULL, op->dst_path, op->dst_file );
  163. paths->Win32Error = 0;
  164. paths->Flags = 0;
  165. return TRUE;
  166. }
  167. /***********************************************************************
  168. * QUEUE_callback_WtoA
  169. *
  170. * Map a file callback parameters from W to A and call the A callback.
  171. */
  172. UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
  173. UINT_PTR param1, UINT_PTR param2 )
  174. {
  175. struct callback_WtoA_context *callback_ctx = context;
  176. char buffer[MAX_PATH];
  177. UINT ret;
  178. UINT_PTR old_param2 = param2;
  179. switch(notification)
  180. {
  181. case SPFILENOTIFY_COPYERROR:
  182. buffer[0] = 0;
  183. param2 = (UINT_PTR)buffer;
  184. /* fall through */
  185. case SPFILENOTIFY_STARTDELETE:
  186. case SPFILENOTIFY_ENDDELETE:
  187. case SPFILENOTIFY_DELETEERROR:
  188. case SPFILENOTIFY_STARTRENAME:
  189. case SPFILENOTIFY_ENDRENAME:
  190. case SPFILENOTIFY_RENAMEERROR:
  191. case SPFILENOTIFY_STARTCOPY:
  192. case SPFILENOTIFY_ENDCOPY:
  193. case SPFILENOTIFY_QUEUESCAN_EX:
  194. {
  195. FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
  196. FILEPATHS_A pathsA;
  197. pathsA.Source = strdupWtoA( pathsW->Source );
  198. pathsA.Target = strdupWtoA( pathsW->Target );
  199. pathsA.Win32Error = pathsW->Win32Error;
  200. pathsA.Flags = pathsW->Flags;
  201. ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
  202. (UINT_PTR)&pathsA, param2 );
  203. HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
  204. HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
  205. }
  206. if (notification == SPFILENOTIFY_COPYERROR)
  207. MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
  208. break;
  209. case SPFILENOTIFY_STARTREGISTRATION:
  210. case SPFILENOTIFY_ENDREGISTRATION:
  211. {
  212. SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
  213. SP_REGISTER_CONTROL_STATUSA statusA;
  214. statusA.cbSize = sizeof(statusA);
  215. statusA.FileName = strdupWtoA( statusW->FileName );
  216. statusA.Win32Error = statusW->Win32Error;
  217. statusA.FailureCode = statusW->FailureCode;
  218. ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
  219. (UINT_PTR)&statusA, param2 );
  220. HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
  221. }
  222. break;
  223. case SPFILENOTIFY_QUEUESCAN:
  224. {
  225. LPWSTR targetW = (LPWSTR)param1;
  226. LPSTR target = strdupWtoA( targetW );
  227. ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
  228. (UINT_PTR)target, param2 );
  229. HeapFree( GetProcessHeap(), 0, target );
  230. }
  231. break;
  232. case SPFILENOTIFY_NEEDMEDIA:
  233. {
  234. const SOURCE_MEDIA_W *mediaW = (const SOURCE_MEDIA_W *)param1;
  235. char path[MAX_PATH];
  236. SOURCE_MEDIA_A mediaA;
  237. mediaA.Tagfile = strdupWtoA(mediaW->Tagfile);
  238. mediaA.Description = strdupWtoA(mediaW->Description);
  239. mediaA.SourcePath = strdupWtoA(mediaW->SourcePath);
  240. mediaA.SourceFile = strdupWtoA(mediaW->SourceFile);
  241. mediaA.Flags = mediaW->Flags;
  242. path[0] = 0;
  243. ret = callback_ctx->orig_handler(callback_ctx->orig_context, notification,
  244. (UINT_PTR)&mediaA, (UINT_PTR)&path);
  245. MultiByteToWideChar(CP_ACP, 0, path, -1, (WCHAR *)param2, MAX_PATH);
  246. heap_free((char *)mediaA.Tagfile);
  247. heap_free((char *)mediaA.Description);
  248. heap_free((char *)mediaA.SourcePath);
  249. heap_free((char *)mediaA.SourceFile);
  250. break;
  251. }
  252. case SPFILENOTIFY_STARTQUEUE:
  253. case SPFILENOTIFY_ENDQUEUE:
  254. case SPFILENOTIFY_STARTSUBQUEUE:
  255. case SPFILENOTIFY_ENDSUBQUEUE:
  256. default:
  257. ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
  258. break;
  259. }
  260. return ret;
  261. }
  262. static void get_source_info( HINF hinf, const WCHAR *src_file, SP_FILE_COPY_PARAMS_W *params,
  263. WCHAR *src_root, WCHAR *src_path)
  264. {
  265. INFCONTEXT file_ctx, disk_ctx;
  266. INT id, diskid;
  267. DWORD len;
  268. /* find the SourceDisksFiles entry */
  269. if (!SetupFindFirstLineW( hinf, L"SourceDisksFiles", src_file, &file_ctx )) return;
  270. if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
  271. /* now find the diskid in the SourceDisksNames section */
  272. if (!SetupFindFirstLineW( hinf, L"SourceDisksNames", NULL, &disk_ctx )) return;
  273. for (;;)
  274. {
  275. if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
  276. if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
  277. }
  278. if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) && len > sizeof(WCHAR)
  279. && (params->SourceDescription = heap_alloc( len * sizeof(WCHAR) )))
  280. SetupGetStringFieldW( &disk_ctx, 1, (WCHAR *)params->SourceDescription, len, NULL );
  281. if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR)
  282. && (params->SourceTagfile = heap_alloc( len * sizeof(WCHAR) )))
  283. SetupGetStringFieldW( &disk_ctx, 2, (WCHAR *)params->SourceTagfile, len, NULL );
  284. if (SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len ) && len > sizeof(WCHAR)
  285. && len < MAX_PATH - lstrlenW( src_root ) - 1)
  286. {
  287. lstrcatW( src_root, L"\\" );
  288. SetupGetStringFieldW( &disk_ctx, 4, src_root + lstrlenW( src_root ),
  289. MAX_PATH - lstrlenW( src_root ), NULL );
  290. }
  291. if (SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len ) && len > sizeof(WCHAR) && len < MAX_PATH)
  292. {
  293. SetupGetStringFieldW( &file_ctx, 2, src_path, MAX_PATH, NULL );
  294. params->SourcePath = src_path;
  295. }
  296. }
  297. /***********************************************************************
  298. * get_destination_dir
  299. *
  300. * Retrieve the destination dir for a given section.
  301. */
  302. static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
  303. {
  304. INFCONTEXT context;
  305. WCHAR systemdir[MAX_PATH], *dir;
  306. BOOL ret;
  307. if (!section || !(ret = SetupFindFirstLineW( hinf, L"DestinationDirs", section, &context )))
  308. ret = SetupFindFirstLineW( hinf, L"DestinationDirs", L"DefaultDestDir", &context );
  309. if (ret && (dir = PARSER_get_dest_dir( &context )))
  310. return dir;
  311. GetSystemDirectoryW( systemdir, MAX_PATH );
  312. return strdupW( systemdir );
  313. }
  314. struct extract_cab_ctx
  315. {
  316. const WCHAR *src;
  317. const WCHAR *dst;
  318. };
  319. static UINT WINAPI extract_cab_cb( void *arg, UINT message, UINT_PTR param1, UINT_PTR param2 )
  320. {
  321. struct extract_cab_ctx *ctx = arg;
  322. switch (message)
  323. {
  324. case SPFILENOTIFY_FILEINCABINET:
  325. {
  326. FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1;
  327. const WCHAR *filename;
  328. if ((filename = wcsrchr( info->NameInCabinet, '\\' )))
  329. filename++;
  330. else
  331. filename = info->NameInCabinet;
  332. if (lstrcmpiW( filename, ctx->src ))
  333. return FILEOP_SKIP;
  334. lstrcpyW( info->FullTargetName, ctx->dst );
  335. return FILEOP_DOIT;
  336. }
  337. case SPFILENOTIFY_FILEEXTRACTED:
  338. {
  339. const FILEPATHS_W *paths = (const FILEPATHS_W *)param1;
  340. return paths->Win32Error;
  341. }
  342. case SPFILENOTIFY_NEEDNEWCABINET:
  343. {
  344. const CABINET_INFO_W *info = (const CABINET_INFO_W *)param1;
  345. lstrcpyW( (WCHAR *)param2, info->CabinetPath );
  346. return ERROR_SUCCESS;
  347. }
  348. case SPFILENOTIFY_CABINETINFO:
  349. return 0;
  350. default:
  351. FIXME("Unexpected message %#x.\n", message);
  352. return 0;
  353. }
  354. }
  355. /***********************************************************************
  356. * extract_cabinet_file
  357. *
  358. * Extract a file from a .cab file.
  359. */
  360. static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
  361. const WCHAR *src, const WCHAR *dst )
  362. {
  363. struct extract_cab_ctx ctx = {src, dst};
  364. int len = lstrlenW( cabinet );
  365. WCHAR path[MAX_PATH];
  366. /* make sure the cabinet file has a .cab extension */
  367. if (len <= 4 || wcsicmp( cabinet + len - 4, L".cab" )) return FALSE;
  368. lstrcpyW(path, root);
  369. lstrcatW(path, L"\\" );
  370. lstrcatW(path, cabinet);
  371. return SetupIterateCabinetW( path, 0, extract_cab_cb, &ctx );
  372. }
  373. /***********************************************************************
  374. * SetupOpenFileQueue (SETUPAPI.@)
  375. */
  376. HSPFILEQ WINAPI SetupOpenFileQueue(void)
  377. {
  378. struct file_queue *queue;
  379. if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
  380. return INVALID_HANDLE_VALUE;
  381. queue->magic = FILE_QUEUE_MAGIC;
  382. return queue;
  383. }
  384. /***********************************************************************
  385. * SetupCloseFileQueue (SETUPAPI.@)
  386. */
  387. BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
  388. {
  389. struct file_queue *queue = handle;
  390. unsigned int i;
  391. /* Windows XP DDK installer passes the handle returned from
  392. * SetupInitDefaultQueueCallback() to this function. */
  393. if (queue->magic != FILE_QUEUE_MAGIC)
  394. {
  395. SetLastError(ERROR_INVALID_HANDLE);
  396. return FALSE;
  397. }
  398. free_file_op_queue( &queue->copy_queue );
  399. free_file_op_queue( &queue->rename_queue );
  400. free_file_op_queue( &queue->delete_queue );
  401. for (i = 0; i < queue->source_count; ++i)
  402. {
  403. heap_free( queue->sources[i]->desc );
  404. heap_free( queue->sources[i]->tag );
  405. heap_free( queue->sources[i] );
  406. }
  407. heap_free( queue->sources );
  408. HeapFree( GetProcessHeap(), 0, queue );
  409. return TRUE;
  410. }
  411. /***********************************************************************
  412. * SetupQueueCopyIndirectA (SETUPAPI.@)
  413. */
  414. BOOL WINAPI SetupQueueCopyIndirectA( SP_FILE_COPY_PARAMS_A *paramsA )
  415. {
  416. SP_FILE_COPY_PARAMS_W paramsW;
  417. BOOL ret;
  418. paramsW.cbSize = sizeof(paramsW);
  419. paramsW.QueueHandle = paramsA->QueueHandle;
  420. paramsW.SourceRootPath = strdupAtoW( paramsA->SourceRootPath );
  421. paramsW.SourcePath = strdupAtoW( paramsA->SourcePath );
  422. paramsW.SourceFilename = strdupAtoW( paramsA->SourceFilename );
  423. paramsW.SourceDescription = strdupAtoW( paramsA->SourceDescription );
  424. paramsW.SourceTagfile = strdupAtoW( paramsA->SourceTagfile );
  425. paramsW.TargetDirectory = strdupAtoW( paramsA->TargetDirectory );
  426. paramsW.TargetFilename = strdupAtoW( paramsA->TargetFilename );
  427. paramsW.CopyStyle = paramsA->CopyStyle;
  428. paramsW.LayoutInf = paramsA->LayoutInf;
  429. paramsW.SecurityDescriptor = strdupAtoW( paramsA->SecurityDescriptor );
  430. ret = SetupQueueCopyIndirectW( &paramsW );
  431. heap_free( (WCHAR *)paramsW.SourceRootPath );
  432. heap_free( (WCHAR *)paramsW.SourcePath );
  433. heap_free( (WCHAR *)paramsW.SourceFilename );
  434. heap_free( (WCHAR *)paramsW.SourceDescription );
  435. heap_free( (WCHAR *)paramsW.SourceTagfile );
  436. heap_free( (WCHAR *)paramsW.TargetDirectory );
  437. heap_free( (WCHAR *)paramsW.TargetFilename );
  438. heap_free( (WCHAR *)paramsW.SecurityDescriptor );
  439. return ret;
  440. }
  441. static BOOL equal_str(const WCHAR *a, const WCHAR *b)
  442. {
  443. return (!a && !b) || (a && b && !wcscmp(a, b));
  444. }
  445. static struct source_media *get_source_media(struct file_queue *queue,
  446. const WCHAR *root, const WCHAR *desc, const WCHAR *tag)
  447. {
  448. unsigned int i;
  449. for (i = 0; i < queue->source_count; ++i)
  450. {
  451. if (!wcscmp(root, queue->sources[i]->root)
  452. && equal_str(desc, queue->sources[i]->desc)
  453. && equal_str(tag, queue->sources[i]->tag))
  454. {
  455. return queue->sources[i];
  456. }
  457. }
  458. queue->sources = heap_realloc( queue->sources, ++queue->source_count * sizeof(*queue->sources) );
  459. queue->sources[i] = heap_alloc( sizeof(*queue->sources[i]) );
  460. lstrcpyW(queue->sources[i]->root, root);
  461. queue->sources[i]->desc = strdupW(desc);
  462. queue->sources[i]->tag = strdupW(tag);
  463. queue->sources[i]->resolved = FALSE;
  464. queue->sources[i]->cabinet = FALSE;
  465. return queue->sources[i];
  466. }
  467. /***********************************************************************
  468. * SetupQueueCopyIndirectW (SETUPAPI.@)
  469. */
  470. BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
  471. {
  472. struct file_queue *queue = params->QueueHandle;
  473. struct file_op *op;
  474. if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
  475. op->style = params->CopyStyle;
  476. op->src_path = strdupW( params->SourcePath );
  477. op->src_file = strdupW( params->SourceFilename );
  478. op->dst_path = strdupW( params->TargetDirectory );
  479. op->dst_file = strdupW( params->TargetFilename );
  480. /* some defaults */
  481. if (!op->dst_file) op->dst_file = op->src_file;
  482. if (params->LayoutInf)
  483. FIXME("Unhandled LayoutInf %p.\n", params->LayoutInf);
  484. op->media = get_source_media( queue, params->SourceRootPath ? params->SourceRootPath : L"",
  485. params->SourceDescription, params->SourceTagfile );
  486. TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
  487. debugstr_w(op->media->root), debugstr_w(op->src_path), debugstr_w(op->src_file),
  488. debugstr_w(op->dst_path), debugstr_w(op->dst_file),
  489. debugstr_w(op->media->desc), debugstr_w(op->media->tag) );
  490. queue_file_op( &queue->copy_queue, op );
  491. return TRUE;
  492. }
  493. /***********************************************************************
  494. * SetupQueueCopyA (SETUPAPI.@)
  495. */
  496. BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
  497. PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
  498. DWORD style )
  499. {
  500. SP_FILE_COPY_PARAMS_A params;
  501. params.cbSize = sizeof(params);
  502. params.QueueHandle = queue;
  503. params.SourceRootPath = src_root;
  504. params.SourcePath = src_path;
  505. params.SourceFilename = src_file;
  506. params.SourceDescription = src_descr;
  507. params.SourceTagfile = src_tag;
  508. params.TargetDirectory = dst_dir;
  509. params.TargetFilename = dst_file;
  510. params.CopyStyle = style;
  511. params.LayoutInf = 0;
  512. params.SecurityDescriptor = NULL;
  513. return SetupQueueCopyIndirectA( &params );
  514. }
  515. /***********************************************************************
  516. * SetupQueueCopyW (SETUPAPI.@)
  517. */
  518. BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
  519. PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
  520. DWORD style )
  521. {
  522. SP_FILE_COPY_PARAMS_W params;
  523. params.cbSize = sizeof(params);
  524. params.QueueHandle = queue;
  525. params.SourceRootPath = src_root;
  526. params.SourcePath = src_path;
  527. params.SourceFilename = src_file;
  528. params.SourceDescription = src_descr;
  529. params.SourceTagfile = src_tag;
  530. params.TargetDirectory = dst_dir;
  531. params.TargetFilename = dst_file;
  532. params.CopyStyle = style;
  533. params.LayoutInf = 0;
  534. params.SecurityDescriptor = NULL;
  535. return SetupQueueCopyIndirectW( &params );
  536. }
  537. /***********************************************************************
  538. * SetupQueueDefaultCopyA (SETUPAPI.@)
  539. */
  540. BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, const char *src_rootA,
  541. const char *src_fileA, const char *dst_fileA, DWORD style )
  542. {
  543. WCHAR src_rootW[MAX_PATH], src_fileW[MAX_PATH], dst_fileW[MAX_PATH];
  544. if (!src_rootA || !src_fileA || !dst_fileA)
  545. {
  546. SetLastError(ERROR_INVALID_PARAMETER);
  547. return FALSE;
  548. }
  549. MultiByteToWideChar( CP_ACP, 0, src_rootA, -1, src_rootW, ARRAY_SIZE(src_rootW) );
  550. MultiByteToWideChar( CP_ACP, 0, src_fileA, -1, src_fileW, ARRAY_SIZE(src_fileW) );
  551. MultiByteToWideChar( CP_ACP, 0, dst_fileA, -1, dst_fileW, ARRAY_SIZE(dst_fileW) );
  552. return SetupQueueDefaultCopyW( queue, hinf, src_rootW, src_fileW, dst_fileW, style );
  553. }
  554. /***********************************************************************
  555. * SetupQueueDefaultCopyW (SETUPAPI.@)
  556. */
  557. BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
  558. PCWSTR dst_file, DWORD style )
  559. {
  560. WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH];
  561. SP_FILE_COPY_PARAMS_W params;
  562. BOOL ret;
  563. if (!src_root || !src_file || !dst_file)
  564. {
  565. SetLastError(ERROR_INVALID_PARAMETER);
  566. return FALSE;
  567. }
  568. params.cbSize = sizeof(params);
  569. params.QueueHandle = queue;
  570. params.SourceRootPath = src_root_buffer;
  571. params.SourcePath = NULL;
  572. params.SourceFilename = src_file;
  573. params.SourceDescription = NULL;
  574. params.SourceTagfile = NULL;
  575. params.TargetFilename = dst_file;
  576. params.CopyStyle = style;
  577. params.LayoutInf = NULL;
  578. params.SecurityDescriptor = NULL;
  579. lstrcpyW( src_root_buffer, src_root );
  580. src_path[0] = 0;
  581. if (!(params.TargetDirectory = get_destination_dir( hinf, NULL ))) return FALSE;
  582. get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
  583. ret = SetupQueueCopyIndirectW( &params );
  584. heap_free( (WCHAR *)params.TargetDirectory );
  585. heap_free( (WCHAR *)params.SourceDescription );
  586. heap_free( (WCHAR *)params.SourceTagfile );
  587. return ret;
  588. }
  589. /***********************************************************************
  590. * SetupQueueDeleteA (SETUPAPI.@)
  591. */
  592. BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
  593. {
  594. struct file_queue *queue = handle;
  595. struct file_op *op;
  596. if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
  597. op->dst_path = strdupAtoW( part1 );
  598. op->dst_file = strdupAtoW( part2 );
  599. queue_file_op( &queue->delete_queue, op );
  600. return TRUE;
  601. }
  602. /***********************************************************************
  603. * SetupQueueDeleteW (SETUPAPI.@)
  604. */
  605. BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
  606. {
  607. struct file_queue *queue = handle;
  608. struct file_op *op;
  609. if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
  610. op->dst_path = strdupW( part1 );
  611. op->dst_file = strdupW( part2 );
  612. queue_file_op( &queue->delete_queue, op );
  613. return TRUE;
  614. }
  615. /***********************************************************************
  616. * SetupQueueRenameA (SETUPAPI.@)
  617. */
  618. BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
  619. PCSTR TargetPath, PCSTR TargetFilename )
  620. {
  621. struct file_queue *queue = handle;
  622. struct file_op *op;
  623. if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
  624. op->src_path = strdupAtoW( SourcePath );
  625. op->src_file = strdupAtoW( SourceFilename );
  626. op->dst_path = strdupAtoW( TargetPath ? TargetPath : SourcePath );
  627. op->dst_file = strdupAtoW( TargetFilename );
  628. queue_file_op( &queue->rename_queue, op );
  629. return TRUE;
  630. }
  631. /***********************************************************************
  632. * SetupQueueRenameW (SETUPAPI.@)
  633. */
  634. BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
  635. PCWSTR TargetPath, PCWSTR TargetFilename )
  636. {
  637. struct file_queue *queue = handle;
  638. struct file_op *op;
  639. if (!(op = heap_alloc_zero( sizeof(*op) ))) return FALSE;
  640. op->src_path = strdupW( SourcePath );
  641. op->src_file = strdupW( SourceFilename );
  642. op->dst_path = strdupW( TargetPath ? TargetPath : SourcePath );
  643. op->dst_file = strdupW( TargetFilename );
  644. queue_file_op( &queue->rename_queue, op );
  645. return TRUE;
  646. }
  647. /***********************************************************************
  648. * SetupQueueCopySectionA (SETUPAPI.@)
  649. */
  650. BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
  651. PCSTR section, DWORD style )
  652. {
  653. UNICODE_STRING sectionW;
  654. BOOL ret = FALSE;
  655. if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
  656. {
  657. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  658. return FALSE;
  659. }
  660. if (!src_root)
  661. ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
  662. else
  663. {
  664. UNICODE_STRING srcW;
  665. if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
  666. {
  667. ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
  668. RtlFreeUnicodeString( &srcW );
  669. }
  670. else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  671. }
  672. RtlFreeUnicodeString( &sectionW );
  673. return ret;
  674. }
  675. /***********************************************************************
  676. * SetupQueueCopySectionW (SETUPAPI.@)
  677. */
  678. BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
  679. PCWSTR section, DWORD style )
  680. {
  681. WCHAR src_root_buffer[MAX_PATH], src_path[MAX_PATH], src_file[MAX_PATH], dst_file[MAX_PATH], *dest_dir;
  682. INFCONTEXT context;
  683. SP_FILE_COPY_PARAMS_W params;
  684. INT flags;
  685. BOOL ret = FALSE;
  686. DWORD len;
  687. TRACE("queue %p, src_root %s, hinf %p, hlist %p, section %s, style %#lx.\n",
  688. queue, debugstr_w(src_root), hinf, hlist, debugstr_w(section), style);
  689. if (!src_root)
  690. {
  691. SetLastError(ERROR_INVALID_PARAMETER);
  692. return FALSE;
  693. }
  694. params.cbSize = sizeof(params);
  695. params.QueueHandle = queue;
  696. params.SourceRootPath = src_root_buffer;
  697. params.SourceFilename = src_file;
  698. params.TargetFilename = dst_file;
  699. params.CopyStyle = style;
  700. params.LayoutInf = NULL;
  701. params.SecurityDescriptor = NULL;
  702. lstrcpyW( src_root_buffer, src_root );
  703. if (!hlist) hlist = hinf;
  704. if (!hinf) hinf = hlist;
  705. if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
  706. if (!(params.TargetDirectory = dest_dir = get_destination_dir( hinf, section ))) return FALSE;
  707. do
  708. {
  709. params.SourcePath = NULL;
  710. params.SourceDescription = NULL;
  711. params.SourceTagfile = NULL;
  712. lstrcpyW( src_root_buffer, src_root );
  713. src_path[0] = 0;
  714. if (!SetupGetStringFieldW( &context, 1, dst_file, ARRAY_SIZE( dst_file ), NULL ))
  715. goto end;
  716. if (!SetupGetStringFieldW( &context, 2, src_file, ARRAY_SIZE( src_file ), &len ) || len <= sizeof(WCHAR))
  717. lstrcpyW( src_file, dst_file );
  718. if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
  719. get_source_info( hinf, src_file, &params, src_root_buffer, src_path );
  720. if (!SetupQueueCopyIndirectW( &params )) goto end;
  721. heap_free( (WCHAR *)params.SourceDescription );
  722. heap_free( (WCHAR *)params.SourceTagfile );
  723. } while (SetupFindNextLine( &context, &context ));
  724. ret = TRUE;
  725. end:
  726. HeapFree(GetProcessHeap(), 0, dest_dir);
  727. return ret;
  728. }
  729. /***********************************************************************
  730. * SetupQueueDeleteSectionA (SETUPAPI.@)
  731. */
  732. BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
  733. {
  734. UNICODE_STRING sectionW;
  735. BOOL ret = FALSE;
  736. if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
  737. {
  738. ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
  739. RtlFreeUnicodeString( &sectionW );
  740. }
  741. else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  742. return ret;
  743. }
  744. /***********************************************************************
  745. * SetupQueueDeleteSectionW (SETUPAPI.@)
  746. */
  747. BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
  748. {
  749. INFCONTEXT context;
  750. WCHAR *dest_dir;
  751. WCHAR buffer[MAX_PATH];
  752. BOOL ret = FALSE;
  753. INT flags;
  754. TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
  755. if (!hlist) hlist = hinf;
  756. if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
  757. if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
  758. do
  759. {
  760. if (!SetupGetStringFieldW( &context, 1, buffer, ARRAY_SIZE( buffer ), NULL ))
  761. goto done;
  762. if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
  763. if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
  764. } while (SetupFindNextLine( &context, &context ));
  765. ret = TRUE;
  766. done:
  767. HeapFree( GetProcessHeap(), 0, dest_dir );
  768. return ret;
  769. }
  770. /***********************************************************************
  771. * SetupQueueRenameSectionA (SETUPAPI.@)
  772. */
  773. BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
  774. {
  775. UNICODE_STRING sectionW;
  776. BOOL ret = FALSE;
  777. if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
  778. {
  779. ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
  780. RtlFreeUnicodeString( &sectionW );
  781. }
  782. else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  783. return ret;
  784. }
  785. /***********************************************************************
  786. * SetupQueueRenameSectionW (SETUPAPI.@)
  787. */
  788. BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
  789. {
  790. INFCONTEXT context;
  791. WCHAR *dest_dir;
  792. WCHAR src[MAX_PATH], dst[MAX_PATH];
  793. BOOL ret = FALSE;
  794. TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
  795. if (!hlist) hlist = hinf;
  796. if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
  797. if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
  798. do
  799. {
  800. if (!SetupGetStringFieldW( &context, 1, dst, ARRAY_SIZE( dst ), NULL ))
  801. goto done;
  802. if (!SetupGetStringFieldW( &context, 2, src, ARRAY_SIZE( src ), NULL ))
  803. goto done;
  804. if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
  805. } while (SetupFindNextLine( &context, &context ));
  806. ret = TRUE;
  807. done:
  808. HeapFree( GetProcessHeap(), 0, dest_dir );
  809. return ret;
  810. }
  811. /***********************************************************************
  812. * SetupCommitFileQueueA (SETUPAPI.@)
  813. */
  814. BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
  815. PVOID context )
  816. {
  817. struct callback_WtoA_context ctx;
  818. ctx.orig_context = context;
  819. ctx.orig_handler = handler;
  820. return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
  821. }
  822. /***********************************************************************
  823. * create_full_pathW
  824. *
  825. * Recursively create all directories in the path.
  826. */
  827. static BOOL create_full_pathW(const WCHAR *path)
  828. {
  829. BOOL ret = TRUE;
  830. int len;
  831. WCHAR *new_path;
  832. new_path = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(path) + 1) * sizeof(WCHAR));
  833. lstrcpyW(new_path, path);
  834. while((len = lstrlenW(new_path)) && new_path[len - 1] == '\\')
  835. new_path[len - 1] = 0;
  836. while(!CreateDirectoryW(new_path, NULL))
  837. {
  838. WCHAR *slash;
  839. DWORD last_error = GetLastError();
  840. if(last_error == ERROR_ALREADY_EXISTS)
  841. break;
  842. if(last_error != ERROR_PATH_NOT_FOUND)
  843. {
  844. ret = FALSE;
  845. break;
  846. }
  847. if(!(slash = wcsrchr(new_path, '\\')))
  848. {
  849. ret = FALSE;
  850. break;
  851. }
  852. len = slash - new_path;
  853. new_path[len] = 0;
  854. if(!create_full_pathW(new_path))
  855. {
  856. ret = FALSE;
  857. break;
  858. }
  859. new_path[len] = '\\';
  860. }
  861. HeapFree(GetProcessHeap(), 0, new_path);
  862. return ret;
  863. }
  864. static BOOL copy_file( LPCWSTR source, LPCWSTR target )
  865. {
  866. WCHAR module[MAX_PATH];
  867. HMODULE mod = NULL;
  868. HRSRC res;
  869. HGLOBAL data;
  870. HANDLE handle;
  871. DWORD size, written;
  872. BOOL ret = FALSE;
  873. int id = 0;
  874. const WCHAR *p;
  875. TRACE( "%s -> %s\n", debugstr_w(source), debugstr_w(target) );
  876. if (source[0] != '@') return CopyFileW( source, target, FALSE );
  877. /* Wine extension: when the source of a file copy is in the format "@file.dll,-123"
  878. * the source data is extracted from the corresponding file.dll resource */
  879. source++; /* skip '@' */
  880. p = wcschr( source, ',' );
  881. if (!p || p - source >= MAX_PATH)
  882. {
  883. SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
  884. return FALSE;
  885. }
  886. memcpy( module, source, (p - source) * sizeof(WCHAR) );
  887. module[p - source] = 0;
  888. id = -wcstol( p + 1, NULL, 10 );
  889. if (id <= 0 || id > 0xffff ||
  890. !(mod = LoadLibraryExW( module, 0, LOAD_LIBRARY_AS_DATAFILE )) ||
  891. !(res = FindResourceW( mod, MAKEINTRESOURCEW(id), L"WINE_DATA_FILE" )) ||
  892. !(data = LoadResource( mod, res )))
  893. {
  894. WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
  895. if (mod) FreeLibrary( mod );
  896. SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND );
  897. return FALSE;
  898. }
  899. size = SizeofResource( mod, res );
  900. if ((handle = CreateFileW( target, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  901. CREATE_ALWAYS, 0, 0 )) == INVALID_HANDLE_VALUE)
  902. {
  903. WARN( "failed to save %s #%d to %s\n", debugstr_w(module), -id, debugstr_w(target) );
  904. if (mod) FreeLibrary( mod );
  905. return FALSE;
  906. }
  907. ret = WriteFile( handle, LockResource(data), size, &written, NULL ) && written == size;
  908. CloseHandle( handle );
  909. if (!ret) DeleteFileW( target );
  910. return ret;
  911. }
  912. static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
  913. PSP_FILE_CALLBACK_W handler, PVOID context )
  914. {
  915. BOOL rc = FALSE;
  916. BOOL docopy = TRUE;
  917. TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style);
  918. /* before copy processing */
  919. if (style & SP_COPY_REPLACEONLY)
  920. {
  921. if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
  922. docopy = FALSE;
  923. }
  924. if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
  925. {
  926. DWORD VersionSizeSource=0;
  927. DWORD VersionSizeTarget=0;
  928. DWORD zero=0;
  929. /*
  930. * This is sort of an interesting workaround. You see, calling
  931. * GetVersionInfoSize on a builtin dll loads that dll into memory
  932. * and we do not properly unload builtin dlls.. so we effectively
  933. * lock into memory all the targets we are replacing. This leads
  934. * to problems when we try to register the replaced dlls.
  935. *
  936. * So I will test for the existence of the files first so that
  937. * we just basically unconditionally replace the builtin versions.
  938. */
  939. if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
  940. (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
  941. {
  942. VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
  943. VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
  944. }
  945. if (VersionSizeSource && VersionSizeTarget)
  946. {
  947. LPVOID VersionSource;
  948. LPVOID VersionTarget;
  949. VS_FIXEDFILEINFO *TargetInfo;
  950. VS_FIXEDFILEINFO *SourceInfo;
  951. UINT length;
  952. DWORD ret;
  953. VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
  954. VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
  955. ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
  956. if (ret)
  957. ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
  958. VersionTarget);
  959. if (ret)
  960. {
  961. ret = VerQueryValueW(VersionSource, L"\\", (LPVOID*)&SourceInfo, &length);
  962. if (ret)
  963. ret = VerQueryValueW(VersionTarget, L"\\", (LPVOID*)&TargetInfo, &length);
  964. if (ret)
  965. {
  966. FILEPATHS_W filepaths;
  967. TRACE("Versions: Source %li.%li target %li.%li\n",
  968. SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
  969. TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
  970. /* used in case of notification */
  971. filepaths.Target = target;
  972. filepaths.Source = source;
  973. filepaths.Win32Error = 0;
  974. filepaths.Flags = 0;
  975. if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
  976. {
  977. if (handler)
  978. docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
  979. else
  980. docopy = FALSE;
  981. }
  982. else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
  983. && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
  984. {
  985. if (handler)
  986. docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
  987. else
  988. docopy = FALSE;
  989. }
  990. else if ((style & SP_COPY_NEWER_ONLY) &&
  991. (TargetInfo->dwFileVersionMS ==
  992. SourceInfo->dwFileVersionMS)
  993. &&(TargetInfo->dwFileVersionLS ==
  994. SourceInfo->dwFileVersionLS))
  995. {
  996. if (handler)
  997. docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
  998. else
  999. docopy = FALSE;
  1000. }
  1001. }
  1002. }
  1003. HeapFree(GetProcessHeap(),0,VersionSource);
  1004. HeapFree(GetProcessHeap(),0,VersionTarget);
  1005. }
  1006. }
  1007. if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
  1008. {
  1009. if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
  1010. {
  1011. FIXME("Notify user target file exists\n");
  1012. docopy = FALSE;
  1013. }
  1014. }
  1015. if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
  1016. SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
  1017. {
  1018. ERR("Unsupported style(s) 0x%lx\n",style);
  1019. }
  1020. if (docopy)
  1021. {
  1022. rc = copy_file( source, target );
  1023. if (!rc && GetLastError() == ERROR_SHARING_VIOLATION &&
  1024. (style & SP_COPY_IN_USE_NEEDS_REBOOT))
  1025. {
  1026. WCHAR temp_file[MAX_PATH];
  1027. WCHAR temp[MAX_PATH];
  1028. if (GetTempPathW(MAX_PATH, temp) &&
  1029. GetTempFileNameW(temp, L"SET", 0, temp_file))
  1030. {
  1031. rc = copy_file( source, temp_file );
  1032. if (rc)
  1033. rc = MoveFileExW(temp_file, target, MOVEFILE_DELAY_UNTIL_REBOOT);
  1034. else
  1035. DeleteFileW(temp_file);
  1036. }
  1037. }
  1038. if (!rc) WARN( "failed to copy, err %lu\n", GetLastError() );
  1039. }
  1040. else
  1041. SetLastError(ERROR_SUCCESS);
  1042. /* after copy processing */
  1043. if (style & SP_COPY_DELETESOURCE)
  1044. {
  1045. if (rc)
  1046. DeleteFileW(source);
  1047. }
  1048. return rc;
  1049. }
  1050. /***********************************************************************
  1051. * SetupInstallFileExA (SETUPAPI.@)
  1052. */
  1053. BOOL WINAPI SetupInstallFileExA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
  1054. PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context, PBOOL in_use )
  1055. {
  1056. BOOL ret = FALSE;
  1057. struct callback_WtoA_context ctx;
  1058. UNICODE_STRING sourceW, rootW, destW;
  1059. TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
  1060. debugstr_a(dest), style, handler, context, in_use);
  1061. sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
  1062. if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
  1063. {
  1064. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1065. return FALSE;
  1066. }
  1067. if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
  1068. {
  1069. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1070. goto exit;
  1071. }
  1072. if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
  1073. {
  1074. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1075. goto exit;
  1076. }
  1077. ctx.orig_context = context;
  1078. ctx.orig_handler = handler;
  1079. ret = SetupInstallFileExW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx, in_use );
  1080. exit:
  1081. RtlFreeUnicodeString( &sourceW );
  1082. RtlFreeUnicodeString( &rootW );
  1083. RtlFreeUnicodeString( &destW );
  1084. return ret;
  1085. }
  1086. /***********************************************************************
  1087. * SetupInstallFileA (SETUPAPI.@)
  1088. */
  1089. BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
  1090. PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
  1091. {
  1092. return SetupInstallFileExA( hinf, inf_context, source, root, dest, style, handler, context, NULL );
  1093. }
  1094. /***********************************************************************
  1095. * SetupInstallFileExW (SETUPAPI.@)
  1096. */
  1097. BOOL WINAPI SetupInstallFileExW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
  1098. PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context, PBOOL in_use )
  1099. {
  1100. BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
  1101. WCHAR *buffer, *p, *inf_source = NULL, dest_path[MAX_PATH];
  1102. DWORD len;
  1103. TRACE("%p %p %s %s %s %lx %p %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
  1104. debugstr_w(dest), style, handler, context, in_use);
  1105. if (in_use) FIXME("no file in use support\n");
  1106. dest_path[0] = 0;
  1107. if (hinf)
  1108. {
  1109. WCHAR *dest_dir;
  1110. INFCONTEXT ctx;
  1111. if (!inf_context)
  1112. {
  1113. inf_context = &ctx;
  1114. if (!SetupFindFirstLineW( hinf, L"CopyFiles", NULL, inf_context )) return FALSE;
  1115. }
  1116. if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, &len )) return FALSE;
  1117. if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
  1118. {
  1119. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1120. return FALSE;
  1121. }
  1122. if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
  1123. {
  1124. HeapFree( GetProcessHeap(), 0, inf_source );
  1125. return FALSE;
  1126. }
  1127. source = inf_source;
  1128. if ((dest_dir = get_destination_dir( hinf, NULL )))
  1129. {
  1130. lstrcpyW( dest_path, dest_dir );
  1131. lstrcatW( dest_path, L"\\" );
  1132. heap_free( dest_dir );
  1133. }
  1134. }
  1135. else if (!source)
  1136. {
  1137. SetLastError( ERROR_INVALID_PARAMETER );
  1138. return FALSE;
  1139. }
  1140. len = lstrlenW( source ) + 1;
  1141. if (absolute) len += lstrlenW( root ) + 1;
  1142. if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
  1143. {
  1144. HeapFree( GetProcessHeap(), 0, inf_source );
  1145. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1146. return FALSE;
  1147. }
  1148. if (absolute)
  1149. {
  1150. lstrcpyW( buffer, root );
  1151. p += lstrlenW( buffer );
  1152. if (p[-1] != '\\') *p++ = '\\';
  1153. }
  1154. while (*source == '\\') source++;
  1155. lstrcpyW( p, source );
  1156. lstrcatW( dest_path, dest );
  1157. ret = do_file_copyW( buffer, dest_path, style, handler, context );
  1158. HeapFree( GetProcessHeap(), 0, inf_source );
  1159. HeapFree( GetProcessHeap(), 0, buffer );
  1160. return ret;
  1161. }
  1162. /***********************************************************************
  1163. * SetupInstallFileW (SETUPAPI.@)
  1164. */
  1165. BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
  1166. PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
  1167. {
  1168. return SetupInstallFileExW( hinf, inf_context, source, root, dest, style, handler, context, NULL );
  1169. }
  1170. static BOOL queue_copy_file( const WCHAR *source, const WCHAR *dest,
  1171. const struct file_op *op, PSP_FILE_CALLBACK_W handler, void *context )
  1172. {
  1173. TRACE("copying file %s -> %s\n", debugstr_w(source), debugstr_w(dest));
  1174. if (op->dst_path && !create_full_pathW(op->dst_path))
  1175. return FALSE;
  1176. if (do_file_copyW(source, dest, op->style, handler, context) || GetLastError() == ERROR_SUCCESS)
  1177. return TRUE;
  1178. /* try to extract it from the cabinet file */
  1179. if (op->media->tag && extract_cabinet_file(op->media->tag, op->media->root, op->src_file, dest))
  1180. {
  1181. op->media->cabinet = TRUE;
  1182. return TRUE;
  1183. }
  1184. return FALSE;
  1185. }
  1186. /***********************************************************************
  1187. * SetupCommitFileQueueW (SETUPAPI.@)
  1188. */
  1189. BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
  1190. PVOID context )
  1191. {
  1192. struct file_queue *queue = handle;
  1193. struct file_op *op;
  1194. BOOL result = FALSE;
  1195. FILEPATHS_W paths;
  1196. UINT op_result;
  1197. paths.Source = paths.Target = NULL;
  1198. if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
  1199. return TRUE; /* nothing to do */
  1200. if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
  1201. /* perform deletes */
  1202. if (queue->delete_queue.count)
  1203. {
  1204. if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
  1205. queue->delete_queue.count ))) goto done;
  1206. for (op = queue->delete_queue.head; op; op = op->next)
  1207. {
  1208. build_filepathsW( op, &paths );
  1209. op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
  1210. if (op_result == FILEOP_ABORT) goto done;
  1211. while (op_result == FILEOP_DOIT)
  1212. {
  1213. TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
  1214. if (DeleteFileW( paths.Target )) break; /* success */
  1215. paths.Win32Error = GetLastError();
  1216. op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
  1217. if (op_result == FILEOP_ABORT) goto done;
  1218. }
  1219. handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
  1220. }
  1221. handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
  1222. }
  1223. /* perform renames */
  1224. if (queue->rename_queue.count)
  1225. {
  1226. if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
  1227. queue->rename_queue.count ))) goto done;
  1228. for (op = queue->rename_queue.head; op; op = op->next)
  1229. {
  1230. build_filepathsW( op, &paths );
  1231. op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
  1232. if (op_result == FILEOP_ABORT) goto done;
  1233. while (op_result == FILEOP_DOIT)
  1234. {
  1235. TRACE( "renaming file %s -> %s\n",
  1236. debugstr_w(paths.Source), debugstr_w(paths.Target) );
  1237. if (MoveFileW( paths.Source, paths.Target )) break; /* success */
  1238. paths.Win32Error = GetLastError();
  1239. op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
  1240. if (op_result == FILEOP_ABORT) goto done;
  1241. }
  1242. handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
  1243. }
  1244. handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
  1245. }
  1246. /* perform copies */
  1247. if (queue->copy_queue.count)
  1248. {
  1249. if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
  1250. queue->copy_queue.count ))) goto done;
  1251. for (op = queue->copy_queue.head; op; op = op->next)
  1252. {
  1253. WCHAR newpath[MAX_PATH];
  1254. if (!op->media->resolved)
  1255. {
  1256. /* The NEEDMEDIA callback asks for the folder containing the
  1257. * first file, but that might be in a subdir of the source
  1258. * disk's root directory. We have to do some contortions to
  1259. * correct for this. Pretend that the file we're using
  1260. * actually isn't in a subdirectory, but keep track of what it
  1261. * was, and then later strip it from the root path that we
  1262. * ultimately resolve the source disk to. */
  1263. WCHAR src_path[MAX_PATH];
  1264. size_t path_len = 0;
  1265. src_path[0] = 0;
  1266. if (op->src_path)
  1267. {