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

/dlls/setupapi/queue.c

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