Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/advpack/files.c
4388 views
1
/*
2
* Advpack file functions
3
*
4
* Copyright 2006 James Hawkins
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#include <stdarg.h>
22
#include <stdlib.h>
23
24
#include "windef.h"
25
#include "winbase.h"
26
#include "winuser.h"
27
#include "winreg.h"
28
#include "winnls.h"
29
#include "winver.h"
30
#include "winternl.h"
31
#include "setupapi.h"
32
#include "advpub.h"
33
#include "fdi.h"
34
#include "wine/debug.h"
35
#include "advpack_private.h"
36
37
WINE_DEFAULT_DEBUG_CHANNEL(advpack);
38
39
/* converts an ansi double null-terminated list to a unicode list */
40
static LPWSTR ansi_to_unicode_list(LPCSTR ansi_list)
41
{
42
DWORD len, wlen = 0;
43
LPWSTR list;
44
LPCSTR ptr = ansi_list;
45
46
while (*ptr) ptr += lstrlenA(ptr) + 1;
47
len = ptr + 1 - ansi_list;
48
wlen = MultiByteToWideChar(CP_ACP, 0, ansi_list, len, NULL, 0);
49
list = malloc(wlen * sizeof(WCHAR));
50
MultiByteToWideChar(CP_ACP, 0, ansi_list, len, list, wlen);
51
return list;
52
}
53
54
/***********************************************************************
55
* AddDelBackupEntryA (ADVPACK.@)
56
*
57
* See AddDelBackupEntryW.
58
*/
59
HRESULT WINAPI AddDelBackupEntryA(LPCSTR lpcszFileList, LPCSTR lpcszBackupDir,
60
LPCSTR lpcszBaseName, DWORD dwFlags)
61
{
62
UNICODE_STRING backupdir, basename;
63
LPWSTR filelist;
64
LPCWSTR backup;
65
HRESULT res;
66
67
TRACE("(%s, %s, %s, %ld)\n", debugstr_a(lpcszFileList),
68
debugstr_a(lpcszBackupDir), debugstr_a(lpcszBaseName), dwFlags);
69
70
if (lpcszFileList)
71
filelist = ansi_to_unicode_list(lpcszFileList);
72
else
73
filelist = NULL;
74
75
RtlCreateUnicodeStringFromAsciiz(&backupdir, lpcszBackupDir);
76
RtlCreateUnicodeStringFromAsciiz(&basename, lpcszBaseName);
77
78
if (lpcszBackupDir)
79
backup = backupdir.Buffer;
80
else
81
backup = NULL;
82
83
res = AddDelBackupEntryW(filelist, backup, basename.Buffer, dwFlags);
84
85
free(filelist);
86
87
RtlFreeUnicodeString(&backupdir);
88
RtlFreeUnicodeString(&basename);
89
90
return res;
91
}
92
93
/***********************************************************************
94
* AddDelBackupEntryW (ADVPACK.@)
95
*
96
* Either appends the files in the file list to the backup section of
97
* the specified INI, or deletes the entries from the INI file.
98
*
99
* PARAMS
100
* lpcszFileList [I] NULL-separated list of filenames.
101
* lpcszBackupDir [I] Path of the backup directory.
102
* lpcszBaseName [I] Basename of the INI file.
103
* dwFlags [I] AADBE_ADD_ENTRY adds the entries in the file list
104
* to the INI file, while AADBE_DEL_ENTRY removes
105
* the entries from the INI file.
106
*
107
* RETURNS
108
* S_OK in all cases.
109
*
110
* NOTES
111
* If the INI file does not exist before adding entries to it, the file
112
* will be created.
113
*
114
* If lpcszBackupDir is NULL, the INI file is assumed to exist in
115
* c:\windows or created there if it does not exist.
116
*/
117
HRESULT WINAPI AddDelBackupEntryW(LPCWSTR lpcszFileList, LPCWSTR lpcszBackupDir,
118
LPCWSTR lpcszBaseName, DWORD dwFlags)
119
{
120
WCHAR szIniPath[MAX_PATH];
121
LPCWSTR szString = NULL;
122
123
TRACE("(%s, %s, %s, %ld)\n", debugstr_w(lpcszFileList),
124
debugstr_w(lpcszBackupDir), debugstr_w(lpcszBaseName), dwFlags);
125
126
if (!lpcszFileList || !*lpcszFileList)
127
return S_OK;
128
129
if (lpcszBackupDir)
130
lstrcpyW(szIniPath, lpcszBackupDir);
131
else
132
GetWindowsDirectoryW(szIniPath, MAX_PATH);
133
134
lstrcatW(szIniPath, L"\\");
135
lstrcatW(szIniPath, lpcszBaseName);
136
lstrcatW(szIniPath, L".ini");
137
138
SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_NORMAL);
139
140
if (dwFlags & AADBE_ADD_ENTRY)
141
szString = L"-1,0,0,0,0,0,-1";
142
else if (dwFlags & AADBE_DEL_ENTRY)
143
szString = NULL;
144
145
/* add or delete the INI entries */
146
while (*lpcszFileList)
147
{
148
WritePrivateProfileStringW(L"backup", lpcszFileList, szString, szIniPath);
149
lpcszFileList += lstrlenW(lpcszFileList) + 1;
150
}
151
152
/* hide the INI file */
153
SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
154
155
return S_OK;
156
}
157
158
/* FIXME: this is only for the local case, X:\ */
159
#define ROOT_LENGTH 3
160
161
static UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification,
162
UINT_PTR Param1, UINT_PTR Param2)
163
{
164
return 1;
165
}
166
167
static UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification,
168
UINT_PTR Param1, UINT_PTR Param2)
169
{
170
/* only be verbose for error notifications */
171
if (!Notification ||
172
Notification == SPFILENOTIFY_RENAMEERROR ||
173
Notification == SPFILENOTIFY_DELETEERROR ||
174
Notification == SPFILENOTIFY_COPYERROR)
175
{
176
return SetupDefaultQueueCallbackW(Context, Notification,
177
Param1, Param2);
178
}
179
180
return 1;
181
}
182
183
/***********************************************************************
184
* AdvInstallFileA (ADVPACK.@)
185
*
186
* See AdvInstallFileW.
187
*/
188
HRESULT WINAPI AdvInstallFileA(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile,
189
LPCSTR lpszDestDir, LPCSTR lpszDestFile,
190
DWORD dwFlags, DWORD dwReserved)
191
{
192
UNICODE_STRING sourcedir, sourcefile;
193
UNICODE_STRING destdir, destfile;
194
HRESULT res;
195
196
TRACE("(%p, %s, %s, %s, %s, %ld, %ld)\n", hwnd, debugstr_a(lpszSourceDir),
197
debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir),
198
debugstr_a(lpszDestFile), dwFlags, dwReserved);
199
200
if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
201
return E_INVALIDARG;
202
203
RtlCreateUnicodeStringFromAsciiz(&sourcedir, lpszSourceDir);
204
RtlCreateUnicodeStringFromAsciiz(&sourcefile, lpszSourceFile);
205
RtlCreateUnicodeStringFromAsciiz(&destdir, lpszDestDir);
206
RtlCreateUnicodeStringFromAsciiz(&destfile, lpszDestFile);
207
208
res = AdvInstallFileW(hwnd, sourcedir.Buffer, sourcefile.Buffer,
209
destdir.Buffer, destfile.Buffer, dwFlags, dwReserved);
210
211
RtlFreeUnicodeString(&sourcedir);
212
RtlFreeUnicodeString(&sourcefile);
213
RtlFreeUnicodeString(&destdir);
214
RtlFreeUnicodeString(&destfile);
215
216
return res;
217
}
218
219
/***********************************************************************
220
* AdvInstallFileW (ADVPACK.@)
221
*
222
* Copies a file from the source to a destination.
223
*
224
* PARAMS
225
* hwnd [I] Handle to the window used for messages.
226
* lpszSourceDir [I] Source directory.
227
* lpszSourceFile [I] Source filename.
228
* lpszDestDir [I] Destination directory.
229
* lpszDestFile [I] Optional destination filename.
230
* dwFlags [I] See advpub.h.
231
* dwReserved [I] Reserved. Must be 0.
232
*
233
* RETURNS
234
* Success: S_OK.
235
* Failure: E_FAIL.
236
*
237
* NOTES
238
* If lpszDestFile is NULL, the destination filename is the same as
239
* lpszSourceFIle.
240
*/
241
HRESULT WINAPI AdvInstallFileW(HWND hwnd, LPCWSTR lpszSourceDir, LPCWSTR lpszSourceFile,
242
LPCWSTR lpszDestDir, LPCWSTR lpszDestFile,
243
DWORD dwFlags, DWORD dwReserved)
244
{
245
PSP_FILE_CALLBACK_W pFileCallback;
246
LPWSTR szDestFilename;
247
LPCWSTR szPath;
248
WCHAR szRootPath[ROOT_LENGTH];
249
DWORD dwLastError;
250
HSPFILEQ fileQueue;
251
PVOID pContext;
252
253
TRACE("(%p, %s, %s, %s, %s, %ld, %ld)\n", hwnd, debugstr_w(lpszSourceDir),
254
debugstr_w(lpszSourceFile), debugstr_w(lpszDestDir),
255
debugstr_w(lpszDestFile), dwFlags, dwReserved);
256
257
if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
258
return E_INVALIDARG;
259
260
fileQueue = SetupOpenFileQueue();
261
if (fileQueue == INVALID_HANDLE_VALUE)
262
return HRESULT_FROM_WIN32(GetLastError());
263
264
pContext = NULL;
265
dwLastError = ERROR_SUCCESS;
266
267
lstrcpynW(szRootPath, lpszSourceDir, ROOT_LENGTH);
268
szPath = lpszSourceDir + ROOT_LENGTH;
269
270
/* use lpszSourceFile as destination filename if lpszDestFile is NULL */
271
szDestFilename = wcsdup(lpszDestFile ? lpszDestFile : lpszSourceFile);
272
273
/* add the file copy operation to the setup queue */
274
if (!SetupQueueCopyW(fileQueue, szRootPath, szPath, lpszSourceFile, NULL,
275
NULL, lpszDestDir, szDestFilename, dwFlags))
276
{
277
dwLastError = GetLastError();
278
goto done;
279
}
280
281
pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE,
282
0, 0, NULL);
283
if (!pContext)
284
{
285
dwLastError = GetLastError();
286
goto done;
287
}
288
289
/* don't output anything for AIF_QUIET */
290
if (dwFlags & AIF_QUIET)
291
pFileCallback = pQuietQueueCallback;
292
else
293
pFileCallback = pQueueCallback;
294
295
/* perform the file copy */
296
if (!SetupCommitFileQueueW(hwnd, fileQueue, pFileCallback, pContext))
297
{
298
dwLastError = GetLastError();
299
goto done;
300
}
301
302
done:
303
SetupTermDefaultQueueCallback(pContext);
304
SetupCloseFileQueue(fileQueue);
305
306
free(szDestFilename);
307
308
return HRESULT_FROM_WIN32(dwLastError);
309
}
310
311
static HRESULT DELNODE_recurse_dirtree(LPWSTR fname, DWORD flags)
312
{
313
DWORD fattrs = GetFileAttributesW(fname);
314
HRESULT ret = E_FAIL;
315
316
if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
317
{
318
HANDLE hFindFile;
319
WIN32_FIND_DATAW w32fd;
320
BOOL done = TRUE;
321
int fname_len = lstrlenW(fname);
322
323
if (!(flags & ADN_DEL_IF_EMPTY))
324
{
325
/* Generate a path with wildcard suitable for iterating */
326
if (fname_len && fname[fname_len-1] != '\\') fname[fname_len++] = '\\';
327
lstrcpyW(fname + fname_len, L"*");
328
329
if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE)
330
{
331
/* Iterate through the files in the directory */
332
for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd))
333
{
334
TRACE("%s\n", debugstr_w(w32fd.cFileName));
335
if (lstrcmpW(L".", w32fd.cFileName) != 0 && lstrcmpW(L"..", w32fd.cFileName) != 0)
336
{
337
lstrcpyW(fname + fname_len, w32fd.cFileName);
338
if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
339
{
340
break; /* Failure */
341
}
342
}
343
}
344
FindClose(hFindFile);
345
}
346
347
/* We're done with this directory, so restore the old path without wildcard */
348
*(fname + fname_len) = '\0';
349
}
350
351
if (done)
352
{
353
TRACE("%s: directory\n", debugstr_w(fname));
354
if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryW(fname))
355
{
356
ret = S_OK;
357
}
358
}
359
}
360
else
361
{
362
TRACE("%s: file\n", debugstr_w(fname));
363
if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileW(fname))
364
{
365
ret = S_OK;
366
}
367
}
368
369
return ret;
370
}
371
372
/***********************************************************************
373
* DelNodeA (ADVPACK.@)
374
*
375
* See DelNodeW.
376
*/
377
HRESULT WINAPI DelNodeA(LPCSTR pszFileOrDirName, DWORD dwFlags)
378
{
379
UNICODE_STRING fileordirname;
380
HRESULT res;
381
382
TRACE("(%s, %ld)\n", debugstr_a(pszFileOrDirName), dwFlags);
383
384
RtlCreateUnicodeStringFromAsciiz(&fileordirname, pszFileOrDirName);
385
386
res = DelNodeW(fileordirname.Buffer, dwFlags);
387
388
RtlFreeUnicodeString(&fileordirname);
389
390
return res;
391
}
392
393
/***********************************************************************
394
* DelNodeW (ADVPACK.@)
395
*
396
* Deletes a file or directory
397
*
398
* PARAMS
399
* pszFileOrDirName [I] Name of file or directory to delete
400
* dwFlags [I] Flags; see include/advpub.h
401
*
402
* RETURNS
403
* Success: S_OK
404
* Failure: E_FAIL
405
*
406
* BUGS
407
* - Ignores flags
408
* - Native version apparently does a lot of checking to make sure
409
* we're not trying to delete a system directory etc.
410
*/
411
HRESULT WINAPI DelNodeW(LPCWSTR pszFileOrDirName, DWORD dwFlags)
412
{
413
WCHAR fname[MAX_PATH];
414
HRESULT ret = E_FAIL;
415
416
TRACE("(%s, %ld)\n", debugstr_w(pszFileOrDirName), dwFlags);
417
418
if (dwFlags)
419
FIXME("Flags ignored!\n");
420
421
if (pszFileOrDirName && *pszFileOrDirName)
422
{
423
lstrcpyW(fname, pszFileOrDirName);
424
425
/* TODO: Should check for system directory deletion etc. here */
426
427
ret = DELNODE_recurse_dirtree(fname, dwFlags);
428
}
429
430
return ret;
431
}
432
433
/***********************************************************************
434
* DelNodeRunDLL32A (ADVPACK.@)
435
*
436
* See DelNodeRunDLL32W.
437
*/
438
HRESULT WINAPI DelNodeRunDLL32A(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
439
{
440
UNICODE_STRING params;
441
HRESULT hr;
442
443
TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
444
445
RtlCreateUnicodeStringFromAsciiz(&params, cmdline);
446
447
hr = DelNodeRunDLL32W(hWnd, hInst, params.Buffer, show);
448
449
RtlFreeUnicodeString(&params);
450
451
return hr;
452
}
453
454
/***********************************************************************
455
* DelNodeRunDLL32W (ADVPACK.@)
456
*
457
* Deletes a file or directory, WinMain style.
458
*
459
* PARAMS
460
* hWnd [I] Handle to the window used for the display.
461
* hInst [I] Instance of the process.
462
* cmdline [I] Contains parameters in the order FileOrDirName,Flags.
463
* show [I] How the window should be shown.
464
*
465
* RETURNS
466
* Success: S_OK.
467
* Failure: E_FAIL.
468
*/
469
HRESULT WINAPI DelNodeRunDLL32W(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
470
{
471
LPWSTR szFilename, szFlags;
472
LPWSTR cmdline_copy, cmdline_ptr;
473
DWORD dwFlags = 0;
474
HRESULT res;
475
476
TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_w(cmdline), show);
477
478
cmdline_copy = wcsdup(cmdline);
479
cmdline_ptr = cmdline_copy;
480
481
/* get the parameters at indexes 0 and 1 respectively */
482
szFilename = get_parameter(&cmdline_ptr, ',', TRUE);
483
szFlags = get_parameter(&cmdline_ptr, ',', TRUE);
484
485
if (szFlags)
486
dwFlags = wcstol(szFlags, NULL, 10);
487
488
res = DelNodeW(szFilename, dwFlags);
489
490
free(cmdline_copy);
491
492
return res;
493
}
494
495
/* The following definitions were copied from dlls/cabinet/cabinet.h */
496
497
/* SESSION Operation */
498
#define EXTRACT_FILLFILELIST 0x00000001
499
#define EXTRACT_EXTRACTFILES 0x00000002
500
501
struct FILELIST{
502
LPSTR FileName;
503
struct FILELIST *next;
504
BOOL DoExtract;
505
};
506
507
typedef struct {
508
INT FileSize;
509
ERF Error;
510
struct FILELIST *FileList;
511
INT FileCount;
512
INT Operation;
513
CHAR Destination[MAX_PATH];
514
CHAR CurrentFile[MAX_PATH];
515
CHAR Reserved[MAX_PATH];
516
struct FILELIST *FilterList;
517
} SESSION;
518
519
static HRESULT (WINAPI *pExtract)(SESSION*, LPCSTR);
520
521
/* removes legal characters before and after file list, and
522
* converts the file list to a NULL-separated list
523
*/
524
static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles)
525
{
526
DWORD dwLen;
527
const char *first = FileList;
528
const char *last = FileList + strlen(FileList) - 1;
529
LPSTR szConvertedList, temp;
530
531
/* any number of these chars before the list is OK */
532
while (first < last && (*first == ' ' || *first == '\t' || *first == ':'))
533
first++;
534
535
/* any number of these chars after the list is OK */
536
while (last > first && (*last == ' ' || *last == '\t' || *last == ':'))
537
last--;
538
539
if (first == last)
540
return NULL;
541
542
dwLen = last - first + 3; /* room for double-null termination */
543
szConvertedList = malloc(dwLen);
544
lstrcpynA(szConvertedList, first, dwLen - 1);
545
szConvertedList[dwLen - 1] = '\0';
546
547
/* empty list */
548
if (!szConvertedList[0])
549
{
550
free(szConvertedList);
551
return NULL;
552
}
553
554
*dwNumFiles = 1;
555
556
/* convert the colons to double-null termination */
557
temp = szConvertedList;
558
while (*temp)
559
{
560
if (*temp == ':')
561
{
562
*temp = '\0';
563
(*dwNumFiles)++;
564
}
565
566
temp++;
567
}
568
569
return szConvertedList;
570
}
571
572
static void free_file_node(struct FILELIST *pNode)
573
{
574
free(pNode->FileName);
575
free(pNode);
576
}
577
578
/* determines whether szFile is in the NULL-separated szFileList */
579
static BOOL file_in_list(LPCSTR szFile, LPCSTR szFileList)
580
{
581
DWORD dwLen = lstrlenA(szFile);
582
DWORD dwTestLen;
583
584
while (*szFileList)
585
{
586
dwTestLen = lstrlenA(szFileList);
587
588
if (dwTestLen == dwLen)
589
{
590
if (!lstrcmpiA(szFile, szFileList))
591
return TRUE;
592
}
593
594
szFileList += dwTestLen + 1;
595
}
596
597
return FALSE;
598
}
599
600
601
/* returns the number of files that are in both the linked list and szFileList */
602
static DWORD fill_file_list(SESSION *session, LPCSTR szCabName, LPCSTR szFileList)
603
{
604
DWORD dwNumFound = 0;
605
struct FILELIST *pNode;
606
607
session->Operation |= EXTRACT_FILLFILELIST;
608
if (pExtract(session, szCabName) != S_OK)
609
{
610
session->Operation &= ~EXTRACT_FILLFILELIST;
611
return -1;
612
}
613
614
pNode = session->FileList;
615
while (pNode)
616
{
617
if (!file_in_list(pNode->FileName, szFileList))
618
pNode->DoExtract = FALSE;
619
else
620
dwNumFound++;
621
622
pNode = pNode->next;
623
}
624
625
session->Operation &= ~EXTRACT_FILLFILELIST;
626
return dwNumFound;
627
}
628
629
static void free_file_list(SESSION* session)
630
{
631
struct FILELIST *next, *curr = session->FileList;
632
633
while (curr)
634
{
635
next = curr->next;
636
free_file_node(curr);
637
curr = next;
638
}
639
}
640
641
/***********************************************************************
642
* ExtractFilesA (ADVPACK.@)
643
*
644
* Extracts the specified files from a cab archive into
645
* a destination directory.
646
*
647
* PARAMS
648
* CabName [I] Filename of the cab archive.
649
* ExpandDir [I] Destination directory for the extracted files.
650
* Flags [I] Reserved.
651
* FileList [I] Optional list of files to extract. See NOTES.
652
* LReserved [I] Reserved. Must be NULL.
653
* Reserved [I] Reserved. Must be 0.
654
*
655
* RETURNS
656
* Success: S_OK.
657
* Failure: E_FAIL.
658
*
659
* NOTES
660
* FileList is a colon-separated list of filenames. If FileList is
661
* non-NULL, only the files in the list will be extracted from the
662
* cab file, otherwise all files will be extracted. Any number of
663
* spaces, tabs, or colons can be before or after the list, but
664
* the list itself must only be separated by colons.
665
*/
666
HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
667
LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
668
{
669
SESSION session;
670
HMODULE hCabinet;
671
HRESULT res = S_OK;
672
DWORD dwFileCount = 0;
673
DWORD dwFilesFound = 0;
674
LPSTR szConvertedList = NULL;
675
676
TRACE("(%s, %s, %ld, %s, %p, %ld)\n", debugstr_a(CabName), debugstr_a(ExpandDir),
677
Flags, debugstr_a(FileList), LReserved, Reserved);
678
679
if (!CabName || !ExpandDir)
680
return E_INVALIDARG;
681
682
if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
683
return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
684
685
hCabinet = LoadLibraryA("cabinet.dll");
686
if (!hCabinet)
687
return E_FAIL;
688
689
ZeroMemory(&session, sizeof(SESSION));
690
691
pExtract = (void *)GetProcAddress(hCabinet, "Extract");
692
if (!pExtract)
693
{
694
res = E_FAIL;
695
goto done;
696
}
697
698
lstrcpyA(session.Destination, ExpandDir);
699
700
if (FileList)
701
{
702
szConvertedList = convert_file_list(FileList, &dwFileCount);
703
if (!szConvertedList)
704
{
705
res = E_FAIL;
706
goto done;
707
}
708
709
dwFilesFound = fill_file_list(&session, CabName, szConvertedList);
710
if (dwFilesFound != dwFileCount)
711
{
712
res = E_FAIL;
713
goto done;
714
}
715
}
716
else
717
session.Operation |= EXTRACT_FILLFILELIST;
718
719
session.Operation |= EXTRACT_EXTRACTFILES;
720
res = pExtract(&session, CabName);
721
722
done:
723
free_file_list(&session);
724
FreeLibrary(hCabinet);
725
free(szConvertedList);
726
727
return res;
728
}
729
730
/***********************************************************************
731
* ExtractFilesW (ADVPACK.@)
732
*
733
* Extracts the specified files from a cab archive into
734
* a destination directory.
735
*
736
* PARAMS
737
* CabName [I] Filename of the cab archive.
738
* ExpandDir [I] Destination directory for the extracted files.
739
* Flags [I] Reserved.
740
* FileList [I] Optional list of files to extract. See NOTES.
741
* LReserved [I] Reserved. Must be NULL.
742
* Reserved [I] Reserved. Must be 0.
743
*
744
* RETURNS
745
* Success: S_OK.
746
* Failure: E_FAIL.
747
*
748
* NOTES
749
* FileList is a colon-separated list of filenames. If FileList is
750
* non-NULL, only the files in the list will be extracted from the
751
* cab file, otherwise all files will be extracted. Any number of
752
* spaces, tabs, or colons can be before or after the list, but
753
* the list itself must only be separated by colons.
754
*
755
* BUGS
756
* Unimplemented.
757
*/
758
HRESULT WINAPI ExtractFilesW(LPCWSTR CabName, LPCWSTR ExpandDir, DWORD Flags,
759
LPCWSTR FileList, LPVOID LReserved, DWORD Reserved)
760
{
761
char *cab_name = NULL, *expand_dir = NULL, *file_list = NULL;
762
HRESULT hres = S_OK;
763
764
TRACE("(%s, %s, %ld, %s, %p, %ld)\n", debugstr_w(CabName), debugstr_w(ExpandDir),
765
Flags, debugstr_w(FileList), LReserved, Reserved);
766
767
if(CabName) {
768
cab_name = strdupWtoA(CabName);
769
if(!cab_name)
770
return E_OUTOFMEMORY;
771
}
772
773
if(ExpandDir) {
774
expand_dir = strdupWtoA(ExpandDir);
775
if(!expand_dir)
776
hres = E_OUTOFMEMORY;
777
}
778
779
if(SUCCEEDED(hres) && FileList) {
780
file_list = strdupWtoA(FileList);
781
if(!file_list)
782
hres = E_OUTOFMEMORY;
783
}
784
785
/* cabinet.dll, which does the real job of extracting files, doesn't have UNICODE API,
786
so we need W->A conversion at some point anyway. */
787
if(SUCCEEDED(hres))
788
hres = ExtractFilesA(cab_name, expand_dir, Flags, file_list, LReserved, Reserved);
789
790
free(cab_name);
791
free(expand_dir);
792
free(file_list);
793
return hres;
794
}
795
796
/***********************************************************************
797
* FileSaveMarkNotExistA (ADVPACK.@)
798
*
799
* See FileSaveMarkNotExistW.
800
*/
801
HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
802
{
803
TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList),
804
debugstr_a(pszDir), debugstr_a(pszBaseName));
805
806
return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
807
}
808
809
/***********************************************************************
810
* FileSaveMarkNotExistW (ADVPACK.@)
811
*
812
* Marks the files in the file list as not existing so they won't be
813
* backed up during a save.
814
*
815
* PARAMS
816
* pszFileList [I] NULL-separated list of filenames.
817
* pszDir [I] Path of the backup directory.
818
* pszBaseName [I] Basename of the INI file.
819
*
820
* RETURNS
821
* Success: S_OK.
822
* Failure: E_FAIL.
823
*/
824
HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName)
825
{
826
TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList),
827
debugstr_w(pszDir), debugstr_w(pszBaseName));
828
829
return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
830
}
831
832
/***********************************************************************
833
* FileSaveRestoreA (ADVPACK.@)
834
*
835
* See FileSaveRestoreW.
836
*/
837
HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
838
LPSTR pszBaseName, DWORD dwFlags)
839
{
840
UNICODE_STRING filelist, dir, basename;
841
HRESULT hr;
842
843
TRACE("(%p, %s, %s, %s, %ld)\n", hDlg, debugstr_a(pszFileList),
844
debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags);
845
846
RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList);
847
RtlCreateUnicodeStringFromAsciiz(&dir, pszDir);
848
RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName);
849
850
hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer,
851
basename.Buffer, dwFlags);
852
853
RtlFreeUnicodeString(&filelist);
854
RtlFreeUnicodeString(&dir);
855
RtlFreeUnicodeString(&basename);
856
857
return hr;
858
}
859
860
/***********************************************************************
861
* FileSaveRestoreW (ADVPACK.@)
862
*
863
* Saves or restores the files in the specified file list.
864
*
865
* PARAMS
866
* hDlg [I] Handle to the dialog used for the display.
867
* pszFileList [I] NULL-separated list of filenames.
868
* pszDir [I] Path of the backup directory.
869
* pszBaseName [I] Basename of the backup files.
870
* dwFlags [I] See advpub.h.
871
*
872
* RETURNS
873
* Success: S_OK.
874
* Failure: E_FAIL.
875
*
876
* NOTES
877
* If pszFileList is NULL on restore, all files will be restored.
878
*
879
* BUGS
880
* Unimplemented.
881
*/
882
HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir,
883
LPWSTR pszBaseName, DWORD dwFlags)
884
{
885
FIXME("(%p, %s, %s, %s, %ld) stub\n", hDlg, debugstr_w(pszFileList),
886
debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags);
887
888
return E_FAIL;
889
}
890
891
/***********************************************************************
892
* FileSaveRestoreOnINFA (ADVPACK.@)
893
*
894
* See FileSaveRestoreOnINFW.
895
*/
896
HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF,
897
LPCSTR pszSection, LPCSTR pszBackupDir,
898
LPCSTR pszBaseBackupFile, DWORD dwFlags)
899
{
900
UNICODE_STRING title, inf, section;
901
UNICODE_STRING backupdir, backupfile;
902
HRESULT hr;
903
904
TRACE("(%p, %s, %s, %s, %s, %s, %ld)\n", hWnd, debugstr_a(pszTitle),
905
debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir),
906
debugstr_a(pszBaseBackupFile), dwFlags);
907
908
RtlCreateUnicodeStringFromAsciiz(&title, pszTitle);
909
RtlCreateUnicodeStringFromAsciiz(&inf, pszINF);
910
RtlCreateUnicodeStringFromAsciiz(&section, pszSection);
911
RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir);
912
RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile);
913
914
hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer,
915
backupdir.Buffer, backupfile.Buffer, dwFlags);
916
917
RtlFreeUnicodeString(&title);
918
RtlFreeUnicodeString(&inf);
919
RtlFreeUnicodeString(&section);
920
RtlFreeUnicodeString(&backupdir);
921
RtlFreeUnicodeString(&backupfile);
922
923
return hr;
924
}
925
926
/***********************************************************************
927
* FileSaveRestoreOnINFW (ADVPACK.@)
928
*
929
*
930
* PARAMS
931
* hWnd [I] Handle to the window used for the display.
932
* pszTitle [I] Title of the window.
933
* pszINF [I] Fully-qualified INF filename.
934
* pszSection [I] GenInstall INF section name.
935
* pszBackupDir [I] Directory to store the backup file.
936
* pszBaseBackupFile [I] Basename of the backup files.
937
* dwFlags [I] See advpub.h
938
*
939
* RETURNS
940
* Success: S_OK.
941
* Failure: E_FAIL.
942
*
943
* NOTES
944
* If pszSection is NULL, the default section will be used.
945
*
946
* BUGS
947
* Unimplemented.
948
*/
949
HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF,
950
LPCWSTR pszSection, LPCWSTR pszBackupDir,
951
LPCWSTR pszBaseBackupFile, DWORD dwFlags)
952
{
953
FIXME("(%p, %s, %s, %s, %s, %s, %ld): stub\n", hWnd, debugstr_w(pszTitle),
954
debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir),
955
debugstr_w(pszBaseBackupFile), dwFlags);
956
957
return E_FAIL;
958
}
959
960
/***********************************************************************
961
* GetVersionFromFileA (ADVPACK.@)
962
*
963
* See GetVersionFromFileExW.
964
*/
965
HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer,
966
LPDWORD MinorVer, BOOL Version )
967
{
968
TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version);
969
return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version);
970
}
971
972
/***********************************************************************
973
* GetVersionFromFileW (ADVPACK.@)
974
*
975
* See GetVersionFromFileExW.
976
*/
977
HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer,
978
LPDWORD MinorVer, BOOL Version )
979
{
980
TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version);
981
return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version);
982
}
983
984
/* data for GetVersionFromFileEx */
985
typedef struct tagLANGANDCODEPAGE
986
{
987
WORD wLanguage;
988
WORD wCodePage;
989
} LANGANDCODEPAGE;
990
991
/***********************************************************************
992
* GetVersionFromFileExA (ADVPACK.@)
993
*
994
* See GetVersionFromFileExW.
995
*/
996
HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer,
997
LPDWORD pdwLSVer, BOOL bVersion )
998
{
999
UNICODE_STRING filename;
1000
HRESULT res;
1001
1002
TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename),
1003
pdwMSVer, pdwLSVer, bVersion);
1004
1005
RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename);
1006
1007
res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion);
1008
1009
RtlFreeUnicodeString(&filename);
1010
1011
return res;
1012
}
1013
1014
/***********************************************************************
1015
* GetVersionFromFileExW (ADVPACK.@)
1016
*
1017
* Gets the files version or language information.
1018
*
1019
* PARAMS
1020
* lpszFilename [I] The file to get the info from.
1021
* pdwMSVer [O] Major version.
1022
* pdwLSVer [O] Minor version.
1023
* bVersion [I] Whether to retrieve version or language info.
1024
*
1025
* RETURNS
1026
* Always returns S_OK.
1027
*
1028
* NOTES
1029
* If bVersion is TRUE, version information is retrieved, else
1030
* pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
1031
*/
1032
HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer,
1033
LPDWORD pdwLSVer, BOOL bVersion )
1034
{
1035
VS_FIXEDFILEINFO *pFixedVersionInfo;
1036
LANGANDCODEPAGE *pLangAndCodePage;
1037
DWORD dwHandle, dwInfoSize;
1038
WCHAR szWinDir[MAX_PATH];
1039
WCHAR szFile[MAX_PATH];
1040
LPVOID pVersionInfo = NULL;
1041
BOOL bFileCopied = FALSE;
1042
UINT uValueLen;
1043
1044
TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename),
1045
pdwMSVer, pdwLSVer, bVersion);
1046
1047
*pdwLSVer = 0;
1048
*pdwMSVer = 0;
1049
1050
lstrcpynW(szFile, lpszFilename, MAX_PATH);
1051
1052
dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1053
if (!dwInfoSize)
1054
{
1055
/* check that the file exists */
1056
if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
1057
return S_OK;
1058
1059
/* file exists, but won't be found by GetFileVersionInfoSize,
1060
* so copy it to the temp dir where it will be found.
1061
*/
1062
GetWindowsDirectoryW(szWinDir, MAX_PATH);
1063
GetTempFileNameW(szWinDir, NULL, 0, szFile);
1064
CopyFileW(lpszFilename, szFile, FALSE);
1065
bFileCopied = TRUE;
1066
1067
dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1068
if (!dwInfoSize)
1069
goto done;
1070
}
1071
1072
pVersionInfo = malloc(dwInfoSize);
1073
if (!pVersionInfo)
1074
goto done;
1075
1076
if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo))
1077
goto done;
1078
1079
if (bVersion)
1080
{
1081
if (!VerQueryValueW(pVersionInfo, L"\\", (void **)&pFixedVersionInfo, &uValueLen))
1082
goto done;
1083
1084
if (!uValueLen)
1085
goto done;
1086
1087
*pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
1088
*pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
1089
}
1090
else
1091
{
1092
if (!VerQueryValueW(pVersionInfo, L"\\VarFileInfo\\Translation",
1093
(LPVOID *)&pLangAndCodePage, &uValueLen))
1094
goto done;
1095
1096
if (!uValueLen)
1097
goto done;
1098
1099
*pdwMSVer = pLangAndCodePage->wLanguage;
1100
*pdwLSVer = pLangAndCodePage->wCodePage;
1101
}
1102
1103
done:
1104
free(pVersionInfo);
1105
1106
if (bFileCopied)
1107
DeleteFileW(szFile);
1108
1109
return S_OK;
1110
}
1111
1112