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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/unicode.h"
27 #include "setupapi_private.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
32 /* context structure for the default queue callback */
33 struct default_callback_context
62 struct file_op_queue copy_queue
;
63 struct file_op_queue delete_queue
;
64 struct file_op_queue rename_queue
;
69 inline static WCHAR
*strdupW( const WCHAR
*str
)
74 int len
= (strlenW(str
) + 1) * sizeof(WCHAR
);
75 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
))) memcpy( ret
, str
, len
);
81 inline static WCHAR
*strdupAtoW( const char *str
)
86 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
87 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
88 MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
93 inline static char *strdupWtoA( const WCHAR
*str
)
98 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
99 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
)))
100 WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
105 /* append a file operation to a queue */
106 inline static void queue_file_op( struct file_op_queue
*queue
, struct file_op
*op
)
109 if (queue
->tail
) queue
->tail
->next
= op
;
110 else queue
->head
= op
;
115 /* free all the file operations on a given queue */
116 static void free_file_op_queue( struct file_op_queue
*queue
)
118 struct file_op
*t
, *op
= queue
->head
;
122 HeapFree( GetProcessHeap(), 0, op
->src_root
);
123 HeapFree( GetProcessHeap(), 0, op
->src_path
);
124 HeapFree( GetProcessHeap(), 0, op
->src_file
);
125 HeapFree( GetProcessHeap(), 0, op
->src_descr
);
126 HeapFree( GetProcessHeap(), 0, op
->src_tag
);
127 HeapFree( GetProcessHeap(), 0, op
->dst_path
);
128 if (op
->dst_file
!= op
->src_file
) HeapFree( GetProcessHeap(), 0, op
->dst_file
);
131 HeapFree( GetProcessHeap(), 0, t
);
135 /* concat 3 strings to make a path, handling separators correctly */
136 static void concat_W( WCHAR
*buffer
, const WCHAR
*src1
, const WCHAR
*src2
, const WCHAR
*src3
)
141 strcpyW( buffer
, src1
);
142 buffer
+= strlenW(buffer
);
143 if (buffer
[-1] != '\\') *buffer
++ = '\\';
144 if (src2
) while (*src2
== '\\') src2
++;
149 strcpyW( buffer
, src2
);
150 buffer
+= strlenW(buffer
);
151 if (buffer
[-1] != '\\') *buffer
++ = '\\';
152 if (src3
) while (*src3
== '\\') src3
++;
156 strcpyW( buffer
, src3
);
157 buffer
+= strlenW(buffer
);
162 /***********************************************************************
165 * Build a FILEPATHS_W structure for a given file operation.
167 static BOOL
build_filepathsW( const struct file_op
*op
, FILEPATHS_W
*paths
)
169 int src_len
= 1, dst_len
= 1;
170 WCHAR
*source
= (PWSTR
)paths
->Source
, *target
= (PWSTR
)paths
->Target
;
172 if (op
->src_root
) src_len
+= strlenW(op
->src_root
) + 1;
173 if (op
->src_path
) src_len
+= strlenW(op
->src_path
) + 1;
174 if (op
->src_file
) src_len
+= strlenW(op
->src_file
) + 1;
175 if (op
->dst_path
) dst_len
+= strlenW(op
->dst_path
) + 1;
176 if (op
->dst_file
) dst_len
+= strlenW(op
->dst_file
) + 1;
177 src_len
*= sizeof(WCHAR
);
178 dst_len
*= sizeof(WCHAR
);
180 if (!source
|| HeapSize( GetProcessHeap(), 0, source
) < src_len
)
182 HeapFree( GetProcessHeap(), 0, source
);
183 paths
->Source
= source
= HeapAlloc( GetProcessHeap(), 0, src_len
);
185 if (!target
|| HeapSize( GetProcessHeap(), 0, target
) < dst_len
)
187 HeapFree( GetProcessHeap(), 0, target
);
188 paths
->Target
= target
= HeapAlloc( GetProcessHeap(), 0, dst_len
);
190 if (!source
|| !target
) return FALSE
;
191 concat_W( source
, op
->src_root
, op
->src_path
, op
->src_file
);
192 concat_W( target
, NULL
, op
->dst_path
, op
->dst_file
);
193 paths
->Win32Error
= 0;
199 /***********************************************************************
200 * QUEUE_callback_WtoA
202 * Map a file callback parameters from W to A and call the A callback.
204 UINT CALLBACK
QUEUE_callback_WtoA( void *context
, UINT notification
,
205 UINT_PTR param1
, UINT_PTR param2
)
207 struct callback_WtoA_context
*callback_ctx
= context
;
208 char buffer
[MAX_PATH
];
210 UINT_PTR old_param2
= param2
;
214 case SPFILENOTIFY_COPYERROR
:
215 param2
= (UINT_PTR
)&buffer
;
217 case SPFILENOTIFY_STARTDELETE
:
218 case SPFILENOTIFY_ENDDELETE
:
219 case SPFILENOTIFY_DELETEERROR
:
220 case SPFILENOTIFY_STARTRENAME
:
221 case SPFILENOTIFY_ENDRENAME
:
222 case SPFILENOTIFY_RENAMEERROR
:
223 case SPFILENOTIFY_STARTCOPY
:
224 case SPFILENOTIFY_ENDCOPY
:
226 FILEPATHS_W
*pathsW
= (FILEPATHS_W
*)param1
;
229 pathsA
.Source
= strdupWtoA( pathsW
->Source
);
230 pathsA
.Target
= strdupWtoA( pathsW
->Target
);
231 pathsA
.Win32Error
= pathsW
->Win32Error
;
232 pathsA
.Flags
= pathsW
->Flags
;
233 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
,
234 (UINT_PTR
)&pathsA
, param2
);
235 HeapFree( GetProcessHeap(), 0, (void *)pathsA
.Source
);
236 HeapFree( GetProcessHeap(), 0, (void *)pathsA
.Target
);
238 if (notification
== SPFILENOTIFY_COPYERROR
)
239 MultiByteToWideChar( CP_ACP
, 0, buffer
, -1, (WCHAR
*)old_param2
, MAX_PATH
);
242 case SPFILENOTIFY_NEEDMEDIA
:
243 case SPFILENOTIFY_QUEUESCAN
:
244 FIXME("mapping for %d not implemented\n",notification
);
245 case SPFILENOTIFY_STARTQUEUE
:
246 case SPFILENOTIFY_ENDQUEUE
:
247 case SPFILENOTIFY_STARTSUBQUEUE
:
248 case SPFILENOTIFY_ENDSUBQUEUE
:
250 ret
= callback_ctx
->orig_handler( callback_ctx
->orig_context
, notification
, param1
, param2
);
257 /***********************************************************************
260 * Retrieve the source file information for a given file.
262 static void get_src_file_info( HINF hinf
, struct file_op
*op
)
264 static const WCHAR SourceDisksNames
[] =
265 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
266 static const WCHAR SourceDisksFiles
[] =
267 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
269 INFCONTEXT file_ctx
, disk_ctx
;
273 /* find the SourceDisksFiles entry */
274 if (!SetupFindFirstLineW( hinf
, SourceDisksFiles
, op
->src_file
, &file_ctx
))
278 if ((op
->style
& (SP_COPY_SOURCE_ABSOLUTE
|SP_COPY_SOURCEPATH_ABSOLUTE
))) return;
279 /* no specific info, use .inf file source directory */
280 if (!op
->src_root
&& (dir
= DIRID_get_string( hinf
, DIRID_SRCPATH
)))
281 op
->src_root
= strdupW( dir
);
284 if (!SetupGetIntField( &file_ctx
, 1, &diskid
)) return;
286 /* now find the diskid in the SourceDisksNames section */
287 if (!SetupFindFirstLineW( hinf
, SourceDisksNames
, NULL
, &disk_ctx
)) return;
290 if (SetupGetIntField( &disk_ctx
, 0, &id
) && (id
== diskid
)) break;
291 if (!SetupFindNextLine( &disk_ctx
, &disk_ctx
)) return;
294 /* and fill in the missing info */
298 if (SetupGetStringFieldW( &disk_ctx
, 1, NULL
, 0, &len
) &&
299 (op
->src_descr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) )))
300 SetupGetStringFieldW( &disk_ctx
, 1, op
->src_descr
, len
, NULL
);
304 if (SetupGetStringFieldW( &disk_ctx
, 2, NULL
, 0, &len
) &&
305 (op
->src_tag
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) )))
306 SetupGetStringFieldW( &disk_ctx
, 2, op
->src_tag
, len
, NULL
);
308 if (!op
->src_path
&& !(op
->style
& SP_COPY_SOURCE_ABSOLUTE
))
310 if (!(op
->style
& SP_COPY_SOURCEPATH_ABSOLUTE
))
312 /* retrieve relative path for this disk */
313 if (!SetupGetStringFieldW( &disk_ctx
, 4, NULL
, 0, &len
)) len
= 0;
315 /* retrieve relative path for this file */
316 if (!SetupGetStringFieldW( &file_ctx
, 2, NULL
, 0, &len2
)) len2
= 0;
319 (op
->src_path
= HeapAlloc( GetProcessHeap(), 0, (len
+len2
)*sizeof(WCHAR
) )))
321 WCHAR
*ptr
= op
->src_path
;
324 SetupGetStringFieldW( &disk_ctx
, 4, op
->src_path
, len
, NULL
);
325 ptr
= op
->src_path
+ strlenW(op
->src_path
);
326 if (len2
&& ptr
> op
->src_path
&& ptr
[-1] != '\\') *ptr
++ = '\\';
328 if (!SetupGetStringFieldW( &disk_ctx
, 4, ptr
, len2
, NULL
)) *ptr
= 0;
331 if (!op
->src_root
) op
->src_root
= strdupW( PARSER_get_src_root(hinf
) );
335 /***********************************************************************
336 * get_destination_dir
338 * Retrieve the destination dir for a given section.
340 static WCHAR
*get_destination_dir( HINF hinf
, const WCHAR
*section
)
342 static const WCHAR Dest
[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
343 static const WCHAR Def
[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
351 if (!SetupFindFirstLineW( hinf
, Dest
, section
, &context
) &&
352 !SetupFindFirstLineW( hinf
, Dest
, Def
, &context
)) return NULL
;
353 if (!SetupGetIntField( &context
, 1, &dirid
)) return NULL
;
354 if (!(dir
= DIRID_get_string( hinf
, dirid
))) return NULL
;
355 len1
= strlenW(dir
) + 1;
356 if (!SetupGetStringFieldW( &context
, 2, NULL
, 0, &len2
)) len2
= 0;
357 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, (len1
+len2
) * sizeof(WCHAR
) ))) return NULL
;
359 ptr
= ret
+ strlenW(ret
);
360 if (len2
&& ptr
> ret
&& ptr
[-1] != '\\') *ptr
++ = '\\';
361 if (!SetupGetStringFieldW( &context
, 2, ptr
, len2
, NULL
)) *ptr
= 0;
366 static void (WINAPI
*pExtractFiles
)( LPSTR
, LPSTR
, DWORD
, DWORD
, DWORD
, DWORD
);
368 /***********************************************************************
369 * extract_cabinet_file
371 * Extract a file from a .cab file.
373 static BOOL
extract_cabinet_file( const WCHAR
*cabinet
, const WCHAR
*root
,
374 const WCHAR
*src
, const WCHAR
*dst
)
376 static const WCHAR extW
[] = {'.','c','a','b',0};
377 static HMODULE advpack
;
379 char *cab_path
, *cab_file
;
380 int len
= strlenW( cabinet
);
382 /* make sure the cabinet file has a .cab extension */
383 if (len
<= 4 || strcmpiW( cabinet
+ len
- 4, extW
)) return FALSE
;
386 if (!advpack
&& !(advpack
= LoadLibraryA( "advpack.dll" )))
388 ERR( "could not load advpack.dll\n" );
391 if (!(pExtractFiles
= (void *)GetProcAddress( advpack
, "ExtractFiles" )))
393 ERR( "could not find ExtractFiles in advpack.dll\n" );
398 if (!(cab_path
= strdupWtoA( root
))) return FALSE
;
399 len
= WideCharToMultiByte( CP_ACP
, 0, cabinet
, -1, NULL
, 0, NULL
, NULL
);
400 if (!(cab_file
= HeapAlloc( GetProcessHeap(), 0, strlen(cab_path
) + len
+ 1 )))
402 HeapFree( GetProcessHeap(), 0, cab_path
);
405 strcpy( cab_file
, cab_path
);
406 if (cab_file
[0] && cab_file
[strlen(cab_file
)-1] != '\\') strcat( cab_file
, "\\" );
407 WideCharToMultiByte( CP_ACP
, 0, cabinet
, -1, cab_file
+ strlen(cab_file
), len
, NULL
, NULL
);
408 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file
) );
409 pExtractFiles( cab_file
, cab_path
, 0, 0, 0, 0 );
410 HeapFree( GetProcessHeap(), 0, cab_file
);
411 HeapFree( GetProcessHeap(), 0, cab_path
);
412 return CopyFileW( src
, dst
, FALSE
/*FIXME*/ );
416 /***********************************************************************
417 * SetupOpenFileQueue (SETUPAPI.@)
419 HSPFILEQ WINAPI
SetupOpenFileQueue(void)
421 struct file_queue
*queue
;
423 if (!(queue
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*queue
))))
424 return (HSPFILEQ
)INVALID_HANDLE_VALUE
;
429 /***********************************************************************
430 * SetupCloseFileQueue (SETUPAPI.@)
432 BOOL WINAPI
SetupCloseFileQueue( HSPFILEQ handle
)
434 struct file_queue
*queue
= handle
;
436 free_file_op_queue( &queue
->copy_queue
);
437 free_file_op_queue( &queue
->rename_queue
);
438 free_file_op_queue( &queue
->delete_queue
);
439 HeapFree( GetProcessHeap(), 0, queue
);
444 /***********************************************************************
445 * SetupQueueCopyIndirectA (SETUPAPI.@)
447 BOOL WINAPI
SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params
)
449 struct file_queue
*queue
= params
->QueueHandle
;
452 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
453 op
->style
= params
->CopyStyle
;
454 op
->src_root
= strdupAtoW( params
->SourceRootPath
);
455 op
->src_path
= strdupAtoW( params
->SourcePath
);
456 op
->src_file
= strdupAtoW( params
->SourceFilename
);
457 op
->src_descr
= strdupAtoW( params
->SourceDescription
);
458 op
->src_tag
= strdupAtoW( params
->SourceTagfile
);
459 op
->dst_path
= strdupAtoW( params
->TargetDirectory
);
460 op
->dst_file
= strdupAtoW( params
->TargetFilename
);
463 if (!op
->src_file
) op
->src_file
= op
->dst_file
;
464 if (params
->LayoutInf
)
466 get_src_file_info( params
->LayoutInf
, op
);
467 if (!op
->dst_path
) op
->dst_path
= get_destination_dir( params
->LayoutInf
, op
->dst_file
);
470 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
471 debugstr_w(op
->src_root
), debugstr_w(op
->src_path
), debugstr_w(op
->src_file
),
472 debugstr_w(op
->dst_path
), debugstr_w(op
->dst_file
),
473 debugstr_w(op
->src_descr
), debugstr_w(op
->src_tag
) );
475 queue_file_op( &queue
->copy_queue
, op
);
480 /***********************************************************************
481 * SetupQueueCopyIndirectW (SETUPAPI.@)
483 BOOL WINAPI
SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params
)
485 struct file_queue
*queue
= params
->QueueHandle
;
488 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
489 op
->style
= params
->CopyStyle
;
490 op
->src_root
= strdupW( params
->SourceRootPath
);
491 op
->src_path
= strdupW( params
->SourcePath
);
492 op
->src_file
= strdupW( params
->SourceFilename
);
493 op
->src_descr
= strdupW( params
->SourceDescription
);
494 op
->src_tag
= strdupW( params
->SourceTagfile
);
495 op
->dst_path
= strdupW( params
->TargetDirectory
);
496 op
->dst_file
= strdupW( params
->TargetFilename
);
499 if (!op
->src_file
) op
->src_file
= op
->dst_file
;
500 if (params
->LayoutInf
)
502 get_src_file_info( params
->LayoutInf
, op
);
503 if (!op
->dst_path
) op
->dst_path
= get_destination_dir( params
->LayoutInf
, op
->dst_file
);
506 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
507 debugstr_w(op
->src_root
), debugstr_w(op
->src_path
), debugstr_w(op
->src_file
),
508 debugstr_w(op
->dst_path
), debugstr_w(op
->dst_file
),
509 debugstr_w(op
->src_descr
), debugstr_w(op
->src_tag
) );
511 queue_file_op( &queue
->copy_queue
, op
);
516 /***********************************************************************
517 * SetupQueueCopyA (SETUPAPI.@)
519 BOOL WINAPI
SetupQueueCopyA( HSPFILEQ queue
, PCSTR src_root
, PCSTR src_path
, PCSTR src_file
,
520 PCSTR src_descr
, PCSTR src_tag
, PCSTR dst_dir
, PCSTR dst_file
,
523 SP_FILE_COPY_PARAMS_A params
;
525 params
.cbSize
= sizeof(params
);
526 params
.QueueHandle
= queue
;
527 params
.SourceRootPath
= src_root
;
528 params
.SourcePath
= src_path
;
529 params
.SourceFilename
= src_file
;
530 params
.SourceDescription
= src_descr
;
531 params
.SourceTagfile
= src_tag
;
532 params
.TargetDirectory
= dst_dir
;
533 params
.TargetFilename
= dst_file
;
534 params
.CopyStyle
= style
;
535 params
.LayoutInf
= 0;
536 params
.SecurityDescriptor
= NULL
;
537 return SetupQueueCopyIndirectA( ¶ms
);
541 /***********************************************************************
542 * SetupQueueCopyW (SETUPAPI.@)
544 BOOL WINAPI
SetupQueueCopyW( HSPFILEQ queue
, PCWSTR src_root
, PCWSTR src_path
, PCWSTR src_file
,
545 PCWSTR src_descr
, PCWSTR src_tag
, PCWSTR dst_dir
, PCWSTR dst_file
,
548 SP_FILE_COPY_PARAMS_W params
;
550 params
.cbSize
= sizeof(params
);
551 params
.QueueHandle
= queue
;
552 params
.SourceRootPath
= src_root
;
553 params
.SourcePath
= src_path
;
554 params
.SourceFilename
= src_file
;
555 params
.SourceDescription
= src_descr
;
556 params
.SourceTagfile
= src_tag
;
557 params
.TargetDirectory
= dst_dir
;
558 params
.TargetFilename
= dst_file
;
559 params
.CopyStyle
= style
;
560 params
.LayoutInf
= 0;
561 params
.SecurityDescriptor
= NULL
;
562 return SetupQueueCopyIndirectW( ¶ms
);
566 /***********************************************************************
567 * SetupQueueDefaultCopyA (SETUPAPI.@)
569 BOOL WINAPI
SetupQueueDefaultCopyA( HSPFILEQ queue
, HINF hinf
, PCSTR src_root
, PCSTR src_file
,
570 PCSTR dst_file
, DWORD style
)
572 SP_FILE_COPY_PARAMS_A params
;
574 params
.cbSize
= sizeof(params
);
575 params
.QueueHandle
= queue
;
576 params
.SourceRootPath
= src_root
;
577 params
.SourcePath
= NULL
;
578 params
.SourceFilename
= src_file
;
579 params
.SourceDescription
= NULL
;
580 params
.SourceTagfile
= NULL
;
581 params
.TargetDirectory
= NULL
;
582 params
.TargetFilename
= dst_file
;
583 params
.CopyStyle
= style
;
584 params
.LayoutInf
= hinf
;
585 params
.SecurityDescriptor
= NULL
;
586 return SetupQueueCopyIndirectA( ¶ms
);
590 /***********************************************************************
591 * SetupQueueDefaultCopyW (SETUPAPI.@)
593 BOOL WINAPI
SetupQueueDefaultCopyW( HSPFILEQ queue
, HINF hinf
, PCWSTR src_root
, PCWSTR src_file
,
594 PCWSTR dst_file
, DWORD style
)
596 SP_FILE_COPY_PARAMS_W params
;
598 params
.cbSize
= sizeof(params
);
599 params
.QueueHandle
= queue
;
600 params
.SourceRootPath
= src_root
;
601 params
.SourcePath
= NULL
;
602 params
.SourceFilename
= src_file
;
603 params
.SourceDescription
= NULL
;
604 params
.SourceTagfile
= NULL
;
605 params
.TargetDirectory
= NULL
;
606 params
.TargetFilename
= dst_file
;
607 params
.CopyStyle
= style
;
608 params
.LayoutInf
= hinf
;
609 params
.SecurityDescriptor
= NULL
;
610 return SetupQueueCopyIndirectW( ¶ms
);
614 /***********************************************************************
615 * SetupQueueDeleteA (SETUPAPI.@)
617 BOOL WINAPI
SetupQueueDeleteA( HSPFILEQ handle
, PCSTR part1
, PCSTR part2
)
619 struct file_queue
*queue
= handle
;
622 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
627 op
->src_descr
= NULL
;
629 op
->dst_path
= strdupAtoW( part1
);
630 op
->dst_file
= strdupAtoW( part2
);
631 queue_file_op( &queue
->delete_queue
, op
);
636 /***********************************************************************
637 * SetupQueueDeleteW (SETUPAPI.@)
639 BOOL WINAPI
SetupQueueDeleteW( HSPFILEQ handle
, PCWSTR part1
, PCWSTR part2
)
641 struct file_queue
*queue
= handle
;
644 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
649 op
->src_descr
= NULL
;
651 op
->dst_path
= strdupW( part1
);
652 op
->dst_file
= strdupW( part2
);
653 queue_file_op( &queue
->delete_queue
, op
);
658 /***********************************************************************
659 * SetupQueueRenameA (SETUPAPI.@)
661 BOOL WINAPI
SetupQueueRenameA( HSPFILEQ handle
, PCSTR SourcePath
, PCSTR SourceFilename
,
662 PCSTR TargetPath
, PCSTR TargetFilename
)
664 struct file_queue
*queue
= handle
;
667 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
670 op
->src_path
= strdupAtoW( SourcePath
);
671 op
->src_file
= strdupAtoW( SourceFilename
);
672 op
->src_descr
= NULL
;
674 op
->dst_path
= strdupAtoW( TargetPath
);
675 op
->dst_file
= strdupAtoW( TargetFilename
);
676 queue_file_op( &queue
->rename_queue
, op
);
681 /***********************************************************************
682 * SetupQueueRenameW (SETUPAPI.@)
684 BOOL WINAPI
SetupQueueRenameW( HSPFILEQ handle
, PCWSTR SourcePath
, PCWSTR SourceFilename
,
685 PCWSTR TargetPath
, PCWSTR TargetFilename
)
687 struct file_queue
*queue
= handle
;
690 if (!(op
= HeapAlloc( GetProcessHeap(), 0, sizeof(*op
) ))) return FALSE
;
693 op
->src_path
= strdupW( SourcePath
);
694 op
->src_file
= strdupW( SourceFilename
);
695 op
->src_descr
= NULL
;
697 op
->dst_path
= strdupW( TargetPath
);
698 op
->dst_file
= strdupW( TargetFilename
);
699 queue_file_op( &queue
->rename_queue
, op
);
704 /***********************************************************************
705 * SetupQueueCopySectionA (SETUPAPI.@)
707 BOOL WINAPI
SetupQueueCopySectionA( HSPFILEQ queue
, PCSTR src_root
, HINF hinf
, HINF hlist
,
708 PCSTR section
, DWORD style
)
710 UNICODE_STRING sectionW
;
713 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
715 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
719 ret
= SetupQueueCopySectionW( queue
, NULL
, hinf
, hlist
, sectionW
.Buffer
, style
);
723 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
725 ret
= SetupQueueCopySectionW( queue
, srcW
.Buffer
, hinf
, hlist
, sectionW
.Buffer
, style
);
726 RtlFreeUnicodeString( &srcW
);
728 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
730 RtlFreeUnicodeString( §ionW
);
735 /***********************************************************************
736 * SetupQueueCopySectionW (SETUPAPI.@)
738 BOOL WINAPI
SetupQueueCopySectionW( HSPFILEQ queue
, PCWSTR src_root
, HINF hinf
, HINF hlist
,
739 PCWSTR section
, DWORD style
)
741 SP_FILE_COPY_PARAMS_W params
;
743 WCHAR dest
[MAX_PATH
], src
[MAX_PATH
];
746 TRACE( "hinf=%p/%p section=%s root=%s\n",
747 hinf
, hlist
, debugstr_w(section
), debugstr_w(src_root
) );
749 params
.cbSize
= sizeof(params
);
750 params
.QueueHandle
= queue
;
751 params
.SourceRootPath
= src_root
;
752 params
.SourcePath
= NULL
;
753 params
.SourceDescription
= NULL
;
754 params
.SourceTagfile
= NULL
;
755 params
.TargetFilename
= dest
;
756 params
.CopyStyle
= style
;
757 params
.LayoutInf
= hinf
;
758 params
.SecurityDescriptor
= NULL
;
760 if (!hlist
) hlist
= hinf
;
761 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
762 if (!(params
.TargetDirectory
= get_destination_dir( hinf
, section
))) return FALSE
;
765 if (!SetupGetStringFieldW( &context
, 1, dest
, sizeof(dest
)/sizeof(WCHAR
), NULL
))
767 if (!SetupGetStringFieldW( &context
, 2, src
, sizeof(src
)/sizeof(WCHAR
), NULL
)) *src
= 0;
768 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0; /* FIXME */
770 params
.SourceFilename
= *src
? src
: NULL
;
771 if (!SetupQueueCopyIndirectW( ¶ms
)) return FALSE
;
772 } while (SetupFindNextLine( &context
, &context
));
777 /***********************************************************************
778 * SetupQueueDeleteSectionA (SETUPAPI.@)
780 BOOL WINAPI
SetupQueueDeleteSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
782 UNICODE_STRING sectionW
;
785 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
787 ret
= SetupQueueDeleteSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
788 RtlFreeUnicodeString( §ionW
);
790 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
795 /***********************************************************************
796 * SetupQueueDeleteSectionW (SETUPAPI.@)
798 BOOL WINAPI
SetupQueueDeleteSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
802 WCHAR buffer
[MAX_PATH
];
806 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
808 if (!hlist
) hlist
= hinf
;
809 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
810 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
813 if (!SetupGetStringFieldW( &context
, 1, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
815 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
816 if (!SetupQueueDeleteW( queue
, dest_dir
, buffer
)) goto done
;
817 } while (SetupFindNextLine( &context
, &context
));
821 HeapFree( GetProcessHeap(), 0, dest_dir
);
826 /***********************************************************************
827 * SetupQueueRenameSectionA (SETUPAPI.@)
829 BOOL WINAPI
SetupQueueRenameSectionA( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCSTR section
)
831 UNICODE_STRING sectionW
;
834 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
836 ret
= SetupQueueRenameSectionW( queue
, hinf
, hlist
, sectionW
.Buffer
);
837 RtlFreeUnicodeString( §ionW
);
839 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
844 /***********************************************************************
845 * SetupQueueRenameSectionW (SETUPAPI.@)
847 BOOL WINAPI
SetupQueueRenameSectionW( HSPFILEQ queue
, HINF hinf
, HINF hlist
, PCWSTR section
)
851 WCHAR src
[MAX_PATH
], dst
[MAX_PATH
];
854 TRACE( "hinf=%p/%p section=%s\n", hinf
, hlist
, debugstr_w(section
) );
856 if (!hlist
) hlist
= hinf
;
857 if (!SetupFindFirstLineW( hlist
, section
, NULL
, &context
)) return FALSE
;
858 if (!(dest_dir
= get_destination_dir( hinf
, section
))) return FALSE
;
861 if (!SetupGetStringFieldW( &context
, 1, dst
, sizeof(dst
)/sizeof(WCHAR
), NULL
))
863 if (!SetupGetStringFieldW( &context
, 2, src
, sizeof(src
)/sizeof(WCHAR
), NULL
))
865 if (!SetupQueueRenameW( queue
, dest_dir
, src
, NULL
, dst
)) goto done
;
866 } while (SetupFindNextLine( &context
, &context
));
870 HeapFree( GetProcessHeap(), 0, dest_dir
);
875 /***********************************************************************
876 * SetupCommitFileQueueA (SETUPAPI.@)
878 BOOL WINAPI
SetupCommitFileQueueA( HWND owner
, HSPFILEQ queue
, PSP_FILE_CALLBACK_A handler
,
881 struct callback_WtoA_context ctx
;
883 ctx
.orig_context
= context
;
884 ctx
.orig_handler
= handler
;
885 return SetupCommitFileQueueW( owner
, queue
, QUEUE_callback_WtoA
, &ctx
);
889 /***********************************************************************
892 * Recursively create all directories in the path.
894 static BOOL
create_full_pathW(const WCHAR
*path
)
900 new_path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(path
) + 1) * sizeof(WCHAR
));
901 strcpyW(new_path
, path
);
903 while((len
= strlenW(new_path
)) && new_path
[len
- 1] == '\\')
904 new_path
[len
- 1] = 0;
906 while(!CreateDirectoryW(new_path
, NULL
))
909 DWORD last_error
= GetLastError();
911 if(last_error
== ERROR_ALREADY_EXISTS
)
914 if(last_error
!= ERROR_PATH_NOT_FOUND
)
920 if(!(slash
= strrchrW(new_path
, '\\')))
926 len
= slash
- new_path
;
928 if(!create_full_pathW(new_path
))
933 new_path
[len
] = '\\';
936 HeapFree(GetProcessHeap(), 0, new_path
);
941 /***********************************************************************
942 * SetupCommitFileQueueW (SETUPAPI.@)
944 BOOL WINAPI
SetupCommitFileQueueW( HWND owner
, HSPFILEQ handle
, PSP_FILE_CALLBACK_W handler
,
947 struct file_queue
*queue
= handle
;
953 paths
.Source
= paths
.Target
= NULL
;
955 if (!queue
->copy_queue
.count
&& !queue
->delete_queue
.count
&& !queue
->rename_queue
.count
)
956 return TRUE
; /* nothing to do */
958 if (!handler( context
, SPFILENOTIFY_STARTQUEUE
, (UINT
)owner
, 0 )) return FALSE
;
960 /* perform deletes */
962 if (queue
->delete_queue
.count
)
964 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_DELETE
,
965 queue
->delete_queue
.count
))) goto done
;
966 for (op
= queue
->delete_queue
.head
; op
; op
= op
->next
)
968 build_filepathsW( op
, &paths
);
969 op_result
= handler( context
, SPFILENOTIFY_STARTDELETE
, (UINT_PTR
)&paths
, FILEOP_DELETE
);
970 if (op_result
== FILEOP_ABORT
) goto done
;
971 while (op_result
== FILEOP_DOIT
)
973 TRACE( "deleting file %s\n", debugstr_w(paths
.Target
) );
974 if (DeleteFileW( paths
.Target
)) break; /* success */
975 paths
.Win32Error
= GetLastError();
976 op_result
= handler( context
, SPFILENOTIFY_DELETEERROR
, (UINT_PTR
)&paths
, 0 );
977 if (op_result
== FILEOP_ABORT
) goto done
;
979 handler( context
, SPFILENOTIFY_ENDDELETE
, (UINT_PTR
)&paths
, 0 );
981 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_DELETE
, 0 );
984 /* perform renames */
986 if (queue
->rename_queue
.count
)
988 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_RENAME
,
989 queue
->rename_queue
.count
))) goto done
;
990 for (op
= queue
->rename_queue
.head
; op
; op
= op
->next
)
992 build_filepathsW( op
, &paths
);
993 op_result
= handler( context
, SPFILENOTIFY_STARTRENAME
, (UINT_PTR
)&paths
, FILEOP_RENAME
);
994 if (op_result
== FILEOP_ABORT
) goto done
;
995 while (op_result
== FILEOP_DOIT
)
997 TRACE( "renaming file %s -> %s\n",
998 debugstr_w(paths
.Source
), debugstr_w(paths
.Target
) );
999 if (MoveFileW( paths
.Source
, paths
.Target
)) break; /* success */
1000 paths
.Win32Error
= GetLastError();
1001 op_result
= handler( context
, SPFILENOTIFY_RENAMEERROR
, (UINT_PTR
)&paths
, 0 );
1002 if (op_result
== FILEOP_ABORT
) goto done
;
1004 handler( context
, SPFILENOTIFY_ENDRENAME
, (UINT_PTR
)&paths
, 0 );
1006 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_RENAME
, 0 );
1009 /* perform copies */
1011 if (queue
->copy_queue
.count
)
1013 if (!(handler( context
, SPFILENOTIFY_STARTSUBQUEUE
, FILEOP_COPY
,
1014 queue
->copy_queue
.count
))) goto done
;
1015 for (op
= queue
->copy_queue
.head
; op
; op
= op
->next
)
1017 WCHAR newpath
[MAX_PATH
];
1019 build_filepathsW( op
, &paths
);
1020 op_result
= handler( context
, SPFILENOTIFY_STARTCOPY
, (UINT_PTR
)&paths
, FILEOP_COPY
);
1021 if (op_result
== FILEOP_ABORT
) goto done
;
1022 if (op_result
== FILEOP_NEWPATH
) op_result
= FILEOP_DOIT
;
1023 while (op_result
== FILEOP_DOIT
|| op_result
== FILEOP_NEWPATH
)
1025 TRACE( "copying file %s -> %s\n",
1026 debugstr_w( op_result
== FILEOP_NEWPATH
? newpath
: paths
.Source
),
1027 debugstr_w(paths
.Target
) );
1030 if (!create_full_pathW( op
->dst_path
))
1032 paths
.Win32Error
= GetLastError();
1033 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
,
1034 (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1035 if (op_result
== FILEOP_ABORT
) goto done
;
1038 if (CopyFileW( op_result
== FILEOP_NEWPATH
? newpath
: paths
.Source
,
1039 paths
.Target
, FALSE
/*FIXME*/ )) break; /* success */
1040 /* try to extract it from the cabinet file */
1043 if (extract_cabinet_file( op
->src_tag
, op
->src_root
,
1044 paths
.Source
, paths
.Target
)) break;
1046 paths
.Win32Error
= GetLastError();
1047 op_result
= handler( context
, SPFILENOTIFY_COPYERROR
,
1048 (UINT_PTR
)&paths
, (UINT_PTR
)newpath
);
1049 if (op_result
== FILEOP_ABORT
) goto done
;
1051 handler( context
, SPFILENOTIFY_ENDCOPY
, (UINT_PTR
)&paths
, 0 );
1053 handler( context
, SPFILENOTIFY_ENDSUBQUEUE
, FILEOP_COPY
, 0 );
1060 handler( context
, SPFILENOTIFY_ENDQUEUE
, result
, 0 );
1061 HeapFree( GetProcessHeap(), 0, (void *)paths
.Source
);
1062 HeapFree( GetProcessHeap(), 0, (void *)paths
.Target
);
1067 /***********************************************************************
1068 * SetupScanFileQueueA (SETUPAPI.@)
1070 BOOL WINAPI
SetupScanFileQueueA( HSPFILEQ queue
, DWORD flags
, HWND window
,
1071 PSP_FILE_CALLBACK_A callback
, PVOID context
, PDWORD result
)
1078 /***********************************************************************
1079 * SetupScanFileQueueW (SETUPAPI.@)
1081 BOOL WINAPI
SetupScanFileQueueW( HSPFILEQ queue
, DWORD flags
, HWND window
,
1082 PSP_FILE_CALLBACK_W callback
, PVOID context
, PDWORD result
)
1089 /***********************************************************************
1090 * SetupGetFileQueueCount (SETUPAPI.@)
1092 BOOL WINAPI
SetupGetFileQueueCount( HSPFILEQ handle
, UINT op
, PUINT result
)
1094 struct file_queue
*queue
= handle
;
1099 *result
= queue
->copy_queue
.count
;
1102 *result
= queue
->rename_queue
.count
;
1105 *result
= queue
->delete_queue
.count
;
1112 /***********************************************************************
1113 * SetupGetFileQueueFlags (SETUPAPI.@)
1115 BOOL WINAPI
SetupGetFileQueueFlags( HSPFILEQ handle
, PDWORD flags
)
1117 struct file_queue
*queue
= handle
;
1118 *flags
= queue
->flags
;
1123 /***********************************************************************
1124 * SetupSetFileQueueFlags (SETUPAPI.@)
1126 BOOL WINAPI
SetupSetFileQueueFlags( HSPFILEQ handle
, DWORD mask
, DWORD flags
)
1128 struct file_queue
*queue
= handle
;
1129 queue
->flags
= (queue
->flags
& ~mask
) | flags
;
1134 /***********************************************************************
1135 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1137 PVOID WINAPI
SetupInitDefaultQueueCallback( HWND owner
)
1139 return SetupInitDefaultQueueCallbackEx( owner
, 0, 0, 0, NULL
);
1143 /***********************************************************************
1144 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1146 PVOID WINAPI
SetupInitDefaultQueueCallbackEx( HWND owner
, HWND progress
, UINT msg
,
1147 DWORD reserved1
, PVOID reserved2
)
1149 struct default_callback_context
*context
;
1151 if ((context
= HeapAlloc( GetProcessHeap(), 0, sizeof(*context
) )))
1153 context
->owner
= owner
;
1154 context
->progress
= progress
;
1155 context
->message
= msg
;
1161 /***********************************************************************
1162 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1164 void WINAPI
SetupTermDefaultQueueCallback( PVOID context
)
1166 HeapFree( GetProcessHeap(), 0, context
);
1170 /***********************************************************************
1171 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1173 UINT WINAPI
SetupDefaultQueueCallbackA( PVOID context
, UINT notification
,
1174 UINT_PTR param1
, UINT_PTR param2
)
1176 FILEPATHS_A
*paths
= (FILEPATHS_A
*)param1
;
1178 switch(notification
)
1180 case SPFILENOTIFY_STARTQUEUE
:
1181 TRACE( "start queue\n" );
1183 case SPFILENOTIFY_ENDQUEUE
:
1184 TRACE( "end queue\n" );
1186 case SPFILENOTIFY_STARTSUBQUEUE
:
1187 TRACE( "start subqueue %d count %d\n", param1
, param2
);
1189 case SPFILENOTIFY_ENDSUBQUEUE
:
1190 TRACE( "end subqueue %d\n", param1
);
1192 case SPFILENOTIFY_STARTDELETE
:
1193 TRACE( "start delete %s\n", debugstr_a(paths
->Target
) );
1195 case SPFILENOTIFY_ENDDELETE
:
1196 TRACE( "end delete %s\n", debugstr_a(paths
->Target
) );
1198 case SPFILENOTIFY_DELETEERROR
:
1199 ERR( "delete error %d %s\n", paths
->Win32Error
, debugstr_a(paths
->Target
) );
1201 case SPFILENOTIFY_STARTRENAME
:
1202 TRACE( "start rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1204 case SPFILENOTIFY_ENDRENAME
:
1205 TRACE( "end rename %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1207 case SPFILENOTIFY_RENAMEERROR
:
1208 ERR( "rename error %d %s -> %s\n", paths
->Win32Error
,
1209 debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1211 case SPFILENOTIFY_STARTCOPY
:
1212 TRACE( "start copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1214 case SPFILENOTIFY_ENDCOPY
:
1215 TRACE( "end copy %s -> %s\n", debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1217 case SPFILENOTIFY_COPYERROR
:
1218 ERR( "copy error %d %s -> %s\n", paths
->Win32Error
,
1219 debugstr_a(paths
->Source
), debugstr_a(paths
->Target
) );
1221 case SPFILENOTIFY_NEEDMEDIA
:
1222 TRACE( "need media\n" );
1225 FIXME( "notification %d params %x,%x\n", notification
, param1
, param2
);
1232 /***********************************************************************
1233 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1235 UINT WINAPI
SetupDefaultQueueCallbackW( PVOID context
, UINT notification
,
1236 UINT_PTR param1
, UINT_PTR param2
)
1238 FIXME( "notification %d params %x,%x\n", notification
, param1
, param2
);