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"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
33 /* context structure for the default queue callback */
34 struct default_callback_context
63 struct file_op_queue copy_queue;
64 struct file_op_queue delete_queue;
65 struct file_op_queue rename_queue;
70 inline static WCHAR *strdupW( const WCHAR *str )
75 int len = (strlenW(str) + 1) * sizeof(WCHAR);
76 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
82 inline static WCHAR *strdupAtoW( const char *str )
87 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
88 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
89 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
94 inline static char *strdupWtoA( const WCHAR *str )
99 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
100 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
101 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
106 /* append a file operation to a queue */
107 inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
110 if (queue->tail) queue->tail->next = op;
111 else queue->head = op;
116 /* free all the file operations on a given queue */
117 static void free_file_op_queue( struct file_op_queue *queue )
119 struct file_op *t, *op = queue->head;
123 HeapFree( GetProcessHeap(), 0, op->src_root );
124 HeapFree( GetProcessHeap(), 0, op->src_path );
125 HeapFree( GetProcessHeap(), 0, op->src_file );
126 HeapFree( GetProcessHeap(), 0, op->src_descr );
127 HeapFree( GetProcessHeap(), 0, op->src_tag );
128 HeapFree( GetProcessHeap(), 0, op->dst_path );
129 if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
132 HeapFree( GetProcessHeap(), 0, t );
136 /* concat 3 strings to make a path, handling separators correctly */
137 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
142 strcpyW( buffer, src1 );
143 buffer += strlenW(buffer );
144 if (buffer[-1] != '\\') *buffer++ = '\\';
145 if (src2) while (*src2 == '\\') src2++;
150 strcpyW( buffer, src2 );
151 buffer += strlenW(buffer );
152 if (buffer[-1] != '\\') *buffer++ = '\\';
153 if (src3) while (*src3 == '\\') src3++;
157 strcpyW( buffer, src3 );
158 buffer += strlenW(buffer );
163 /***********************************************************************
166 * Build a FILEPATHS_W structure for a given file operation.
168 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
170 int src_len = 1, dst_len = 1;
171 WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
173 if (op->src_root) src_len += strlenW(op->src_root) + 1;
174 if (op->src_path) src_len += strlenW(op->src_path) + 1;
175 if (op->src_file) src_len += strlenW(op->src_file) + 1;
176 if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
177 if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
178 src_len *= sizeof(WCHAR);
179 dst_len *= sizeof(WCHAR);
181 if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
183 HeapFree( GetProcessHeap(), 0, source );
184 paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
186 if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
188 HeapFree( GetProcessHeap(), 0, target );
189 paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
191 if (!source || !target) return FALSE;
192 concat_W( source, op->src_root, op->src_path, op->src_file );
193 concat_W( target, NULL, op->dst_path, op->dst_file );
194 paths->Win32Error = 0;
200 /***********************************************************************
201 * QUEUE_callback_WtoA
203 * Map a file callback parameters from W to A and call the A callback.
205 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
206 UINT_PTR param1, UINT_PTR param2 )
208 struct callback_WtoA_context *callback_ctx = context;
209 char buffer[MAX_PATH];
211 UINT_PTR old_param2 = param2;
215 case SPFILENOTIFY_COPYERROR:
216 param2 = (UINT_PTR)&buffer;
218 case SPFILENOTIFY_STARTDELETE:
219 case SPFILENOTIFY_ENDDELETE:
220 case SPFILENOTIFY_DELETEERROR:
221 case SPFILENOTIFY_STARTRENAME:
222 case SPFILENOTIFY_ENDRENAME:
223 case SPFILENOTIFY_RENAMEERROR:
224 case SPFILENOTIFY_STARTCOPY:
225 case SPFILENOTIFY_ENDCOPY:
227 FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
230 pathsA.Source = strdupWtoA( pathsW->Source );
231 pathsA.Target = strdupWtoA( pathsW->Target );
232 pathsA.Win32Error = pathsW->Win32Error;
233 pathsA.Flags = pathsW->Flags;
234 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
235 (UINT_PTR)&pathsA, param2 );
236 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
237 HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
239 if (notification == SPFILENOTIFY_COPYERROR)
240 MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
243 case SPFILENOTIFY_NEEDMEDIA:
244 case SPFILENOTIFY_QUEUESCAN:
245 FIXME("mapping for %d not implemented\n",notification);
246 case SPFILENOTIFY_STARTQUEUE:
247 case SPFILENOTIFY_ENDQUEUE:
248 case SPFILENOTIFY_STARTSUBQUEUE:
249 case SPFILENOTIFY_ENDSUBQUEUE:
251 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
258 /***********************************************************************
261 * Retrieve the source file information for a given file.
263 static void get_src_file_info( HINF hinf, struct file_op *op )
265 static const WCHAR SourceDisksNames[] =
266 {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
267 static const WCHAR SourceDisksFiles[] =
268 {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
270 INFCONTEXT file_ctx, disk_ctx;
274 /* find the SourceDisksFiles entry */
275 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
279 if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
280 /* no specific info, use .inf file source directory */
281 if (!op->src_root && (dir = DIRID_get_string( hinf, DIRID_SRCPATH )))
282 op->src_root = strdupW( dir );
285 if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
287 /* now find the diskid in the SourceDisksNames section */
288 if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
291 if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
292 if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
295 /* and fill in the missing info */
299 if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
300 (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
301 SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
305 if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
306 (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
307 SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
309 if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
311 if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
313 /* retrieve relative path for this disk */
314 if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
316 /* retrieve relative path for this file */
317 if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
320 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
322 WCHAR *ptr = op->src_path;
325 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
326 ptr = op->src_path + strlenW(op->src_path);
327 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
329 if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0;
332 if (!op->src_root) op->src_root = strdupW( PARSER_get_src_root(hinf) );
336 /***********************************************************************
337 * get_destination_dir
339 * Retrieve the destination dir for a given section.
341 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
343 static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
344 static const WCHAR Def[] = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
352 if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
353 !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
354 if (!SetupGetIntField( &context, 1, &dirid )) return NULL;
355 if (!(dir = DIRID_get_string( hinf, dirid ))) return NULL;
356 len1 = strlenW(dir) + 1;
357 if (!SetupGetStringFieldW( &context, 2, NULL, 0, &len2 )) len2 = 0;
358 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len1+len2) * sizeof(WCHAR) ))) return NULL;
360 ptr = ret + strlenW(ret);
361 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
362 if (!SetupGetStringFieldW( &context, 2, ptr, len2, NULL )) *ptr = 0;
367 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
369 /***********************************************************************
370 * extract_cabinet_file
372 * Extract a file from a .cab file.
374 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
375 const WCHAR *src, const WCHAR *dst )
377 static const WCHAR extW[] = {'.','c','a','b',0};
378 static HMODULE advpack;
380 char *cab_path, *cab_file;
381 int len = strlenW( cabinet );
383 /* make sure the cabinet file has a .cab extension */
384 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
387 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
389 ERR( "could not load advpack.dll\n" );
392 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
394 ERR( "could not find ExtractFiles in advpack.dll\n" );
399 if (!(cab_path = strdupWtoA( root ))) return FALSE;
400 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
401 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
403 HeapFree( GetProcessHeap(), 0, cab_path );
406 strcpy( cab_file, cab_path );
407 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
408 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
409 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
410 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
411 HeapFree( GetProcessHeap(), 0, cab_file );
412 HeapFree( GetProcessHeap(), 0, cab_path );
413 return CopyFileW( src, dst, FALSE /*FIXME*/ );
417 /***********************************************************************
418 * SetupOpenFileQueue (SETUPAPI.@)
420 HSPFILEQ WINAPI SetupOpenFileQueue(void)
422 struct file_queue *queue;
424 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
425 return (HSPFILEQ)INVALID_HANDLE_VALUE;
430 /***********************************************************************
431 * SetupCloseFileQueue (SETUPAPI.@)
433 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
435 struct file_queue *queue = handle;
437 free_file_op_queue( &queue->copy_queue );
438 free_file_op_queue( &queue->rename_queue );
439 free_file_op_queue( &queue->delete_queue );
440 HeapFree( GetProcessHeap(), 0, queue );
445 /***********************************************************************
446 * SetupQueueCopyIndirectA (SETUPAPI.@)
448 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
450 struct file_queue *queue = params->QueueHandle;
453 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
454 op->style = params->CopyStyle;
455 op->src_root = strdupAtoW( params->SourceRootPath );
456 op->src_path = strdupAtoW( params->SourcePath );
457 op->src_file = strdupAtoW( params->SourceFilename );
458 op->src_descr = strdupAtoW( params->SourceDescription );
459 op->src_tag = strdupAtoW( params->SourceTagfile );
460 op->dst_path = strdupAtoW( params->TargetDirectory );
461 op->dst_file = strdupAtoW( params->TargetFilename );
464 if (!op->src_file) op->src_file = op->dst_file;
465 if (params->LayoutInf)
467 get_src_file_info( params->LayoutInf, op );
468 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
471 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
472 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
473 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
474 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
476 queue_file_op( &queue->copy_queue, op );
481 /***********************************************************************
482 * SetupQueueCopyIndirectW (SETUPAPI.@)
484 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
486 struct file_queue *queue = params->QueueHandle;
489 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
490 op->style = params->CopyStyle;
491 op->src_root = strdupW( params->SourceRootPath );
492 op->src_path = strdupW( params->SourcePath );
493 op->src_file = strdupW( params->SourceFilename );
494 op->src_descr = strdupW( params->SourceDescription );
495 op->src_tag = strdupW( params->SourceTagfile );
496 op->dst_path = strdupW( params->TargetDirectory );
497 op->dst_file = strdupW( params->TargetFilename );
500 if (!op->src_file) op->src_file = op->dst_file;
501 if (params->LayoutInf)
503 get_src_file_info( params->LayoutInf, op );
504 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
507 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
508 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
509 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
510 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
512 queue_file_op( &queue->copy_queue, op );
517 /***********************************************************************
518 * SetupQueueCopyA (SETUPAPI.@)
520 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
521 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
524 SP_FILE_COPY_PARAMS_A params;
526 params.cbSize = sizeof(params);
527 params.QueueHandle = queue;
528 params.SourceRootPath = src_root;
529 params.SourcePath = src_path;
530 params.SourceFilename = src_file;
531 params.SourceDescription = src_descr;
532 params.SourceTagfile = src_tag;
533 params.TargetDirectory = dst_dir;
534 params.TargetFilename = dst_file;
535 params.CopyStyle = style;
536 params.LayoutInf = 0;
537 params.SecurityDescriptor = NULL;
538 return SetupQueueCopyIndirectA( ¶ms );
542 /***********************************************************************
543 * SetupQueueCopyW (SETUPAPI.@)
545 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
546 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
549 SP_FILE_COPY_PARAMS_W params;
551 params.cbSize = sizeof(params);
552 params.QueueHandle = queue;
553 params.SourceRootPath = src_root;
554 params.SourcePath = src_path;
555 params.SourceFilename = src_file;
556 params.SourceDescription = src_descr;
557 params.SourceTagfile = src_tag;
558 params.TargetDirectory = dst_dir;
559 params.TargetFilename = dst_file;
560 params.CopyStyle = style;
561 params.LayoutInf = 0;
562 params.SecurityDescriptor = NULL;
563 return SetupQueueCopyIndirectW( ¶ms );
567 /***********************************************************************
568 * SetupQueueDefaultCopyA (SETUPAPI.@)
570 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
571 PCSTR dst_file, DWORD style )
573 SP_FILE_COPY_PARAMS_A params;
575 params.cbSize = sizeof(params);
576 params.QueueHandle = queue;
577 params.SourceRootPath = src_root;
578 params.SourcePath = NULL;
579 params.SourceFilename = src_file;
580 params.SourceDescription = NULL;
581 params.SourceTagfile = NULL;
582 params.TargetDirectory = NULL;
583 params.TargetFilename = dst_file;
584 params.CopyStyle = style;
585 params.LayoutInf = hinf;
586 params.SecurityDescriptor = NULL;
587 return SetupQueueCopyIndirectA( ¶ms );
591 /***********************************************************************
592 * SetupQueueDefaultCopyW (SETUPAPI.@)
594 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
595 PCWSTR dst_file, DWORD style )
597 SP_FILE_COPY_PARAMS_W params;
599 params.cbSize = sizeof(params);
600 params.QueueHandle = queue;
601 params.SourceRootPath = src_root;
602 params.SourcePath = NULL;
603 params.SourceFilename = src_file;
604 params.SourceDescription = NULL;
605 params.SourceTagfile = NULL;
606 params.TargetDirectory = NULL;
607 params.TargetFilename = dst_file;
608 params.CopyStyle = style;
609 params.LayoutInf = hinf;
610 params.SecurityDescriptor = NULL;
611 return SetupQueueCopyIndirectW( ¶ms );
615 /***********************************************************************
616 * SetupQueueDeleteA (SETUPAPI.@)
618 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
620 struct file_queue *queue = handle;
623 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
628 op->src_descr = NULL;
630 op->dst_path = strdupAtoW( part1 );
631 op->dst_file = strdupAtoW( part2 );
632 queue_file_op( &queue->delete_queue, op );
637 /***********************************************************************
638 * SetupQueueDeleteW (SETUPAPI.@)
640 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
642 struct file_queue *queue = handle;
645 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
650 op->src_descr = NULL;
652 op->dst_path = strdupW( part1 );
653 op->dst_file = strdupW( part2 );
654 queue_file_op( &queue->delete_queue, op );
659 /***********************************************************************
660 * SetupQueueRenameA (SETUPAPI.@)
662 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
663 PCSTR TargetPath, PCSTR TargetFilename )
665 struct file_queue *queue = handle;
668 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
671 op->src_path = strdupAtoW( SourcePath );
672 op->src_file = strdupAtoW( SourceFilename );
673 op->src_descr = NULL;
675 op->dst_path = strdupAtoW( TargetPath );
676 op->dst_file = strdupAtoW( TargetFilename );
677 queue_file_op( &queue->rename_queue, op );
682 /***********************************************************************
683 * SetupQueueRenameW (SETUPAPI.@)
685 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
686 PCWSTR TargetPath, PCWSTR TargetFilename )
688 struct file_queue *queue = handle;
691 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
694 op->src_path = strdupW( SourcePath );
695 op->src_file = strdupW( SourceFilename );
696 op->src_descr = NULL;
698 op->dst_path = strdupW( TargetPath );
699 op->dst_file = strdupW( TargetFilename );
700 queue_file_op( &queue->rename_queue, op );
705 /***********************************************************************
706 * SetupQueueCopySectionA (SETUPAPI.@)
708 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
709 PCSTR section, DWORD style )
711 UNICODE_STRING sectionW;
714 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
716 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
720 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
724 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
726 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
727 RtlFreeUnicodeString( &srcW );
729 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
731 RtlFreeUnicodeString( §ionW );
736 /***********************************************************************
737 * SetupQueueCopySectionW (SETUPAPI.@)
739 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
740 PCWSTR section, DWORD style )
742 SP_FILE_COPY_PARAMS_W params;
744 WCHAR dest[MAX_PATH], src[MAX_PATH];
747 TRACE( "hinf=%p/%p section=%s root=%s\n",
748 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
750 params.cbSize = sizeof(params);
751 params.QueueHandle = queue;
752 params.SourceRootPath = src_root;
753 params.SourcePath = NULL;
754 params.SourceDescription = NULL;
755 params.SourceTagfile = NULL;
756 params.TargetFilename = dest;
757 params.CopyStyle = style;
758 params.LayoutInf = hinf;
759 params.SecurityDescriptor = NULL;
761 if (!hlist) hlist = hinf;
762 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
763 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
766 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
768 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
769 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
771 params.SourceFilename = *src ? src : NULL;
772 if (!SetupQueueCopyIndirectW( ¶ms )) return FALSE;
773 } while (SetupFindNextLine( &context, &context ));
778 /***********************************************************************
779 * SetupQueueDeleteSectionA (SETUPAPI.@)
781 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
783 UNICODE_STRING sectionW;
786 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
788 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
789 RtlFreeUnicodeString( §ionW );
791 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
796 /***********************************************************************
797 * SetupQueueDeleteSectionW (SETUPAPI.@)
799 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
803 WCHAR buffer[MAX_PATH];
807 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
809 if (!hlist) hlist = hinf;
810 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
811 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
814 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
816 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
817 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
818 } while (SetupFindNextLine( &context, &context ));
822 HeapFree( GetProcessHeap(), 0, dest_dir );
827 /***********************************************************************
828 * SetupQueueRenameSectionA (SETUPAPI.@)
830 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
832 UNICODE_STRING sectionW;
835 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
837 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
838 RtlFreeUnicodeString( §ionW );
840 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
845 /***********************************************************************
846 * SetupQueueRenameSectionW (SETUPAPI.@)
848 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
852 WCHAR src[MAX_PATH], dst[MAX_PATH];
855 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
857 if (!hlist) hlist = hinf;
858 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
859 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
862 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
864 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
866 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
867 } while (SetupFindNextLine( &context, &context ));
871 HeapFree( GetProcessHeap(), 0, dest_dir );
876 /***********************************************************************
877 * SetupCommitFileQueueA (SETUPAPI.@)
879 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
882 struct callback_WtoA_context ctx;
884 ctx.orig_context = context;
885 ctx.orig_handler = handler;
886 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
890 /***********************************************************************
893 * Recursively create all directories in the path.
895 static BOOL create_full_pathW(const WCHAR *path)
901 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
902 strcpyW(new_path, path);
904 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
905 new_path[len - 1] = 0;
907 while(!CreateDirectoryW(new_path, NULL))
910 DWORD last_error = GetLastError();
912 if(last_error == ERROR_ALREADY_EXISTS)
915 if(last_error != ERROR_PATH_NOT_FOUND)
921 if(!(slash = strrchrW(new_path, '\\')))
927 len = slash - new_path;
929 if(!create_full_pathW(new_path))
934 new_path[len] = '\\';
937 HeapFree(GetProcessHeap(), 0, new_path);
941 BOOL static do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style)
946 TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style);
948 /* before copy processing */
949 if (style & SP_COPY_REPLACEONLY)
951 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
954 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
956 DWORD VersionSizeSource=0;
957 DWORD VersionSizeTarget=0;
961 * This is sort of an interesting workaround. You see, calling
962 * GetVersionInfoSize on a builtin dll loads that dll into memory
963 * and we do not properly unload builtin dlls.. so we effectively
964 * lock into memory all the targets we are replacing. This leads
965 * to problems when we try to register the replaced dlls.
967 * So I will test for the existence of the files first so that
968 * we just basically unconditionally replace the builtin versions.
970 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
971 (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
973 VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
974 VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
977 TRACE("SizeTarget %li ... SizeSource %li\n",VersionSizeTarget,
980 if (VersionSizeSource && VersionSizeTarget)
982 LPVOID VersionSource;
983 LPVOID VersionTarget;
984 VS_FIXEDFILEINFO *TargetInfo;
985 VS_FIXEDFILEINFO *SourceInfo;
987 WCHAR SubBlock[2]={'\\',0};
990 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
991 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
993 ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
995 ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
1000 ret = VerQueryValueW(VersionSource, SubBlock,
1001 (LPVOID*)&SourceInfo, &length);
1003 ret = VerQueryValueW(VersionTarget, SubBlock,
1004 (LPVOID*)&TargetInfo, &length);
1008 TRACE("Versions: Source %li.%li target %li.%li\n",
1009 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1010 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1012 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1014 FIXME("Notify that target version is greater..\n");
1017 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1018 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1020 FIXME("Notify that target version is greater..\n");
1023 else if ((style & SP_COPY_NEWER_ONLY) &&
1024 (TargetInfo->dwFileVersionMS ==
1025 SourceInfo->dwFileVersionMS)
1026 &&(TargetInfo->dwFileVersionLS ==
1027 SourceInfo->dwFileVersionLS))
1029 FIXME("Notify that target version is greater..\n");
1033 HeapFree(GetProcessHeap(),0,VersionSource);
1034 HeapFree(GetProcessHeap(),0,VersionTarget);
1038 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1040 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1042 FIXME("Notify user target file exists\n");
1046 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1047 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1049 ERR("Unsupported style(s) 0x%lx\n",style);
1054 rc = CopyFileW(source,target,FALSE);
1055 TRACE("Did copy... rc was %i\n",rc);
1058 /* after copy processing */
1059 if (style & SP_COPY_DELETESOURCE)
1062 DeleteFileW(source);
1068 /***********************************************************************
1069 * SetupCommitFileQueueW (SETUPAPI.@)
1071 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1074 struct file_queue *queue = handle;
1076 BOOL result = FALSE;
1080 paths.Source = paths.Target = NULL;
1082 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1083 return TRUE; /* nothing to do */
1085 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT)owner, 0 )) return FALSE;
1087 /* perform deletes */
1089 if (queue->delete_queue.count)
1091 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1092 queue->delete_queue.count ))) goto done;
1093 for (op = queue->delete_queue.head; op; op = op->next)
1095 build_filepathsW( op, &paths );
1096 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1097 if (op_result == FILEOP_ABORT) goto done;
1098 while (op_result == FILEOP_DOIT)
1100 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1101 if (DeleteFileW( paths.Target )) break; /* success */
1102 paths.Win32Error = GetLastError();
1103 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1104 if (op_result == FILEOP_ABORT) goto done;
1106 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1108 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1111 /* perform renames */
1113 if (queue->rename_queue.count)
1115 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1116 queue->rename_queue.count ))) goto done;
1117 for (op = queue->rename_queue.head; op; op = op->next)
1119 build_filepathsW( op, &paths );
1120 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1121 if (op_result == FILEOP_ABORT) goto done;
1122 while (op_result == FILEOP_DOIT)
1124 TRACE( "renaming file %s -> %s\n",
1125 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1126 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1127 paths.Win32Error = GetLastError();
1128 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1129 if (op_result == FILEOP_ABORT) goto done;
1131 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1133 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1136 /* perform copies */
1138 if (queue->copy_queue.count)
1140 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1141 queue->copy_queue.count ))) goto done;
1142 for (op = queue->copy_queue.head; op; op = op->next)
1144 WCHAR newpath[MAX_PATH];
1146 build_filepathsW( op, &paths );
1147 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1148 if (op_result == FILEOP_ABORT) goto done;
1149 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1150 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1152 TRACE( "copying file %s -> %s\n",
1153 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1154 debugstr_w(paths.Target) );
1157 if (!create_full_pathW( op->dst_path ))
1159 paths.Win32Error = GetLastError();
1160 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1161 (UINT_PTR)&paths, (UINT_PTR)newpath );
1162 if (op_result == FILEOP_ABORT) goto done;
1165 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1166 paths.Target, op->style )) break; /* success */
1167 /* try to extract it from the cabinet file */
1170 if (extract_cabinet_file( op->src_tag, op->src_root,
1171 paths.Source, paths.Target )) break;
1173 paths.Win32Error = GetLastError();
1174 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1175 (UINT_PTR)&paths, (UINT_PTR)newpath );
1176 if (op_result == FILEOP_ABORT) goto done;
1178 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1180 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1187 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1188 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1189 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1194 /***********************************************************************
1195 * SetupScanFileQueueA (SETUPAPI.@)
1197 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1198 PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1205 /***********************************************************************
1206 * SetupScanFileQueueW (SETUPAPI.@)
1208 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1209 PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1216 /***********************************************************************
1217 * SetupGetFileQueueCount (SETUPAPI.@)
1219 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1221 struct file_queue *queue = handle;
1226 *result = queue->copy_queue.count;
1229 *result = queue->rename_queue.count;
1232 *result = queue->delete_queue.count;
1239 /***********************************************************************
1240 * SetupGetFileQueueFlags (SETUPAPI.@)
1242 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1244 struct file_queue *queue = handle;
1245 *flags = queue->flags;
1250 /***********************************************************************
1251 * SetupSetFileQueueFlags (SETUPAPI.@)
1253 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1255 struct file_queue *queue = handle;
1256 queue->flags = (queue->flags & ~mask) | flags;
1261 /***********************************************************************
1262 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1264 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1266 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1270 /***********************************************************************
1271 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1273 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1274 DWORD reserved1, PVOID reserved2 )
1276 struct default_callback_context *context;
1278 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1280 context->owner = owner;
1281 context->progress = progress;
1282 context->message = msg;
1288 /***********************************************************************
1289 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1291 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1293 HeapFree( GetProcessHeap(), 0, context );
1297 /***********************************************************************
1298 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1300 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1301 UINT_PTR param1, UINT_PTR param2 )
1303 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1305 switch(notification)
1307 case SPFILENOTIFY_STARTQUEUE:
1308 TRACE( "start queue\n" );
1310 case SPFILENOTIFY_ENDQUEUE:
1311 TRACE( "end queue\n" );
1313 case SPFILENOTIFY_STARTSUBQUEUE:
1314 TRACE( "start subqueue %d count %d\n", param1, param2 );
1316 case SPFILENOTIFY_ENDSUBQUEUE:
1317 TRACE( "end subqueue %d\n", param1 );
1319 case SPFILENOTIFY_STARTDELETE:
1320 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1322 case SPFILENOTIFY_ENDDELETE:
1323 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1325 case SPFILENOTIFY_DELETEERROR:
1326 ERR( "delete error %d %s\n", paths->Win32Error, debugstr_a(paths->Target) );
1328 case SPFILENOTIFY_STARTRENAME:
1329 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1331 case SPFILENOTIFY_ENDRENAME:
1332 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1334 case SPFILENOTIFY_RENAMEERROR:
1335 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1336 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1338 case SPFILENOTIFY_STARTCOPY:
1339 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1341 case SPFILENOTIFY_ENDCOPY:
1342 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1344 case SPFILENOTIFY_COPYERROR:
1345 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1346 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1348 case SPFILENOTIFY_NEEDMEDIA:
1349 TRACE( "need media\n" );
1352 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1359 /***********************************************************************
1360 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1362 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1363 UINT_PTR param1, UINT_PTR param2 )
1365 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );