2 * Setupapi file queue routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
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.
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.
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
21 #include "setupapi_private.h"
25 /* Unicode constants */
26 static const WCHAR DotSecurity
[] = {'.','S','e','c','u','r','i','t','y',0};
28 /* context structure for the default queue callback */
29 struct default_callback_context
47 PSECURITY_DESCRIPTOR dst_sd
;
59 struct file_op_queue copy_queue
;
60 struct file_op_queue delete_queue
;
61 struct file_op_queue rename_queue
;
66 static inline WCHAR
*strdupW( const WCHAR
*str
)
71 int len
= (strlenW(str
) + 1) * sizeof(WCHAR
);
72 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
))) memcpy( ret
, str
, len
);
77 static inline char *strdupWtoA( const WCHAR
*str
)
82 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
83 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
)))
84 WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
89 /* append a file operation to a queue */
90 static inline void queue_file_op( struct file_op_queue
*queue
, struct file_op
*op
)
93 if (queue
->tail
) queue
->tail
->next
= op
;
94 else queue
->head
= op
;
99 /* free all the file operations on a given queue */
100 static void free_file_op_queue( struct file_op_queue
*queue
)
102 struct file_op
*t
, *op
= queue
->head
;
106 HeapFree( GetProcessHeap(), 0, op
->src_root
);
107 HeapFree( GetProcessHeap(), 0, op
->src_path
);
108 HeapFree( GetProcessHeap(), 0, op
->src_file
);
109 HeapFree( GetProcessHeap(), 0, op
->src_descr
);
110 HeapFree( GetProcessHeap(), 0, op
->src_tag
);
111 HeapFree( GetProcessHeap(), 0, op
->dst_path
);
112 if (op
->dst_sd
) LocalFree( op
->dst_sd
);
113 if (op
->dst_file
!= op
->src_file
) HeapFree( GetProcessHeap(), 0, op
->dst_file
);
116 HeapFree( GetProcessHeap(), 0, t
);
120 /* concat 3 strings to make a path, handling separators correctly */
121 static void concat_W( WCHAR
*buffer
, const WCHAR
*src1
, const WCHAR
*src2
, const WCHAR
*src3
)
126 strcpyW( buffer
, src1
);
127 buffer
+= strlenW(buffer
);
128 if (buffer
[-1] != '\\') *buffer
++ = '\\';
129 if (src2
) while (*src2
== '\\') src2
++;
134 strcpyW( buffer
, src2
);
135 buffer
+= strlenW(buffer
);
136 if (buffer
[-1] != '\\') *buffer
++ = '\\';
137 if (src3
) while (*src3
== '\\') src3
++;
141 strcpyW( buffer
, src3
);
145 /***********************************************************************
148 * Build a FILEPATHS_W structure for a given file operation.
150 static BOOL
build_filepathsW( const struct file_op
*op
, FILEPATHS_W
*paths
)
152 unsigned int src_len
= 1, dst_len
= 1;
153 WCHAR
*source
= (PWSTR
)paths
->Source
, *target
= (PWSTR
)paths
->Target
;
155 if (op
->src_root
) src_len
+= strlenW(op
->src_root
) + 1;
156 if (op
->src_path
) src_len
+= strlenW(op
->src_path
) + 1;
157 if (op
->src_file
) src_len
+= strlenW(op
->src_file
) + 1;
158 if (op
->dst_path
) dst_len
+= strlenW(op
->dst_path
) + 1;
159 if (op
->dst_file
) dst_len
+= strlenW(op
->dst_file
) + 1;
160 src_len
*= sizeof(WCHAR
);
161 dst_len
*= sizeof(WCHAR
);
163 if (!source
|| HeapSize( GetProcessHeap(), 0, source
) < src_len
)
165 HeapFree( GetProcessHeap(), 0, source
);
166 paths
->Source
= source
= HeapAlloc( GetProcessHeap(), 0, src_len
);
168 if (!target
|| HeapSize( GetProcessHeap(), 0, target
) < dst_len
)
170 HeapFree( GetProcessHeap(), 0, target
);
171 paths
->Target
= target
= HeapAlloc( GetProcessHeap(), 0, dst_len
);
173 if (!source
|| !target
) return FALSE
;
174 concat_W( source
, op
->src_root
, op
->src_path
, op
->src_file
);
175 concat_W( target
, NULL
, op
->dst_path
, op
->dst_file
);
176 paths
->Win32Error
= 0;
182 /***********************************************************************
183 * QUEUE_callback_WtoA
185 * Map a file callback parameters from W to A and call the A callback.
187 UINT CALLBACK
QUEUE_callback_WtoA( void *context
, UINT notification
,
188 UINT_PTR param1
, UINT_PTR param2
)
190 struct callback_WtoA_context
*callback_ctx
= context
;
191 char buffer
[MAX_PATH
];
193 UINT_PTR old_param2
= param2
;
197 case SPFILENOTIFY_COPYERROR
:
198 param2
= (UINT_PTR
)&buffer
;
200 case SPFILENOTIFY_STARTDELETE
:
201 case SPFILENOTIFY_ENDDELETE
:
202 case SPFILENOTIFY_DELETEERROR
:
203 case SPFILENOTIFY_STARTRENAME
:
204 case SPFILENOTIFY_ENDRENAME
:
205 case SPFILENOTIFY_RENAMEERROR
:
206 case SPFILENOTIFY_STARTCOPY
:
207 case SPFILENOTIFY_ENDCOPY
:
208 case SPFILENOTIFY_QUEUESCAN_EX
:
210 FILEPATHS_W
*pathsW
= (FILEPATHS_W
*)param1
;
213 pathsA
.Source
= strdupWtoA( pathsW
->Source
);
214 pathsA
.Target
= strdupWtoA( pathsW
->Target
);
215 pathsA
.Win32Error
= pathsW
->Win32Error
;
216 pathsA
.Flags
= pathsW
->Flags
;
217 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
,
218 (UINT_PTR
)&pathsA
, param2
);
219 HeapFree( GetProcessHeap(), 0, (void *)pathsA
.Source
);
220 HeapFree( GetProcessHeap(), 0, (void *)pathsA
.Target
);
222 if (notification
== SPFILENOTIFY_COPYERROR
)
223 MultiByteToWideChar( CP_ACP
, 0, buffer
, -1, (WCHAR
*)old_param2
, MAX_PATH
);
226 case SPFILENOTIFY_STARTREGISTRATION
:
227 case SPFILENOTIFY_ENDREGISTRATION
:
229 SP_REGISTER_CONTROL_STATUSW
*statusW
= (SP_REGISTER_CONTROL_STATUSW
*)param1
;
230 SP_REGISTER_CONTROL_STATUSA statusA
;
232 statusA
.cbSize
= sizeof(statusA
);
233 statusA
.FileName
= strdupWtoA( statusW
->FileName
);
234 statusA
.Win32Error
= statusW
->Win32Error
;
235 statusA
.FailureCode
= statusW
->FailureCode
;
236 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
,
237 (UINT_PTR
)&statusA
, param2
);
238 HeapFree( GetProcessHeap(), 0, (LPSTR
)statusA
.FileName
);
242 case SPFILENOTIFY_QUEUESCAN
:
244 LPWSTR targetW
= (LPWSTR
)param1
;
245 LPSTR target
= strdupWtoA( targetW
);
247 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
,
248 (UINT_PTR
)target
, param2
);
249 HeapFree( GetProcessHeap(), 0, target
);
253 case SPFILENOTIFY_NEEDMEDIA
:
254 FIXME("mapping for %d not implemented\n",notification
);
255 case SPFILENOTIFY_STARTQUEUE
:
256 case SPFILENOTIFY_ENDQUEUE
:
257 case SPFILENOTIFY_STARTSUBQUEUE
:
258 case SPFILENOTIFY_ENDSUBQUEUE
:
260 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
, param1
, param2
);
267 /***********************************************************************
270 * Retrieve the source file information for a given file.
272 static void get_src_file_info( HINF hinf
, struct file_op
*op
)
274 static const WCHAR SourceDisksNames
[] =
275 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
276 static const WCHAR SourceDisksFiles
[] =
277 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
279 INFCONTEXT file_ctx
, disk_ctx
;
282 WCHAR SectionName
[MAX_PATH
];
284 /* find the SourceDisksFiles entry */
285 if(!SetupDiGetActualSectionToInstallW(hinf
, SourceDisksFiles
, SectionName
, MAX_PATH
, NULL
, NULL
))
287 if (!SetupFindFirstLineW( hinf
, SectionName
, op
->src_file
, &file_ctx
))
289 if ((op
->style
& (SP_COPY_SOURCE_ABSOLUTE
|SP_COPY_SOURCEPATH_ABSOLUTE
))) return;
290 /* no specific info, use .inf file source directory */
291 if (!op
->src_root
) op
->src_root
= PARSER_get_src_root( hinf
);
294 if (!SetupGetIntField( &file_ctx
, 1, &diskid
)) return;
296 /* now find the diskid in the SourceDisksNames section */
297 if(!SetupDiGetActualSectionToInstallW(hinf
, SourceDisksNames
, SectionName
, MAX_PATH
, NULL
, NULL
))
299 if (!SetupFindFirstLineW( hinf
, SectionName
, NULL
, &disk_ctx
)) return;
302 if (SetupGetIntField( &disk_ctx
, 0, &id
) && (id
== diskid
)) break;
303 if (!SetupFindNextLine( &disk_ctx
, &disk_ctx
)) return;
306 /* and fill in the missing info */
310 if (SetupGetStringFieldW( &disk_ctx
, 1, NULL
, 0, &len
) &&
311 (op
->src_descr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) )))
312 SetupGetStringFieldW( &disk_ctx
, 1, op
->src_descr
, len
, NULL
);
316 if (SetupGetStringFieldW( &disk_ctx
, 2, NULL
, 0, &len
) &&
317 (op
->src_tag
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) )))
318 SetupGetStringFieldW( &disk_ctx
, 2, op
->src_tag
, len
, NULL
);
320 if (!op
->src_path
&& !(op
->style
& SP_COPY_SOURCE_ABSOLUTE
))
323 if (!(op
->style
& SP_COPY_SOURCEPATH_ABSOLUTE
))
325 /* retrieve relative path for this disk */
326 if (!SetupGetStringFieldW( &disk_ctx
, 4, NULL
, 0, &len
)) len
= 0;
328 /* retrieve relative path for this file */
329 if (!SetupGetStringFieldW( &file_ctx
, 2, NULL
, 0, &len2
)) len2
= 0;
332 (op
->src_path
= HeapAlloc( GetProcessHeap(), 0, (len
+len2
)*sizeof(WCHAR
) )))
334 WCHAR
*ptr
= op
->src_path
;
337 SetupGetStringFieldW( &disk_ctx
, 4, op
->src_path
, len
, NULL
);
338 ptr
= op
->src_path
+ strlenW(op
->src_path
);
339 if (len2
&& ptr
> op
->src_path
&& ptr
[-1] != '\\') *ptr
++ = '\\';
341 if (!SetupGetStringFieldW( &file_ctx
, 2, ptr
, len2
, NULL
)) *ptr
= 0;
344 if (!op
->src_root
) op
->src_root
= PARSER_get_src_root(hinf
);
348 /***********************************************************************
349 * get_destination_dir
351 * Retrieve the destination dir for a given section.
353 static WCHAR
*get_destination_dir( HINF hinf
, const WCHAR
*section
)
355 static const WCHAR Dest
[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
356 static const WCHAR Def
[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
359 if (!SetupFindFirstLineW( hinf
, Dest
, section
, &context
) &&
360 !SetupFindFirstLineW( hinf
, Dest
, Def
, &context
)) return NULL
;
361 return PARSER_get_dest_dir( &context
);
366 static void (WINAPI
*pExtractFiles
)( LPSTR
, LPSTR
, DWORD
, DWORD
, DWORD
, DWORD
);
368 static void (WINAPI
*pExtractFiles
)( LPSTR
, LPSTR
, DWORD
, LPSTR
, LPVOID
, DWORD
);
371 /***********************************************************************
372 * extract_cabinet_file
374 * Extract a file from a .cab file.
376 static BOOL
extract_cabinet_file( const WCHAR
*cabinet
, const WCHAR
*root
,
377 const WCHAR
*src
, const WCHAR
*dst
)
380 static const WCHAR extW
[] = {'.','c','a','b',0};
382 static HMODULE advpack
;
384 char *cab_path
, *cab_file
;
385 int len
= strlenW( cabinet
);
388 TRACE("extract_cabinet_file(cab = '%s' ; root = '%s' ; src = '%s' ; dst = '%s')\n",
389 debugstr_w(cabinet
), debugstr_w(root
), debugstr_w(src
), debugstr_w(dst
));
391 /* make sure the cabinet file has a .cab extension */
392 if (len
<= 4 || strcmpiW( cabinet
+ len
- 4, extW
)) return FALSE
;
396 if (!advpack
&& !(advpack
= LoadLibraryA( "advpack.dll" )))
398 ERR( "could not load advpack.dll\n" );
401 if (!(pExtractFiles
= (void *)GetProcAddress( advpack
, "ExtractFiles" )))
403 ERR( "could not find ExtractFiles in advpack.dll\n" );
408 if (!(cab_path
= strdupWtoA( root
))) return FALSE
;
409 len
= WideCharToMultiByte( CP_ACP
, 0, cabinet
, -1, NULL
, 0, NULL
, NULL
);
410 if (!(cab_file
= HeapAlloc( GetProcessHeap(), 0, strlen(cab_path
) + len
+ 1 )))
412 HeapFree( GetProcessHeap(), 0, cab_path
);
415 strcpy( cab_file
, cab_path
);
416 if (cab_file
[0] && cab_file
[strlen(cab_file
)-1] != '\\') strcat( cab_file
, "\\" );
417 WideCharToMultiByte( CP_ACP
, 0, cabinet
, -1, cab_file
+ strlen(cab_file
), len
, NULL
, NULL
);
418 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file
) );
424 const WCHAR
*src_fileW
;
425 WCHAR TempPath
[MAX_PATH
];
427 /* Retrieve the temporary path */
428 if (!GetTempPathW(ARRAYSIZE(TempPath
), TempPath
))
430 ERR("GetTempPathW error\n");
431 HeapFree( GetProcessHeap(), 0, cab_file
);
435 /* Build the real path to where the file will be extracted */
436 HeapFree( GetProcessHeap(), 0, cab_path
);
437 if (!(cab_path
= strdupWtoA( TempPath
)))
439 HeapFree( GetProcessHeap(), 0, cab_file
);
443 /* Build the file list */
444 src_fileW
= strrchrW(src
, '\\'); // Find where the filename starts.
445 if (src_fileW
) ++src_fileW
;
446 else src_fileW
= src
;
447 /* Convert to ANSI */
448 if (!(src_file
= strdupWtoA( src_fileW
)))
450 HeapFree( GetProcessHeap(), 0, cab_file
);
451 HeapFree( GetProcessHeap(), 0, cab_path
);
455 /* Prepare for the move operation */
456 /* Build the full path to the extracted file, that will be renamed */
457 if (!(src
= HeapAlloc( GetProcessHeap(), 0, (strlenW(TempPath
) + 1 + strlenW(src_fileW
) + 1) * sizeof(WCHAR
) )))
459 HeapFree( GetProcessHeap(), 0, src_file
);
460 HeapFree( GetProcessHeap(), 0, cab_file
);
461 HeapFree( GetProcessHeap(), 0, cab_path
);
464 concat_W( (WCHAR
*)src
, NULL
, TempPath
, src_fileW
);
466 TRACE("pExtractFiles(cab_file = '%s' ; cab_path = '%s', src_file = '%s')\n",
467 debugstr_a(cab_file
), debugstr_a(cab_path
), debugstr_a(src_file
));
469 /* Extract to temporary folder */
470 pExtractFiles( cab_file
, cab_path
, 0, src_file
, NULL
, 0 );
471 HeapFree( GetProcessHeap(), 0, src_file
);
472 HeapFree( GetProcessHeap(), 0, cab_file
);
473 HeapFree( GetProcessHeap(), 0, cab_path
);
475 /* Move to destination, overwriting the original file if needed */
476 TRACE("Renaming src = '%s' to dst = '%s')\n", debugstr_w(src
), debugstr_w(dst
));
477 Success
= MoveFileExW( src
, dst
, MOVEFILE_REPLACE_EXISTING
| MOVEFILE_COPY_ALLOWED
);
478 HeapFree( GetProcessHeap(), 0, (WCHAR
*)src
);
482 pExtractFiles( cab_file
, cab_path
, 0, 0, 0, 0 );
483 HeapFree( GetProcessHeap(), 0, cab_file
);
484 HeapFree( GetProcessHeap(), 0, cab_path
);
485 return CopyFileW( src
, dst
, FALSE
/*FIXME*/ );
490 /***********************************************************************
491 * SetupOpenFileQueue (SETUPAPI.@)
493 HSPFILEQ WINAPI
SetupOpenFileQueue(void)
495 struct file_queue
*queue
;
497 if (!(queue
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*queue
))))
498 return INVALID_HANDLE_VALUE
;
503 /***********************************************************************
504 * SetupCloseFileQueue (SETUPAPI.@)
506 BOOL WINAPI
SetupCloseFileQueue( HSPFILEQ handle
)
508 struct file_queue
*queue
= handle
;
510 free_file_op_queue( &queue
->copy_queue
);
511 free_file_op_queue( &queue
->rename_queue
);
512 free_file_op_queue( &queue
->delete_queue
);
513 HeapFree( GetProcessHeap(), 0, queue
);
518 /***********************************************************************
519 * SetupQueueCopyIndirectA (SETUPAPI.@)
521 BOOL WINAPI
SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params
)
523 struct file_queue
*queue
= params
->QueueHandle
;
526 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
527 op
->style
= params
->CopyStyle
;
528 op
->src_root
= strdupAtoW( params
->SourceRootPath
);
529 op
->src_path
= strdupAtoW( params
->SourcePath
);
530 op
->src_file
= strdupAtoW( params
->SourceFilename
);
531 op
->src_descr
= strdupAtoW( params
->SourceDescription
);
532 op
->src_tag
= strdupAtoW( params
->SourceTagfile
);
533 op
->dst_path
= strdupAtoW( params
->TargetDirectory
);
534 op
->dst_file
= strdupAtoW( params
->TargetFilename
);
538 if (!op
->src_file
) op
->src_file
= op
->dst_file
;
539 if (params
->LayoutInf
)
541 get_src_file_info( params
->LayoutInf
, op
);
542 if (!op
->dst_path
) op
->dst_path
= get_destination_dir( params
->LayoutInf
, op
->dst_file
);
545 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
546 debugstr_w(op
->src_root
), debugstr_w(op
->src_path
), debugstr_w(op
->src_file
),
547 debugstr_w(op
->dst_path
), debugstr_w(op
->dst_file
),
548 debugstr_w(op
->src_descr
), debugstr_w(op
->src_tag
) );
550 queue_file_op( &queue
->copy_queue
, op
);
555 /***********************************************************************
556 * SetupQueueCopyIndirectW (SETUPAPI.@)
558 BOOL WINAPI
SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params
)
560 struct file_queue
*queue
= params
->QueueHandle
;
563 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
564 op
->style
= params
->CopyStyle
;
565 op
->src_root
= strdupW( params
->SourceRootPath
);
566 op
->src_path
= strdupW( params
->SourcePath
);
567 op
->src_file
= strdupW( params
->SourceFilename
);
568 op
->src_descr
= strdupW( params
->SourceDescription
);
569 op
->src_tag
= strdupW( params
->SourceTagfile
);
570 op
->dst_path
= strdupW( params
->TargetDirectory
);
571 op
->dst_file
= strdupW( params
->TargetFilename
);
573 if (params
->SecurityDescriptor
)
574 ConvertStringSecurityDescriptorToSecurityDescriptorW( params
->SecurityDescriptor
, SDDL_REVISION_1
, &op
->dst_sd
, NULL
);
577 if (!op
->src_file
) op
->src_file
= op
->dst_file
;
578 if (params
->LayoutInf
)
580 get_src_file_info( params
->LayoutInf
, op
);
581 if (!op
->dst_path
) op
->dst_path
= get_destination_dir( params
->LayoutInf
, op
->dst_file
);
584 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
585 debugstr_w(op
->src_root
), debugstr_w(op
->src_path
), debugstr_w(op
->src_file
),
586 debugstr_w(op
->dst_path
), debugstr_w(op
->dst_file
),
587 debugstr_w(op
->src_descr
), debugstr_w(op
->src_tag
) );
589 queue_file_op( &queue
->copy_queue
, op
);
594 /***********************************************************************
595 * SetupQueueCopyA (SETUPAPI.@)
597 BOOL WINAPI
SetupQueueCopyA( HSPFILEQ queue
, PCSTR src_root
, PCSTR src_path
, PCSTR src_file
,
598 PCSTR src_descr
, PCSTR src_tag
, PCSTR dst_dir
, PCSTR dst_file
,
601 SP_FILE_COPY_PARAMS_A params
;
603 params
.cbSize
= sizeof(params
);
604 params
.QueueHandle
= queue
;
605 params
.SourceRootPath
= src_root
;
606 params
.SourcePath
= src_path
;
607 params
.SourceFilename
= src_file
;
608 params
.SourceDescription
= src_descr
;
609 params
.SourceTagfile
= src_tag
;
610 params
.TargetDirectory
= dst_dir
;
611 params
.TargetFilename
= dst_file
;
612 params
.CopyStyle
= style
;
613 params
.LayoutInf
= 0;
614 params
.SecurityDescriptor
= NULL
;
615 return SetupQueueCopyIndirectA( ¶ms
);
619 /***********************************************************************
620 * SetupQueueCopyW (SETUPAPI.@)
622 BOOL WINAPI
SetupQueueCopyW( HSPFILEQ queue
, PCWSTR src_root
, PCWSTR src_path
, PCWSTR src_file
,
623 PCWSTR src_descr
, PCWSTR src_tag
, PCWSTR dst_dir
, PCWSTR dst_file
,
626 SP_FILE_COPY_PARAMS_W params
;
628 params
.cbSize
= sizeof(params
);
629 params
.QueueHandle
= queue
;
630 params
.SourceRootPath
= src_root
;
631 params
.SourcePath
= src_path
;
632 params
.SourceFilename
= src_file
;
633 params
.SourceDescription
= src_descr
;
634 params
.SourceTagfile
= src_tag
;
635 params
.TargetDirectory
= dst_dir
;
636 params
.TargetFilename
= dst_file
;
637 params
.CopyStyle
= style
;
638 params
.LayoutInf
= 0;
639 params
.SecurityDescriptor
= NULL
;
640 return SetupQueueCopyIndirectW( ¶ms
);
644 /***********************************************************************
645 * SetupQueueDefaultCopyA (SETUPAPI.@)
647 BOOL WINAPI
SetupQueueDefaultCopyA( HSPFILEQ queue
, HINF hinf
, PCSTR src_root
, PCSTR src_file
,
648 PCSTR dst_file
, DWORD style
)
650 SP_FILE_COPY_PARAMS_A params
;
652 params
.cbSize
= sizeof(params
);
653 params
.QueueHandle
= queue
;
654 params
.SourceRootPath
= src_root
;
655 params
.SourcePath
= NULL
;
656 params
.SourceFilename
= src_file
;
657 params
.SourceDescription
= NULL
;
658 params
.SourceTagfile
= NULL
;
659 params
.TargetDirectory
= NULL
;
660 params
.TargetFilename
= dst_file
;
661 params
.CopyStyle
= style
;
662 params
.LayoutInf
= hinf
;
663 params
.SecurityDescriptor
= NULL
;
664 return SetupQueueCopyIndirectA( ¶ms
);
668 /***********************************************************************
669 * SetupQueueDefaultCopyW (SETUPAPI.@)
671 BOOL WINAPI
SetupQueueDefaultCopyW( HSPFILEQ queue
, HINF hinf
, PCWSTR src_root
, PCWSTR src_file
,
672 PCWSTR dst_file
, DWORD style
)
674 SP_FILE_COPY_PARAMS_W params
;
676 params
.cbSize
= sizeof(params
);
677 params
.QueueHandle
= queue
;
678 params
.SourceRootPath
= src_root
;
679 params
.SourcePath
= NULL
;
680 params
.SourceFilename
= src_file
;
681 params
.SourceDescription
= NULL
;
682 params
.SourceTagfile
= NULL
;
683 params
.TargetDirectory
= NULL
;
684 params
.TargetFilename
= dst_file
;
685 params
.CopyStyle
= style
;
686 params
.LayoutInf
= hinf
;
687 params
.SecurityDescriptor
= NULL
;
688 return SetupQueueCopyIndirectW( ¶ms
);
692 /***********************************************************************
693 * SetupQueueDeleteA (SETUPAPI.@)
695 BOOL WINAPI
SetupQueueDeleteA( HSPFILEQ handle
, PCSTR part1
, PCSTR part2
)
697 struct file_queue
*queue
= handle
;
700 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
705 op
->src_descr
= NULL
;
707 op
->dst_path
= strdupAtoW( part1
);
708 op
->dst_file
= strdupAtoW( part2
);
710 queue_file_op( &queue
->delete_queue
, op
);
715 /***********************************************************************
716 * SetupQueueDeleteW (SETUPAPI.@)
718 BOOL WINAPI
SetupQueueDeleteW( HSPFILEQ handle
, PCWSTR part1
, PCWSTR part2
)
720 struct file_queue
*queue
= handle
;
723 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
728 op
->src_descr
= NULL
;
730 op
->dst_path
= strdupW( part1
);
731 op
->dst_file
= strdupW( part2
);
733 queue_file_op( &queue
->delete_queue
, op
);
738 /***********************************************************************
739 * SetupQueueRenameA (SETUPAPI.@)
741 BOOL WINAPI
SetupQueueRenameA( HSPFILEQ handle
, PCSTR SourcePath
, PCSTR SourceFilename
,
742 PCSTR TargetPath
, PCSTR TargetFilename
)
744 struct file_queue
*queue
= handle
;
747 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
750 op
->src_path
= strdupAtoW( SourcePath
);
751 op
->src_file
= strdupAtoW( SourceFilename
);
752 op
->src_descr
= NULL
;
754 op
->dst_path
= strdupAtoW( TargetPath
);
755 op
->dst_file
= strdupAtoW( TargetFilename
);
757 queue_file_op( &queue
->rename_queue
, op
);
762 /***********************************************************************
763 * SetupQueueRenameW (SETUPAPI.@)
765 BOOL WINAPI
SetupQueueRenameW( HSPFILEQ handle
, PCWSTR SourcePath
, PCWSTR SourceFilename
,
766 PCWSTR TargetPath
, PCWSTR TargetFilename
)
768 struct file_queue
*queue
= handle
;
771 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
774 op
->src_path
= strdupW( SourcePath
);
775 op
->src_file
= strdupW( SourceFilename
);
776 op
->src_descr
= NULL
;
778 op
->dst_path
= strdupW( TargetPath
);
779 op
->dst_file
= strdupW( TargetFilename
);
781 queue_file_op( &queue
->rename_queue
, op
);
786 /***********************************************************************
787 * SetupQueueCopySectionA (SETUPAPI.@)
789 BOOL WINAPI
SetupQueueCopySectionA( HSPFILEQ queue
, PCSTR src_root
, HINF hinf
, HINF hlist
,
790 PCSTR section
, DWORD style
)
792 UNICODE_STRING sectionW
;
795 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
797 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
801 ret
= SetupQueueCopySectionW( queue
, NULL
, hinf
, hlist
, sectionW
.Buffer
, style
);
805 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
807 ret
= SetupQueueCopySectionW( queue
, srcW
.Buffer
, hinf
, hlist
, sectionW
.Buffer
, style
);
808 RtlFreeUnicodeString( &srcW
);
810 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
812 RtlFreeUnicodeString( §ionW
);
817 /***********************************************************************
818 * SetupQueueCopySectionW (SETUPAPI.@)
820 BOOL WINAPI
SetupQueueCopySectionW( HSPFILEQ queue
, PCWSTR src_root
, HINF hinf
, HINF hlist
,
821 PCWSTR section
, DWORD style
)
823 SP_FILE_COPY_PARAMS_W params
;
824 LPWSTR security_key
, security_descriptor
= NULL
;
825 INFCONTEXT context
, security_context
;
826 WCHAR dest
[MAX_PATH
], src
[MAX_PATH
];
831 TRACE( "hinf=%p/%p section=%s root=%s\n",
832 hinf
, hlist
, debugstr_w(section
), debugstr_w(src_root
) );
834 /* Check for .Security section */
835 security_key
= MyMalloc( (strlenW( section
) + strlenW( DotSecurity
)) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
) );
838 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
841 strcpyW( security_key
, section
);
842 strcatW( security_key
, DotSecurity
);
843 ret
= SetupFindFirstLineW( hinf
, security_key
, NULL
, &security_context
);
844 MyFree(security_key
);
847 if (!SetupGetLineTextW( &security_context
, NULL
, NULL
, NULL
, NULL
, 0, &required
))
849 security_descriptor
= MyMalloc( required
* sizeof(WCHAR
) );
850 if (!security_descriptor
)
852 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
855 if (!SetupGetLineTextW( &security_context
, NULL
, NULL
, NULL
, security_descriptor
, required
, NULL
))
857 MyFree( security_descriptor
);
862 params
.cbSize
= sizeof(params
);
863 params
.QueueHandle
= queue
;
864 params
.SourceRootPath
= src_root
;
865 params
.SourcePath
= NULL
;
866 params
.SourceDescription
= NULL
;
867 params
.SourceTagfile
= NULL
;
868 params
.TargetFilename
= dest
;
869 params
.CopyStyle
= style
;
870 params
.LayoutInf
= hinf
;
871 params
.SecurityDescriptor
= security_descriptor
;
874 if (!hlist
) hlist
= hinf
;
875 if (!hinf
) hinf
= hlist
;
876 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) goto done
;
877 if (!(params
.TargetDirectory
= get_destination_dir( hinf
, section
))) goto done
;
880 if (!SetupGetStringFieldW( &context
, 1, dest
, sizeof(dest
)/sizeof(WCHAR
), NULL
))
882 if (!SetupGetStringFieldW( &context
, 2, src
, sizeof(src
)/sizeof(WCHAR
), NULL
)) *src
= 0;
883 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0; /* FIXME */
885 params
.SourceFilename
= *src
? src
: NULL
;
886 if (!SetupQueueCopyIndirectW( ¶ms
)) goto done
;
887 } while (SetupFindNextLine( &context
, &context
));
891 if (security_descriptor
)
892 MyFree( security_descriptor
);
897 /***********************************************************************
898 * SetupQueueDeleteSectionA (SETUPAPI.@)
900 BOOL WINAPI
SetupQueueDeleteSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
902 UNICODE_STRING sectionW
;
905 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
907 ret
= SetupQueueDeleteSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
908 RtlFreeUnicodeString( §ionW
);
910 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
915 /***********************************************************************
916 * SetupQueueDeleteSectionW (SETUPAPI.@)
918 BOOL WINAPI
SetupQueueDeleteSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
922 WCHAR buffer
[MAX_PATH
];
926 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
928 if (!hlist
) hlist
= hinf
;
929 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
930 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
933 if (!SetupGetStringFieldW( &context
, 1, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
935 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
936 if (!SetupQueueDeleteW( queue
, dest_dir
, buffer
)) goto done
;
937 } while (SetupFindNextLine( &context
, &context
));
941 HeapFree( GetProcessHeap(), 0, dest_dir
);
946 /***********************************************************************
947 * SetupQueueRenameSectionA (SETUPAPI.@)
949 BOOL WINAPI
SetupQueueRenameSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
951 UNICODE_STRING sectionW
;
954 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
956 ret
= SetupQueueRenameSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
957 RtlFreeUnicodeString( §ionW
);
959 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
964 /***********************************************************************
965 * SetupQueueRenameSectionW (SETUPAPI.@)
967 BOOL WINAPI
SetupQueueRenameSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
971 WCHAR src
[MAX_PATH
], dst
[MAX_PATH
];
974 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
976 if (!hlist
) hlist
= hinf
;
977 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
978 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
981 if (!SetupGetStringFieldW( &context
, 1, dst
, sizeof(dst
)/sizeof(WCHAR
), NULL
))
983 if (!SetupGetStringFieldW( &context
, 2, src
, sizeof(src
)/sizeof(WCHAR
), NULL
))
985 if (!SetupQueueRenameW( queue
, dest_dir
, src
, NULL
, dst
)) goto done
;
986 } while (SetupFindNextLine( &context
, &context
));
990 HeapFree( GetProcessHeap(), 0, dest_dir
);
995 /***********************************************************************
996 * SetupCommitFileQueueA (SETUPAPI.@)
998 BOOL WINAPI
SetupCommitFileQueueA( HWND owner
, HSPFILEQ queue
, PSP_FILE_CALLBACK_A handler
,
1001 struct callback_WtoA_context ctx
;
1003 ctx
.orig_context
= context
;
1004 ctx
.orig_handler
= handler
;
1005 return SetupCommitFileQueueW( owner
, queue
, QUEUE_callback_WtoA
, &ctx
);
1009 /***********************************************************************
1012 * Recursively create all directories in the path.
1014 static BOOL
create_full_pathW(const WCHAR
*path
)
1020 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) * sizeof(WCHAR
));
1021 strcpyW(new_path
, path
);
1023 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
1024 new_path
[len
- 1] = 0;
1026 while(!CreateDirectoryW(new_path
, NULL
))
1029 DWORD last_error
= GetLastError();
1031 if(last_error
== ERROR_ALREADY_EXISTS
)
1034 if(last_error
!= ERROR_PATH_NOT_FOUND
)
1040 if(!(slash
= strrchrW(new_path
, '\\')))
1046 len
= slash
- new_path
;
1048 if(!create_full_pathW(new_path
))
1053 new_path
[len
] = '\\';
1056 HeapFree(GetProcessHeap(), 0, new_path
);
1060 static BOOL
do_file_copyW( LPCWSTR source
, LPCWSTR target
, DWORD style
,
1061 PSP_FILE_CALLBACK_W handler
, PVOID context
)
1068 WCHAR TempPath
[MAX_PATH
];
1069 WCHAR TempFile
[MAX_PATH
];
1074 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source
),debugstr_w(target
),style
);
1077 /* Get a temp file name */
1078 if (!GetTempPathW(ARRAYSIZE(TempPath
), TempPath
))
1080 ERR("GetTempPathW error\n");
1084 /* Try to open the source file */
1085 hSource
= LZOpenFileW((LPWSTR
)source
, &OfStruct
, OF_READ
);
1088 ERR("LZOpenFileW(1) error %d %s\n", (int)hSource
, debugstr_w(source
));
1092 if (!GetTempFileNameW(TempPath
, L
"", 0, TempFile
))
1094 dwLastError
= GetLastError();
1096 ERR("GetTempFileNameW(%s) error\n", debugstr_w(TempPath
));
1098 /* Close the source handle */
1101 /* Restore error condition triggered by GetTempFileNameW */
1102 SetLastError(dwLastError
);
1107 /* Extract the compressed file to a temp location */
1108 hTemp
= LZOpenFileW(TempFile
, &OfStruct
, OF_CREATE
);
1111 dwLastError
= GetLastError();
1113 ERR("LZOpenFileW(2) error %d %s\n", (int)hTemp
, debugstr_w(TempFile
));
1115 /* Close the source handle */
1118 /* Delete temp file if an error is signaled */
1119 DeleteFileW(TempFile
);
1121 /* Restore error condition triggered by LZOpenFileW */
1122 SetLastError(dwLastError
);
1127 lRes
= LZCopy(hSource
, hTemp
);
1129 dwLastError
= GetLastError();
1136 ERR("LZCopy error %d (%s, %s)\n", (int)lRes
, debugstr_w(source
), debugstr_w(TempFile
));
1138 /* Delete temp file if copy was not successful */
1139 DeleteFileW(TempFile
);
1141 /* Restore error condition triggered by LZCopy */
1142 SetLastError(dwLastError
);
1148 /* before copy processing */
1149 if (style
& SP_COPY_REPLACEONLY
)
1151 if (GetFileAttributesW(target
) == INVALID_FILE_ATTRIBUTES
)
1154 if (style
& (SP_COPY_NEWER_OR_SAME
| SP_COPY_NEWER_ONLY
| SP_COPY_FORCE_NEWER
))
1156 DWORD VersionSizeSource
=0;
1157 DWORD VersionSizeTarget
=0;
1161 * This is sort of an interesting workaround. You see, calling
1162 * GetVersionInfoSize on a builtin dll loads that dll into memory
1163 * and we do not properly unload builtin dlls.. so we effectively
1164 * lock into memory all the targets we are replacing. This leads
1165 * to problems when we try to register the replaced dlls.
1167 * So I will test for the existence of the files first so that
1168 * we just basically unconditionally replace the builtin versions.
1170 if ((GetFileAttributesW(target
) != INVALID_FILE_ATTRIBUTES
) &&
1171 (GetFileAttributesW(TempFile
) != INVALID_FILE_ATTRIBUTES
))
1173 VersionSizeSource
= GetFileVersionInfoSizeW(TempFile
,&zero
);
1174 VersionSizeTarget
= GetFileVersionInfoSizeW((LPWSTR
)target
,&zero
);
1177 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget
,
1180 if (VersionSizeSource
&& VersionSizeTarget
)
1182 LPVOID VersionSource
;
1183 LPVOID VersionTarget
;
1184 VS_FIXEDFILEINFO
*TargetInfo
;
1185 VS_FIXEDFILEINFO
*SourceInfo
;
1187 WCHAR SubBlock
[2]={'\\',0};
1190 VersionSource
= HeapAlloc(GetProcessHeap(),0,VersionSizeSource
);
1191 VersionTarget
= HeapAlloc(GetProcessHeap(),0,VersionSizeTarget
);
1193 ret
= GetFileVersionInfoW(TempFile
,0,VersionSizeSource
,VersionSource
);
1195 ret
= GetFileVersionInfoW((LPWSTR
)target
, 0, VersionSizeTarget
,
1200 ret
= VerQueryValueW(VersionSource
, SubBlock
,
1201 (LPVOID
*)&SourceInfo
, &length
);
1203 ret
= VerQueryValueW(VersionTarget
, SubBlock
,
1204 (LPVOID
*)&TargetInfo
, &length
);
1208 FILEPATHS_W filepaths
;
1210 TRACE("Versions: Source %i.%i target %i.%i\n",
1211 SourceInfo
->dwFileVersionMS
, SourceInfo
->dwFileVersionLS
,
1212 TargetInfo
->dwFileVersionMS
, TargetInfo
->dwFileVersionLS
);
1214 /* used in case of notification */
1215 filepaths
.Target
= target
;
1216 filepaths
.Source
= source
;
1217 filepaths
.Win32Error
= 0;
1218 filepaths
.Flags
= 0;
1220 if (TargetInfo
->dwFileVersionMS
> SourceInfo
->dwFileVersionMS
)
1223 docopy
= handler (context
, SPFILENOTIFY_TARGETNEWER
, (UINT_PTR
)&filepaths
, 0);
1227 else if ((TargetInfo
->dwFileVersionMS
== SourceInfo
->dwFileVersionMS
)
1228 && (TargetInfo
->dwFileVersionLS
> SourceInfo
->dwFileVersionLS
))
1231 docopy
= handler (context
, SPFILENOTIFY_TARGETNEWER
, (UINT_PTR
)&filepaths
, 0);
1235 else if ((style
& SP_COPY_NEWER_ONLY
) &&
1236 (TargetInfo
->dwFileVersionMS
==
1237 SourceInfo
->dwFileVersionMS
)
1238 &&(TargetInfo
->dwFileVersionLS
==
1239 SourceInfo
->dwFileVersionLS
))
1242 docopy
= handler (context
, SPFILENOTIFY_TARGETNEWER
, (UINT_PTR
)&filepaths
, 0);
1248 HeapFree(GetProcessHeap(),0,VersionSource
);
1249 HeapFree(GetProcessHeap(),0,VersionTarget
);
1252 if (style
& (SP_COPY_NOOVERWRITE
| SP_COPY_FORCE_NOOVERWRITE
))
1254 if (GetFileAttributesW(target
) != INVALID_FILE_ATTRIBUTES
)
1256 FIXME("Notify user target file exists\n");
1260 if (style
& (SP_COPY_NODECOMP
| SP_COPY_LANGUAGEAWARE
| SP_COPY_FORCE_IN_USE
|
1261 SP_COPY_IN_USE_NEEDS_REBOOT
| SP_COPY_NOSKIP
| SP_COPY_WARNIFSKIP
))
1263 ERR("Unsupported style(s) 0x%x\n",style
);
1268 rc
= MoveFileExW(TempFile
,target
,MOVEFILE_REPLACE_EXISTING
);
1269 TRACE("Did copy... rc was %i\n",rc
);
1272 /* after copy processing */
1273 if (style
& SP_COPY_DELETESOURCE
)
1276 DeleteFileW(source
);
1282 /***********************************************************************
1283 * SetupInstallFileA (SETUPAPI.@)
1285 BOOL WINAPI
SetupInstallFileA( HINF hinf
, PINFCONTEXT inf_context
, PCSTR source
, PCSTR root
,
1286 PCSTR dest
, DWORD style
, PSP_FILE_CALLBACK_A handler
, PVOID context
)
1289 struct callback_WtoA_context ctx
;
1290 UNICODE_STRING sourceW
, rootW
, destW
;
1292 TRACE("%p %p %s %s %s %x %p %p\n", hinf
, inf_context
, debugstr_a(source
), debugstr_a(root
),
1293 debugstr_a(dest
), style
, handler
, context
);
1295 sourceW
.Buffer
= rootW
.Buffer
= destW
.Buffer
= NULL
;
1296 if (source
&& !RtlCreateUnicodeStringFromAsciiz( &sourceW
, source
))
1298 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1301 if (root
&& !RtlCreateUnicodeStringFromAsciiz( &rootW
, root
))
1303 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1306 if (dest
&& !RtlCreateUnicodeStringFromAsciiz( &destW
, dest
))
1308 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1312 ctx
.orig_context
= context
;
1313 ctx
.orig_handler
= handler
;
1315 ret
= SetupInstallFileW( hinf
, inf_context
, sourceW
.Buffer
, rootW
.Buffer
, destW
.Buffer
, style
, QUEUE_callback_WtoA
, &ctx
);
1318 RtlFreeUnicodeString( &sourceW
);
1319 RtlFreeUnicodeString( &rootW
);
1320 RtlFreeUnicodeString( &destW
);
1324 /***********************************************************************
1325 * SetupInstallFileW (SETUPAPI.@)
1327 BOOL WINAPI
SetupInstallFileW( HINF hinf
, PINFCONTEXT inf_context
, PCWSTR source
, PCWSTR root
,
1328 PCWSTR dest
, DWORD style
, PSP_FILE_CALLBACK_W handler
, PVOID context
)
1330 static const WCHAR CopyFiles
[] = {'C','o','p','y','F','i','l','e','s',0};
1332 BOOL ret
, absolute
= (root
&& *root
&& !(style
& SP_COPY_SOURCE_ABSOLUTE
));
1333 WCHAR
*buffer
, *p
, *inf_source
= NULL
;
1336 TRACE("%p %p %s %s %s %x %p %p\n", hinf
, inf_context
, debugstr_w(source
), debugstr_w(root
),
1337 debugstr_w(dest
), style
, handler
, context
);
1346 if (!SetupFindFirstLineW( hinf
, CopyFiles
, NULL
, inf_context
)) return FALSE
;
1348 if (!SetupGetStringFieldW( inf_context
, 1, NULL
, 0, (PDWORD
) &len
)) return FALSE
;
1349 if (!(inf_source
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1351 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1354 if (!SetupGetStringFieldW( inf_context
, 1, inf_source
, len
, NULL
))
1356 HeapFree( GetProcessHeap(), 0, inf_source
);
1359 source
= inf_source
;
1363 SetLastError( ERROR_INVALID_PARAMETER
);
1367 len
= strlenW( source
) + 1;
1368 if (absolute
) len
+= strlenW( root
) + 1;
1370 if (!(p
= buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1372 HeapFree( GetProcessHeap(), 0, inf_source
);
1373 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1379 strcpyW( buffer
, root
);
1380 p
+= strlenW( buffer
);
1381 if (p
[-1] != '\\') *p
++ = '\\';
1383 while (*source
== '\\') source
++;
1384 strcpyW( p
, source
);
1386 ret
= do_file_copyW( buffer
, dest
, style
, handler
, context
);
1388 HeapFree( GetProcessHeap(), 0, inf_source
);
1389 HeapFree( GetProcessHeap(), 0, buffer
);
1393 /***********************************************************************
1394 * SetupCommitFileQueueW (SETUPAPI.@)
1396 BOOL WINAPI
SetupCommitFileQueueW( HWND owner
, HSPFILEQ handle
, PSP_FILE_CALLBACK_W handler
,
1399 struct file_queue
*queue
= handle
;
1401 BOOL result
= FALSE
;
1405 paths
.Source
= paths
.Target
= NULL
;
1407 if (!queue
->copy_queue
.count
&& !queue
->delete_queue
.count
&& !queue
->rename_queue
.count
)
1408 return TRUE
; /* nothing to do */
1410 if (!handler( context
, SPFILENOTIFY_STARTQUEUE
, (UINT_PTR
)owner
, 0 )) return FALSE
;
1412 /* perform deletes */
1414 if (queue
->delete_queue
.count
)
1416 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_DELETE
,
1417 queue
->delete_queue
.count
))) goto done
;
1418 for (op
= queue
->delete_queue
.head
; op
; op
= op
->next
)
1420 build_filepathsW( op
, &paths
);
1421 op_result
= handler( context
, SPFILENOTIFY_STARTDELETE
, (UINT_PTR
)&paths
, FILEOP_DELETE
);
1422 if (op_result
== FILEOP_ABORT
) goto done
;
1423 while (op_result
== FILEOP_DOIT
)
1425 TRACE( "deleting file %s\n", debugstr_w(paths
.Target
) );
1426 if (DeleteFileW( paths
.Target
)) break; /* success */
1427 paths
.Win32Error
= GetLastError();
1428 op_result
= handler( context
, SPFILENOTIFY_DELETEERROR
, (UINT_PTR
)&paths
, 0 );
1429 if (op_result
== FILEOP_ABORT
) goto done
;
1431 handler( context
, SPFILENOTIFY_ENDDELETE
, (UINT_PTR
)&paths
, 0 );
1433 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_DELETE
, 0 );
1436 /* perform renames */
1438 if (queue
->rename_queue
.count
)
1440 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_RENAME
,
1441 queue
->rename_queue
.count
))) goto done
;
1442 for (op
= queue
->rename_queue
.head
; op
; op
= op
->next
)
1444 build_filepathsW( op
, &paths
);
1445 op_result
= handler( context
, SPFILENOTIFY_STARTRENAME
, (UINT_PTR
)&paths
, FILEOP_RENAME
);
1446 if (op_result
== FILEOP_ABORT
) goto done
;
1447 while (op_result
== FILEOP_DOIT
)
1449 TRACE( "renaming file %s -> %s\n",
1450 debugstr_w(paths
.Source
), debugstr_w(paths
.Target
) );
1451 if (MoveFileW( paths
.Source
, paths
.Target
)) break; /* success */
1452 paths
.Win32Error
= GetLastError();
1453 op_result
= handler( context
, SPFILENOTIFY_RENAMEERROR
, (UINT_PTR
)&paths
, 0 );
1454 if (op_result
== FILEOP_ABORT
) goto done
;
1456 handler( context
, SPFILENOTIFY_ENDRENAME
, (UINT_PTR
)&paths
, 0 );
1458 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_RENAME
, 0 );
1461 /* perform copies */
1463 if (queue
->copy_queue
.count
)
1465 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_COPY
,
1466 queue
->copy_queue
.count
))) goto done
;
1467 for (op
= queue
->copy_queue
.head
; op
; op
= op
->next
)
1469 WCHAR newpath
[MAX_PATH
];
1471 build_filepathsW( op
, &paths
);
1472 op_result
= handler( context
, SPFILENOTIFY_STARTCOPY
, (UINT_PTR
)&paths
, FILEOP_COPY
);
1473 if (op_result
== FILEOP_ABORT
) goto done
;
1474 if (op_result
== FILEOP_NEWPATH
) op_result
= FILEOP_DOIT
;
1475 while (op_result
== FILEOP_DOIT
|| op_result
== FILEOP_NEWPATH
)
1477 TRACE( "copying file %s -> %s\n",
1478 debugstr_w( op_result
== FILEOP_NEWPATH
? newpath
: paths
.Source
),
1479 debugstr_w(paths
.Target
) );
1482 if (!create_full_pathW( op
->dst_path
))
1484 paths
.Win32Error
= GetLastError();
1485 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
,
1486 (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1487 if (op_result
== FILEOP_ABORT
) goto done
;
1490 if (do_file_copyW( op_result
== FILEOP_NEWPATH
? newpath
: paths
.Source
,
1491 paths
.Target
, op
->style
, handler
, context
)) break; /* success */
1492 /* try to extract it from the cabinet file */
1495 if (extract_cabinet_file( op
->src_tag
, op
->src_root
,
1496 paths
.Source
, paths
.Target
)) break;
1498 paths
.Win32Error
= GetLastError();
1499 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
,
1500 (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1501 if (op_result
== FILEOP_ABORT
) goto done
;
1505 PSID psidOwner
= NULL
, psidGroup
= NULL
;
1506 PACL pDacl
= NULL
, pSacl
= NULL
;
1507 SECURITY_INFORMATION security_info
= 0;
1508 BOOL present
, dummy
;
1510 if (GetSecurityDescriptorOwner( op
->dst_sd
, &psidOwner
, &dummy
) && psidOwner
)
1511 security_info
|= OWNER_SECURITY_INFORMATION
;
1512 if (GetSecurityDescriptorGroup( op
->dst_sd
, &psidGroup
, &dummy
) && psidGroup
)
1513 security_info
|= GROUP_SECURITY_INFORMATION
;
1514 if (GetSecurityDescriptorDacl( op
->dst_sd
, &present
, &pDacl
, &dummy
))
1515 security_info
|= DACL_SECURITY_INFORMATION
;
1516 if (GetSecurityDescriptorSacl( op
->dst_sd
, &present
, &pSacl
, &dummy
))
1517 security_info
|= DACL_SECURITY_INFORMATION
;
1518 SetNamedSecurityInfoW( (LPWSTR
)paths
.Target
, SE_FILE_OBJECT
, security_info
,
1519 psidOwner
, psidGroup
, pDacl
, pSacl
);
1520 /* Yes, ignore the return code... */
1522 handler( context
, SPFILENOTIFY_ENDCOPY
, (UINT_PTR
)&paths
, 0 );
1524 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_COPY
, 0 );
1531 handler( context
, SPFILENOTIFY_ENDQUEUE
, result
, 0 );
1532 HeapFree( GetProcessHeap(), 0, (void *)paths
.Source
);
1533 HeapFree( GetProcessHeap(), 0, (void *)paths
.Target
);
1538 /***********************************************************************
1539 * SetupScanFileQueueA (SETUPAPI.@)
1541 BOOL WINAPI
SetupScanFileQueueA( HSPFILEQ handle
, DWORD flags
, HWND window
,
1542 PSP_FILE_CALLBACK_A handler
, PVOID context
, PDWORD result
)
1544 struct callback_WtoA_context ctx
;
1546 TRACE("%p %x %p %p %p %p\n", handle
, flags
, window
, handler
, context
, result
);
1548 ctx
.orig_context
= context
;
1549 ctx
.orig_handler
= handler
;
1551 return SetupScanFileQueueW( handle
, flags
, window
, QUEUE_callback_WtoA
, &ctx
, result
);
1555 /***********************************************************************
1556 * SetupScanFileQueueW (SETUPAPI.@)
1558 BOOL WINAPI
SetupScanFileQueueW( HSPFILEQ handle
, DWORD flags
, HWND window
,
1559 PSP_FILE_CALLBACK_W handler
, PVOID context
, PDWORD result
)
1561 struct file_queue
*queue
= handle
;
1564 UINT notification
= 0;
1567 TRACE("%p %x %p %p %p %p\n", handle
, flags
, window
, handler
, context
, result
);
1571 if (!queue
->copy_queue
.count
) return TRUE
;
1573 if (flags
& SPQ_SCAN_USE_CALLBACK
) notification
= SPFILENOTIFY_QUEUESCAN
;
1574 else if (flags
& SPQ_SCAN_USE_CALLBACKEX
) notification
= SPFILENOTIFY_QUEUESCAN_EX
;
1576 if (flags
& ~(SPQ_SCAN_USE_CALLBACK
| SPQ_SCAN_USE_CALLBACKEX
))
1578 FIXME("flags %x not fully implemented\n", flags
);
1581 paths
.Source
= paths
.Target
= NULL
;
1583 for (op
= queue
->copy_queue
.head
; op
; op
= op
->next
)
1585 build_filepathsW( op
, &paths
);
1586 switch (notification
)
1588 case SPFILENOTIFY_QUEUESCAN
:
1589 /* FIXME: handle delay flag */
1590 if (handler( context
, notification
, (UINT_PTR
)paths
.Target
, 0 )) goto done
;
1592 case SPFILENOTIFY_QUEUESCAN_EX
:
1593 if (handler( context
, notification
, (UINT_PTR
)&paths
, 0 )) goto done
;
1596 ret
= TRUE
; goto done
;
1603 HeapFree( GetProcessHeap(), 0, (void *)paths
.Source
);
1604 HeapFree( GetProcessHeap(), 0, (void *)paths
.Target
);
1609 /***********************************************************************
1610 * SetupGetFileQueueCount (SETUPAPI.@)
1612 BOOL WINAPI
SetupGetFileQueueCount( HSPFILEQ handle
, UINT op
, PUINT result
)
1614 struct file_queue
*queue
= handle
;
1619 *result
= queue
->copy_queue
.count
;
1622 *result
= queue
->rename_queue
.count
;
1625 *result
= queue
->delete_queue
.count
;
1632 /***********************************************************************
1633 * SetupGetFileQueueFlags (SETUPAPI.@)
1635 BOOL WINAPI
SetupGetFileQueueFlags( HSPFILEQ handle
, PDWORD flags
)
1637 struct file_queue
*queue
= handle
;
1638 *flags
= queue
->flags
;
1643 /***********************************************************************
1644 * SetupSetFileQueueFlags (SETUPAPI.@)
1646 BOOL WINAPI
SetupSetFileQueueFlags( HSPFILEQ handle
, DWORD mask
, DWORD flags
)
1648 struct file_queue
*queue
= handle
;
1649 queue
->flags
= (queue
->flags
& ~mask
) | flags
;
1654 /***********************************************************************
1655 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1657 BOOL WINAPI
SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle
, PSP_ALTPLATFORM_INFO platform
, PCSTR catalogfile
)
1659 FIXME("(%p, %p, %s) stub!\n", handle
, platform
, debugstr_a(catalogfile
));
1664 /***********************************************************************
1665 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1667 BOOL WINAPI
SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle
, PSP_ALTPLATFORM_INFO platform
, PCWSTR catalogfile
)
1669 FIXME("(%p, %p, %s) stub!\n", handle
, platform
, debugstr_w(catalogfile
));
1674 /***********************************************************************
1675 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1677 PVOID WINAPI
SetupInitDefaultQueueCallback( HWND owner
)
1679 return SetupInitDefaultQueueCallbackEx( owner
, 0, 0, 0, NULL
);
1683 /***********************************************************************
1684 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1686 PVOID WINAPI
SetupInitDefaultQueueCallbackEx( HWND owner
, HWND progress
, UINT msg
,
1687 DWORD reserved1
, PVOID reserved2
)
1689 struct default_callback_context
*context
;
1691 if ((context
= HeapAlloc( GetProcessHeap(), 0, sizeof(*context
) )))
1693 context
->owner
= owner
;
1694 context
->progress
= progress
;
1695 context
->message
= msg
;
1701 /***********************************************************************
1702 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1704 void WINAPI
SetupTermDefaultQueueCallback( PVOID context
)
1706 HeapFree( GetProcessHeap(), 0, context
);
1710 /***********************************************************************
1711 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1713 UINT WINAPI
SetupDefaultQueueCallbackA( PVOID context
, UINT notification
,
1714 UINT_PTR param1
, UINT_PTR param2
)
1716 FILEPATHS_A
*paths
= (FILEPATHS_A
*)param1
;
1717 struct default_callback_context
*ctx
= (struct default_callback_context
*)context
;
1719 switch(notification
)
1721 case SPFILENOTIFY_STARTQUEUE
:
1722 TRACE( "start queue\n" );
1724 case SPFILENOTIFY_ENDQUEUE
:
1725 TRACE( "end queue\n" );
1727 case SPFILENOTIFY_STARTSUBQUEUE
:
1728 TRACE( "start subqueue %ld count %ld\n", param1
, param2
);
1730 case SPFILENOTIFY_ENDSUBQUEUE
:
1731 TRACE( "end subqueue %ld\n", param1
);
1733 case SPFILENOTIFY_STARTDELETE
:
1734 TRACE( "start delete %s\n", debugstr_a(paths
->Target
) );
1736 case SPFILENOTIFY_ENDDELETE
:
1737 TRACE( "end delete %s\n", debugstr_a(paths
->Target
) );
1739 case SPFILENOTIFY_DELETEERROR
:
1740 /*Windows Ignores attempts to delete files / folders which do not exist*/
1741 if ((paths
->Win32Error
!= ERROR_FILE_NOT_FOUND
) && (paths
->Win32Error
!= ERROR_PATH_NOT_FOUND
))
1742 SetupDeleteErrorA(ctx
->owner
, NULL
, paths
->Target
, paths
->Win32Error
, 0);
1744 case SPFILENOTIFY_STARTRENAME
:
1745 TRACE( "start rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1747 case SPFILENOTIFY_ENDRENAME
:
1748 TRACE( "end rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1750 case SPFILENOTIFY_RENAMEERROR
:
1751 SetupRenameErrorA(ctx
->owner
, NULL
, paths
->Source
, paths
->Target
, paths
->Win32Error
, 0);
1753 case SPFILENOTIFY_STARTCOPY
:
1754 TRACE( "start copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1756 case SPFILENOTIFY_ENDCOPY
:
1757 TRACE( "end copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1759 case SPFILENOTIFY_COPYERROR
:
1760 ERR( "copy error %d %s -> %s\n", paths
->Win32Error
,
1761 debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1763 case SPFILENOTIFY_NEEDMEDIA
:
1764 TRACE( "need media\n" );
1767 FIXME( "notification %d params %lx,%lx\n", notification
, param1
, param2
);
1774 /***********************************************************************
1775 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1777 UINT WINAPI
SetupDefaultQueueCallbackW( PVOID context
, UINT notification
,
1778 UINT_PTR param1
, UINT_PTR param2
)
1780 FILEPATHS_W
*paths
= (FILEPATHS_W
*)param1
;
1781 struct default_callback_context
*ctx
= (struct default_callback_context
*)context
;
1783 switch(notification
)
1785 case SPFILENOTIFY_STARTQUEUE
:
1786 TRACE( "start queue\n" );
1788 case SPFILENOTIFY_ENDQUEUE
:
1789 TRACE( "end queue\n" );
1791 case SPFILENOTIFY_STARTSUBQUEUE
:
1792 TRACE( "start subqueue %ld count %ld\n", param1
, param2
);
1794 case SPFILENOTIFY_ENDSUBQUEUE
:
1795 TRACE( "end subqueue %ld\n", param1
);
1797 case SPFILENOTIFY_STARTDELETE
:
1798 TRACE( "start delete %s\n", debugstr_w(paths
->Target
) );
1800 case SPFILENOTIFY_ENDDELETE
:
1801 TRACE( "end delete %s\n", debugstr_w(paths
->Target
) );
1803 case SPFILENOTIFY_DELETEERROR
:
1804 /*Windows Ignores attempts to delete files / folders which do not exist*/
1805 if ((paths
->Win32Error
!= ERROR_FILE_NOT_FOUND
) && (paths
->Win32Error
!= ERROR_PATH_NOT_FOUND
))
1806 SetupDeleteErrorW(ctx
->owner
, NULL
, paths
->Target
, paths
->Win32Error
, 0);
1808 case SPFILENOTIFY_STARTRENAME
:
1809 SetupRenameErrorW(ctx
->owner
, NULL
, paths
->Source
, paths
->Target
, paths
->Win32Error
, 0);
1811 case SPFILENOTIFY_ENDRENAME
:
1812 TRACE( "end rename %s -> %s\n", debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1814 case SPFILENOTIFY_RENAMEERROR
:
1815 ERR( "rename error %d %s -> %s\n", paths
->Win32Error
,
1816 debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1818 case SPFILENOTIFY_STARTCOPY
:
1819 TRACE( "start copy %s -> %s\n", debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1821 case SPFILENOTIFY_ENDCOPY
:
1822 TRACE( "end copy %s -> %s\n", debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1824 case SPFILENOTIFY_COPYERROR
:
1825 ERR( "copy error %d %s -> %s\n", paths
->Win32Error
,
1826 debugstr_w(paths
->Source
), debugstr_w(paths
->Target
) );
1828 case SPFILENOTIFY_NEEDMEDIA
:
1829 TRACE( "need media\n" );
1832 FIXME( "notification %d params %lx,%lx\n", notification
, param1
, param2
);
1838 /***********************************************************************
1839 * SetupDeleteErrorA (SETUPAPI.@)
1842 UINT WINAPI
SetupDeleteErrorA( HWND parent
, PCSTR dialogTitle
, PCSTR file
,
1843 UINT w32error
, DWORD style
)
1845 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1846 w32error
, debugstr_a(file
) );
1847 return DPROMPT_SKIPFILE
;
1850 /***********************************************************************
1851 * SetupDeleteErrorW (SETUPAPI.@)
1854 UINT WINAPI
SetupDeleteErrorW( HWND parent
, PCWSTR dialogTitle
, PCWSTR file
,
1855 UINT w32error
, DWORD style
)
1857 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1858 w32error
, debugstr_w(file
) );
1859 return DPROMPT_SKIPFILE
;
1862 /***********************************************************************
1863 * SetupRenameErrorA (SETUPAPI.@)
1866 UINT WINAPI
SetupRenameErrorA( HWND parent
, PCSTR dialogTitle
, PCSTR source
,
1867 PCSTR target
, UINT w32error
, DWORD style
)
1869 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1870 w32error
, debugstr_a(source
), debugstr_a(target
));
1871 return DPROMPT_SKIPFILE
;
1874 /***********************************************************************
1875 * SetupRenameErrorW (SETUPAPI.@)
1878 UINT WINAPI
SetupRenameErrorW( HWND parent
, PCWSTR dialogTitle
, PCWSTR source
,
1879 PCWSTR target
, UINT w32error
, DWORD style
)
1881 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1882 w32error
, debugstr_w(source
), debugstr_w(target
));
1883 return DPROMPT_SKIPFILE
;
1887 /***********************************************************************
1888 * SetupCopyErrorA (SETUPAPI.@)
1891 UINT WINAPI
SetupCopyErrorA( HWND parent
, PCSTR dialogTitle
, PCSTR diskname
,
1892 PCSTR sourcepath
, PCSTR sourcefile
, PCSTR targetpath
,
1893 UINT w32error
, DWORD style
, PSTR pathbuffer
,
1894 DWORD buffersize
, PDWORD requiredsize
)
1896 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1897 w32error
, debugstr_a(sourcefile
), debugstr_a(sourcepath
) ,debugstr_a(targetpath
));
1898 return DPROMPT_SKIPFILE
;
1901 /***********************************************************************
1902 * SetupCopyErrorW (SETUPAPI.@)
1905 UINT WINAPI
SetupCopyErrorW( HWND parent
, PCWSTR dialogTitle
, PCWSTR diskname
,
1906 PCWSTR sourcepath
, PCWSTR sourcefile
, PCWSTR targetpath
,
1907 UINT w32error
, DWORD style
, PWSTR pathbuffer
,
1908 DWORD buffersize
, PDWORD requiredsize
)
1910 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1911 w32error
, debugstr_w(sourcefile
), debugstr_w(sourcepath
) ,debugstr_w(targetpath
));
1912 return DPROMPT_SKIPFILE
;
1915 /***********************************************************************
1916 * pSetupGetQueueFlags (SETUPAPI.@)
1918 DWORD WINAPI
pSetupGetQueueFlags( HSPFILEQ handle
)
1920 struct file_queue
*queue
= handle
;
1921 return queue
->flags
;
1924 /***********************************************************************
1925 * pSetupSetQueueFlags (SETUPAPI.@)
1927 BOOL WINAPI
pSetupSetQueueFlags( HSPFILEQ handle
, DWORD flags
)
1929 struct file_queue
*queue
= handle
;
1930 queue
->flags
= flags
;