Avoid crashing when releasing an NdrCStdStubBuffer that had been
[wine/dcerpc.git] / dlls / setupapi / queue.c
blob476fd000b60c685fce9df9eceedcb16738f9c2b1
1 /*
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
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winternl.h"
24 #include "winerror.h"
25 #include "setupapi.h"
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
35 HWND owner;
36 HWND progress;
37 UINT message;
40 struct file_op
42 struct file_op *next;
43 UINT style;
44 WCHAR *src_root;
45 WCHAR *src_path;
46 WCHAR *src_file;
47 WCHAR *src_descr;
48 WCHAR *src_tag;
49 WCHAR *dst_path;
50 WCHAR *dst_file;
53 struct file_op_queue
55 struct file_op *head;
56 struct file_op *tail;
57 unsigned int count;
60 struct file_queue
62 struct file_op_queue copy_queue;
63 struct file_op_queue delete_queue;
64 struct file_op_queue rename_queue;
65 DWORD flags;
69 inline static WCHAR *strdupW( const WCHAR *str )
71 WCHAR *ret = NULL;
72 if (str)
74 int len = (strlenW(str) + 1) * sizeof(WCHAR);
75 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
77 return ret;
81 inline static WCHAR *strdupAtoW( const char *str )
83 WCHAR *ret = NULL;
84 if (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 );
90 return ret;
93 inline static char *strdupWtoA( const WCHAR *str )
95 char *ret = NULL;
96 if (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 );
102 return ret;
105 /* append a file operation to a queue */
106 inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
108 op->next = NULL;
109 if (queue->tail) queue->tail->next = op;
110 else queue->head = op;
111 queue->tail = op;
112 queue->count++;
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;
120 while( op )
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 );
129 t = op;
130 op = op->next;
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 )
138 *buffer = 0;
139 if (src1 && *src1)
141 strcpyW( buffer, src1 );
142 buffer += strlenW(buffer );
143 if (buffer[-1] != '\\') *buffer++ = '\\';
144 if (src2) while (*src2 == '\\') src2++;
147 if (src2)
149 strcpyW( buffer, src2 );
150 buffer += strlenW(buffer );
151 if (buffer[-1] != '\\') *buffer++ = '\\';
152 if (src3) while (*src3 == '\\') src3++;
154 if (src3)
156 strcpyW( buffer, src3 );
157 buffer += strlenW(buffer );
162 /***********************************************************************
163 * build_filepathsW
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;
194 paths->Flags = 0;
195 return TRUE;
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];
209 UINT ret;
210 UINT_PTR old_param2 = param2;
212 switch(notification)
214 case SPFILENOTIFY_COPYERROR:
215 param2 = (UINT_PTR)&buffer;
216 /* fall through */
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;
227 FILEPATHS_A pathsA;
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 );
240 break;
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:
249 default:
250 ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
251 break;
253 return ret;
257 /***********************************************************************
258 * get_src_file_info
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;
270 INT id, diskid;
271 DWORD len, len2;
273 /* find the SourceDisksFiles entry */
274 if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
276 const WCHAR *dir;
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 );
282 return;
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;
288 for (;;)
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 */
296 if (!op->src_descr)
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 );
302 if (!op->src_tag)
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;
318 if ((len || len2) &&
319 (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
321 WCHAR *ptr = op->src_path;
322 if (len)
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};
345 const WCHAR *dir;
346 WCHAR *ptr, *ret;
347 INFCONTEXT context;
348 INT dirid;
349 DWORD len1, len2;
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;
358 strcpyW( ret, dir );
359 ptr = ret + strlenW(ret);
360 if (len2 && ptr > ret && ptr[-1] != '\\') *ptr++ = '\\';
361 if (!SetupGetStringFieldW( &context, 2, ptr, len2, NULL )) *ptr = 0;
362 return ret;
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;
384 if (!pExtractFiles)
386 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
388 ERR( "could not load advpack.dll\n" );
389 return FALSE;
391 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
393 ERR( "could not find ExtractFiles in advpack.dll\n" );
394 return FALSE;
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 );
403 return FALSE;
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;
425 return queue;
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 );
440 return TRUE;
444 /***********************************************************************
445 * SetupQueueCopyIndirectA (SETUPAPI.@)
447 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
449 struct file_queue *queue = params->QueueHandle;
450 struct file_op *op;
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 );
462 /* some defaults */
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 );
476 return TRUE;
480 /***********************************************************************
481 * SetupQueueCopyIndirectW (SETUPAPI.@)
483 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
485 struct file_queue *queue = params->QueueHandle;
486 struct file_op *op;
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 );
498 /* some defaults */
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 );
512 return TRUE;
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,
521 DWORD style )
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( &params );
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,
546 DWORD style )
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( &params );
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( &params );
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( &params );
614 /***********************************************************************
615 * SetupQueueDeleteA (SETUPAPI.@)
617 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
619 struct file_queue *queue = handle;
620 struct file_op *op;
622 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
623 op->style = 0;
624 op->src_root = NULL;
625 op->src_path = NULL;
626 op->src_file = NULL;
627 op->src_descr = NULL;
628 op->src_tag = NULL;
629 op->dst_path = strdupAtoW( part1 );
630 op->dst_file = strdupAtoW( part2 );
631 queue_file_op( &queue->delete_queue, op );
632 return TRUE;
636 /***********************************************************************
637 * SetupQueueDeleteW (SETUPAPI.@)
639 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
641 struct file_queue *queue = handle;
642 struct file_op *op;
644 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
645 op->style = 0;
646 op->src_root = NULL;
647 op->src_path = NULL;
648 op->src_file = NULL;
649 op->src_descr = NULL;
650 op->src_tag = NULL;
651 op->dst_path = strdupW( part1 );
652 op->dst_file = strdupW( part2 );
653 queue_file_op( &queue->delete_queue, op );
654 return TRUE;
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;
665 struct file_op *op;
667 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
668 op->style = 0;
669 op->src_root = NULL;
670 op->src_path = strdupAtoW( SourcePath );
671 op->src_file = strdupAtoW( SourceFilename );
672 op->src_descr = NULL;
673 op->src_tag = NULL;
674 op->dst_path = strdupAtoW( TargetPath );
675 op->dst_file = strdupAtoW( TargetFilename );
676 queue_file_op( &queue->rename_queue, op );
677 return TRUE;
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;
688 struct file_op *op;
690 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
691 op->style = 0;
692 op->src_root = NULL;
693 op->src_path = strdupW( SourcePath );
694 op->src_file = strdupW( SourceFilename );
695 op->src_descr = NULL;
696 op->src_tag = NULL;
697 op->dst_path = strdupW( TargetPath );
698 op->dst_file = strdupW( TargetFilename );
699 queue_file_op( &queue->rename_queue, op );
700 return TRUE;
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;
711 BOOL ret = FALSE;
713 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
715 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
716 return FALSE;
718 if (!src_root)
719 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
720 else
722 UNICODE_STRING srcW;
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( &sectionW );
731 return ret;
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;
742 INFCONTEXT context;
743 WCHAR dest[MAX_PATH], src[MAX_PATH];
744 INT flags;
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 ))
766 return FALSE;
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( &params )) return FALSE;
772 } while (SetupFindNextLine( &context, &context ));
773 return TRUE;
777 /***********************************************************************
778 * SetupQueueDeleteSectionA (SETUPAPI.@)
780 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
782 UNICODE_STRING sectionW;
783 BOOL ret = FALSE;
785 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
787 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
788 RtlFreeUnicodeString( &sectionW );
790 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
791 return ret;
795 /***********************************************************************
796 * SetupQueueDeleteSectionW (SETUPAPI.@)
798 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
800 INFCONTEXT context;
801 WCHAR *dest_dir;
802 WCHAR buffer[MAX_PATH];
803 BOOL ret = FALSE;
804 INT flags;
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 ))
814 goto done;
815 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
816 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
817 } while (SetupFindNextLine( &context, &context ));
819 ret = TRUE;
820 done:
821 HeapFree( GetProcessHeap(), 0, dest_dir );
822 return ret;
826 /***********************************************************************
827 * SetupQueueRenameSectionA (SETUPAPI.@)
829 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
831 UNICODE_STRING sectionW;
832 BOOL ret = FALSE;
834 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
836 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
837 RtlFreeUnicodeString( &sectionW );
839 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
840 return ret;
844 /***********************************************************************
845 * SetupQueueRenameSectionW (SETUPAPI.@)
847 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
849 INFCONTEXT context;
850 WCHAR *dest_dir;
851 WCHAR src[MAX_PATH], dst[MAX_PATH];
852 BOOL ret = FALSE;
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 ))
862 goto done;
863 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
864 goto done;
865 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
866 } while (SetupFindNextLine( &context, &context ));
868 ret = TRUE;
869 done:
870 HeapFree( GetProcessHeap(), 0, dest_dir );
871 return ret;
875 /***********************************************************************
876 * SetupCommitFileQueueA (SETUPAPI.@)
878 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
879 PVOID context )
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 /***********************************************************************
890 * create_full_pathW
892 * Recursively create all directories in the path.
894 static BOOL create_full_pathW(const WCHAR *path)
896 BOOL ret = TRUE;
897 int len;
898 WCHAR *new_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))
908 WCHAR *slash;
909 DWORD last_error = GetLastError();
911 if(last_error == ERROR_ALREADY_EXISTS)
912 break;
914 if(last_error != ERROR_PATH_NOT_FOUND)
916 ret = FALSE;
917 break;
920 if(!(slash = strrchrW(new_path, '\\')))
922 ret = FALSE;
923 break;
926 len = slash - new_path;
927 new_path[len] = 0;
928 if(!create_full_pathW(new_path))
930 ret = FALSE;
931 break;
933 new_path[len] = '\\';
936 HeapFree(GetProcessHeap(), 0, new_path);
937 return ret;
941 /***********************************************************************
942 * SetupCommitFileQueueW (SETUPAPI.@)
944 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
945 PVOID context )
947 struct file_queue *queue = handle;
948 struct file_op *op;
949 BOOL result = FALSE;
950 FILEPATHS_W paths;
951 UINT op_result;
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) );
1028 if (op->dst_path)
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 */
1041 if (op->src_tag)
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 );
1057 result = TRUE;
1059 done:
1060 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1061 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1062 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1063 return result;
1067 /***********************************************************************
1068 * SetupScanFileQueueA (SETUPAPI.@)
1070 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1071 PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1073 FIXME("stub\n");
1074 return FALSE;
1078 /***********************************************************************
1079 * SetupScanFileQueueW (SETUPAPI.@)
1081 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1082 PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1084 FIXME("stub\n");
1085 return FALSE;
1089 /***********************************************************************
1090 * SetupGetFileQueueCount (SETUPAPI.@)
1092 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1094 struct file_queue *queue = handle;
1096 switch(op)
1098 case FILEOP_COPY:
1099 *result = queue->copy_queue.count;
1100 return TRUE;
1101 case FILEOP_RENAME:
1102 *result = queue->rename_queue.count;
1103 return TRUE;
1104 case FILEOP_DELETE:
1105 *result = queue->delete_queue.count;
1106 return TRUE;
1108 return FALSE;
1112 /***********************************************************************
1113 * SetupGetFileQueueFlags (SETUPAPI.@)
1115 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1117 struct file_queue *queue = handle;
1118 *flags = queue->flags;
1119 return TRUE;
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;
1130 return TRUE;
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;
1157 return context;
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" );
1182 return TRUE;
1183 case SPFILENOTIFY_ENDQUEUE:
1184 TRACE( "end queue\n" );
1185 return 0;
1186 case SPFILENOTIFY_STARTSUBQUEUE:
1187 TRACE( "start subqueue %d count %d\n", param1, param2 );
1188 return TRUE;
1189 case SPFILENOTIFY_ENDSUBQUEUE:
1190 TRACE( "end subqueue %d\n", param1 );
1191 return 0;
1192 case SPFILENOTIFY_STARTDELETE:
1193 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1194 return FILEOP_DOIT;
1195 case SPFILENOTIFY_ENDDELETE:
1196 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1197 return 0;
1198 case SPFILENOTIFY_DELETEERROR:
1199 ERR( "delete error %d %s\n", paths->Win32Error, debugstr_a(paths->Target) );
1200 return FILEOP_SKIP;
1201 case SPFILENOTIFY_STARTRENAME:
1202 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1203 return FILEOP_DOIT;
1204 case SPFILENOTIFY_ENDRENAME:
1205 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1206 return 0;
1207 case SPFILENOTIFY_RENAMEERROR:
1208 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1209 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1210 return FILEOP_SKIP;
1211 case SPFILENOTIFY_STARTCOPY:
1212 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1213 return FILEOP_DOIT;
1214 case SPFILENOTIFY_ENDCOPY:
1215 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1216 return 0;
1217 case SPFILENOTIFY_COPYERROR:
1218 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1219 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1220 return FILEOP_SKIP;
1221 case SPFILENOTIFY_NEEDMEDIA:
1222 TRACE( "need media\n" );
1223 return FILEOP_SKIP;
1224 default:
1225 FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1226 break;
1228 return 0;
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 );
1239 return FILEOP_SKIP;