ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

media.c
Go to the documentation of this file.
00001 /*
00002  * Implementation of the Microsoft Installer (msi.dll)
00003  *
00004  * Copyright 2008 James Hawkins
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <stdarg.h>
00022 
00023 #define COBJMACROS
00024 
00025 #include "windef.h"
00026 #include "winerror.h"
00027 #include "wine/debug.h"
00028 #include "fdi.h"
00029 #include "msipriv.h"
00030 #include "winuser.h"
00031 #include "winreg.h"
00032 #include "shlwapi.h"
00033 #include "objidl.h"
00034 #include "wine/unicode.h"
00035 
00036 WINE_DEFAULT_DEBUG_CHANNEL(msi);
00037 
00038 /* from msvcrt/fcntl.h */
00039 #define _O_RDONLY      0
00040 #define _O_WRONLY      1
00041 #define _O_RDWR        2
00042 #define _O_ACCMODE     (_O_RDONLY|_O_WRONLY|_O_RDWR)
00043 #define _O_APPEND      0x0008
00044 #define _O_RANDOM      0x0010
00045 #define _O_SEQUENTIAL  0x0020
00046 #define _O_TEMPORARY   0x0040
00047 #define _O_NOINHERIT   0x0080
00048 #define _O_CREAT       0x0100
00049 #define _O_TRUNC       0x0200
00050 #define _O_EXCL        0x0400
00051 #define _O_SHORT_LIVED 0x1000
00052 #define _O_TEXT        0x4000
00053 #define _O_BINARY      0x8000
00054 
00055 static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
00056 {
00057     WCHAR volume_name[MAX_PATH + 1];
00058     WCHAR root[MAX_PATH + 1];
00059 
00060     strcpyW(root, source_root);
00061     PathStripToRootW(root);
00062     PathAddBackslashW(root);
00063 
00064     if (!GetVolumeInformationW(root, volume_name, MAX_PATH + 1, NULL, NULL, NULL, NULL, 0))
00065     {
00066         WARN("failed to get volume information for %s (%u)\n", debugstr_w(root), GetLastError());
00067         return FALSE;
00068     }
00069     return !strcmpiW( mi->volume_label, volume_name );
00070 }
00071 
00072 static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
00073 {
00074     LPWSTR error, error_dialog;
00075     LPWSTR source_dir;
00076     UINT r = ERROR_SUCCESS;
00077 
00078     static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0};
00079 
00080     if ((package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE &&
00081         !gUIHandlerA && !gUIHandlerW && !gUIHandlerRecord) return ERROR_SUCCESS;
00082 
00083     error = msi_build_error_string(package, 1302, 1, mi->disk_prompt);
00084     error_dialog = msi_dup_property(package->db, error_prop);
00085     source_dir = msi_dup_property(package->db, szSourceDir);
00086 
00087     while (r == ERROR_SUCCESS && !source_matches_volume(mi, source_dir))
00088     {
00089         r = msi_spawn_error_dialog(package, error_dialog, error);
00090 
00091         if (gUIHandlerW)
00092         {
00093             gUIHandlerW(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, error);
00094         }
00095         else if (gUIHandlerA)
00096         {
00097             char *msg = strdupWtoA(error);
00098             gUIHandlerA(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, msg);
00099             msi_free(msg);
00100         }
00101         else if (gUIHandlerRecord)
00102         {
00103             MSIHANDLE rec = MsiCreateRecord(1);
00104             MsiRecordSetStringW(rec, 0, error);
00105             gUIHandlerRecord(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, rec);
00106             MsiCloseHandle(rec);
00107         }
00108     }
00109 
00110     msi_free(error);
00111     msi_free(error_dialog);
00112     msi_free(source_dir);
00113 
00114     return r;
00115 }
00116 
00117 static MSICABINETSTREAM *msi_get_cabinet_stream( MSIPACKAGE *package, UINT disk_id )
00118 {
00119     MSICABINETSTREAM *cab;
00120 
00121     LIST_FOR_EACH_ENTRY( cab, &package->cabinet_streams, MSICABINETSTREAM, entry )
00122     {
00123         if (cab->disk_id == disk_id) return cab;
00124     }
00125     return NULL;
00126 }
00127 
00128 static void * CDECL cabinet_alloc(ULONG cb)
00129 {
00130     return msi_alloc(cb);
00131 }
00132 
00133 static void CDECL cabinet_free(void *pv)
00134 {
00135     msi_free(pv);
00136 }
00137 
00138 static INT_PTR CDECL cabinet_open(char *pszFile, int oflag, int pmode)
00139 {
00140     HANDLE handle;
00141     DWORD dwAccess = 0;
00142     DWORD dwShareMode = 0;
00143     DWORD dwCreateDisposition = OPEN_EXISTING;
00144 
00145     switch (oflag & _O_ACCMODE)
00146     {
00147     case _O_RDONLY:
00148         dwAccess = GENERIC_READ;
00149         dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
00150         break;
00151     case _O_WRONLY:
00152         dwAccess = GENERIC_WRITE;
00153         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
00154         break;
00155     case _O_RDWR:
00156         dwAccess = GENERIC_READ | GENERIC_WRITE;
00157         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
00158         break;
00159     }
00160 
00161     if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
00162         dwCreateDisposition = CREATE_NEW;
00163     else if (oflag & _O_CREAT)
00164         dwCreateDisposition = CREATE_ALWAYS;
00165 
00166     handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
00167                          dwCreateDisposition, 0, NULL);
00168     if (handle == INVALID_HANDLE_VALUE)
00169         return 0;
00170 
00171     return (INT_PTR)handle;
00172 }
00173 
00174 static UINT CDECL cabinet_read(INT_PTR hf, void *pv, UINT cb)
00175 {
00176     HANDLE handle = (HANDLE)hf;
00177     DWORD read;
00178 
00179     if (ReadFile(handle, pv, cb, &read, NULL))
00180         return read;
00181 
00182     return 0;
00183 }
00184 
00185 static UINT CDECL cabinet_write(INT_PTR hf, void *pv, UINT cb)
00186 {
00187     HANDLE handle = (HANDLE)hf;
00188     DWORD written;
00189 
00190     if (WriteFile(handle, pv, cb, &written, NULL))
00191         return written;
00192 
00193     return 0;
00194 }
00195 
00196 static int CDECL cabinet_close(INT_PTR hf)
00197 {
00198     HANDLE handle = (HANDLE)hf;
00199     return CloseHandle(handle) ? 0 : -1;
00200 }
00201 
00202 static LONG CDECL cabinet_seek(INT_PTR hf, LONG dist, int seektype)
00203 {
00204     HANDLE handle = (HANDLE)hf;
00205     /* flags are compatible and so are passed straight through */
00206     return SetFilePointer(handle, dist, NULL, seektype);
00207 }
00208 
00209 struct package_disk
00210 {
00211     MSIPACKAGE *package;
00212     UINT        id;
00213 };
00214 
00215 static struct package_disk package_disk;
00216 
00217 static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
00218 {
00219     MSICABINETSTREAM *cab;
00220     IStream *stream;
00221     WCHAR *encoded;
00222     HRESULT hr;
00223 
00224     cab = msi_get_cabinet_stream( package_disk.package, package_disk.id );
00225     if (!cab)
00226     {
00227         WARN("failed to get cabinet stream\n");
00228         return 0;
00229     }
00230     if (!cab->stream[0] || !(encoded = encode_streamname( FALSE, cab->stream + 1 )))
00231     {
00232         WARN("failed to encode stream name\n");
00233         return 0;
00234     }
00235     if (msi_clone_open_stream( package_disk.package->db, cab->storage, encoded, &stream ) != ERROR_SUCCESS)
00236     {
00237         hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
00238         if (FAILED(hr))
00239         {
00240             WARN("failed to open stream 0x%08x\n", hr);
00241             msi_free( encoded );
00242             return 0;
00243         }
00244     }
00245     msi_free( encoded );
00246     return (INT_PTR)stream;
00247 }
00248 
00249 static UINT CDECL cabinet_read_stream( INT_PTR hf, void *pv, UINT cb )
00250 {
00251     IStream *stm = (IStream *)hf;
00252     DWORD read;
00253     HRESULT hr;
00254 
00255     hr = IStream_Read( stm, pv, cb, &read );
00256     if (hr == S_OK || hr == S_FALSE)
00257         return read;
00258 
00259     return 0;
00260 }
00261 
00262 static int CDECL cabinet_close_stream( INT_PTR hf )
00263 {
00264     IStream *stm = (IStream *)hf;
00265     IStream_Release( stm );
00266     return 0;
00267 }
00268 
00269 static LONG CDECL cabinet_seek_stream( INT_PTR hf, LONG dist, int seektype )
00270 {
00271     IStream *stm = (IStream *)hf;
00272     LARGE_INTEGER move;
00273     ULARGE_INTEGER newpos;
00274     HRESULT hr;
00275 
00276     move.QuadPart = dist;
00277     hr = IStream_Seek( stm, move, seektype, &newpos );
00278     if (SUCCEEDED(hr))
00279     {
00280         if (newpos.QuadPart <= MAXLONG) return newpos.QuadPart;
00281         ERR("Too big!\n");
00282     }
00283     return -1;
00284 }
00285 
00286 static UINT CDECL msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi)
00287 {
00288     MSIRECORD *row;
00289 
00290     static const WCHAR query[] = {
00291         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
00292         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
00293         '`','D','i','s','k','I','d','`',' ','=',' ','%','i',0};
00294 
00295     row = MSI_QueryGetRecord(package->db, query, mi->disk_id);
00296     if (!row)
00297     {
00298         TRACE("Unable to query row\n");
00299         return ERROR_FUNCTION_FAILED;
00300     }
00301 
00302     mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
00303     mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
00304     mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
00305 
00306     if (!mi->first_volume)
00307         mi->first_volume = strdupW(mi->volume_label);
00308 
00309     msiobj_release(&row->hdr);
00310     return ERROR_SUCCESS;
00311 }
00312 
00313 static INT_PTR cabinet_partial_file(FDINOTIFICATIONTYPE fdint,
00314                                     PFDINOTIFICATION pfdin)
00315 {
00316     MSICABDATA *data = pfdin->pv;
00317     data->mi->is_continuous = FALSE;
00318     return 0;
00319 }
00320 
00321 static WCHAR *get_cabinet_filename(MSIMEDIAINFO *mi)
00322 {
00323     int len;
00324     WCHAR *ret;
00325 
00326     len = strlenW(mi->sourcedir) + strlenW(mi->cabinet) + 1;
00327     if (!(ret = msi_alloc(len * sizeof(WCHAR)))) return NULL;
00328     strcpyW(ret, mi->sourcedir);
00329     strcatW(ret, mi->cabinet);
00330     return ret;
00331 }
00332 
00333 static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint,
00334                                     PFDINOTIFICATION pfdin)
00335 {
00336     MSICABDATA *data = pfdin->pv;
00337     MSIMEDIAINFO *mi = data->mi;
00338     LPWSTR cabinet_file = NULL, cab = strdupAtoW(pfdin->psz1);
00339     INT_PTR res = -1;
00340     UINT rc;
00341 
00342     msi_free(mi->disk_prompt);
00343     msi_free(mi->cabinet);
00344     msi_free(mi->volume_label);
00345     mi->disk_prompt = NULL;
00346     mi->cabinet = NULL;
00347     mi->volume_label = NULL;
00348 
00349     mi->disk_id++;
00350     mi->is_continuous = TRUE;
00351 
00352     rc = msi_media_get_disk_info(data->package, mi);
00353     if (rc != ERROR_SUCCESS)
00354     {
00355         ERR("Failed to get next cabinet information: %d\n", rc);
00356         goto done;
00357     }
00358 
00359     if (strcmpiW( mi->cabinet, cab ))
00360     {
00361         ERR("Continuous cabinet does not match the next cabinet in the Media table\n");
00362         goto done;
00363     }
00364 
00365     if (!(cabinet_file = get_cabinet_filename(mi)))
00366         goto done;
00367 
00368     TRACE("Searching for %s\n", debugstr_w(cabinet_file));
00369 
00370     res = 0;
00371     if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
00372     {
00373         if (msi_change_media(data->package, mi) != ERROR_SUCCESS)
00374             res = -1;
00375     }
00376 
00377 done:
00378     msi_free(cab);
00379     msi_free(cabinet_file);
00380     return res;
00381 }
00382 
00383 static INT_PTR cabinet_next_cabinet_stream( FDINOTIFICATIONTYPE fdint,
00384                                             PFDINOTIFICATION pfdin )
00385 {
00386     MSICABDATA *data = pfdin->pv;
00387     MSIMEDIAINFO *mi = data->mi;
00388     UINT rc;
00389 
00390     msi_free( mi->disk_prompt );
00391     msi_free( mi->cabinet );
00392     msi_free( mi->volume_label );
00393     mi->disk_prompt = NULL;
00394     mi->cabinet = NULL;
00395     mi->volume_label = NULL;
00396 
00397     mi->disk_id++;
00398     mi->is_continuous = TRUE;
00399 
00400     rc = msi_media_get_disk_info( data->package, mi );
00401     if (rc != ERROR_SUCCESS)
00402     {
00403         ERR("Failed to get next cabinet information: %u\n", rc);
00404         return -1;
00405     }
00406     package_disk.id = mi->disk_id;
00407 
00408     TRACE("next cabinet is %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
00409     return 0;
00410 }
00411 
00412 static INT_PTR cabinet_copy_file(FDINOTIFICATIONTYPE fdint,
00413                                  PFDINOTIFICATION pfdin)
00414 {
00415     MSICABDATA *data = pfdin->pv;
00416     HANDLE handle = 0;
00417     LPWSTR path = NULL;
00418     DWORD attrs;
00419 
00420     data->curfile = strdupAtoW(pfdin->psz1);
00421     if (!data->cb(data->package, data->curfile, MSICABEXTRACT_BEGINEXTRACT, &path,
00422                   &attrs, data->user))
00423     {
00424         /* We're not extracting this file, so free the filename. */
00425         msi_free(data->curfile);
00426         data->curfile = NULL;
00427         goto done;
00428     }
00429 
00430     TRACE("extracting %s -> %s\n", debugstr_w(data->curfile), debugstr_w(path));
00431 
00432     attrs = attrs & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
00433     if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;
00434 
00435     handle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0,
00436                          NULL, CREATE_ALWAYS, attrs, NULL);
00437     if (handle == INVALID_HANDLE_VALUE)
00438     {
00439         DWORD err = GetLastError();
00440         DWORD attrs2 = GetFileAttributesW(path);
00441 
00442         if (attrs2 == INVALID_FILE_ATTRIBUTES)
00443         {
00444             ERR("failed to create %s (error %d)\n", debugstr_w(path), err);
00445             goto done;
00446         }
00447         else if (err == ERROR_ACCESS_DENIED && (attrs2 & FILE_ATTRIBUTE_READONLY))
00448         {
00449             TRACE("removing read-only attribute on %s\n", debugstr_w(path));
00450             SetFileAttributesW( path, attrs2 & ~FILE_ATTRIBUTE_READONLY );
00451             handle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, attrs2, NULL);
00452 
00453             if (handle != INVALID_HANDLE_VALUE) goto done;
00454             err = GetLastError();
00455         }
00456         if (err == ERROR_SHARING_VIOLATION || err == ERROR_USER_MAPPED_FILE)
00457         {
00458             WCHAR *tmpfileW, *tmppathW, *p;
00459             DWORD len;
00460 
00461             TRACE("file in use, scheduling rename operation\n");
00462 
00463             if (!(tmppathW = strdupW( path ))) return ERROR_OUTOFMEMORY;
00464             if ((p = strrchrW(tmppathW, '\\'))) *p = 0;
00465             len = strlenW( tmppathW ) + 16;
00466             if (!(tmpfileW = msi_alloc(len * sizeof(WCHAR))))
00467             {
00468                 msi_free( tmppathW );
00469                 return ERROR_OUTOFMEMORY;
00470             }
00471             if (!GetTempFileNameW(tmppathW, szMsi, 0, tmpfileW)) tmpfileW[0] = 0;
00472             msi_free( tmppathW );
00473 
00474             handle = CreateFileW(tmpfileW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, attrs, NULL);
00475 
00476             if (handle != INVALID_HANDLE_VALUE &&
00477                 MoveFileExW(path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) &&
00478                 MoveFileExW(tmpfileW, path, MOVEFILE_DELAY_UNTIL_REBOOT))
00479             {
00480                 data->package->need_reboot_at_end = 1;
00481             }
00482             else
00483             {
00484                 WARN("failed to schedule rename operation %s (error %d)\n", debugstr_w(path), GetLastError());
00485                 DeleteFileW( tmpfileW );
00486             }
00487             msi_free(tmpfileW);
00488         }
00489         else
00490             WARN("failed to create %s (error %d)\n", debugstr_w(path), err);
00491     }
00492 
00493 done:
00494     msi_free(path);
00495 
00496     return (INT_PTR)handle;
00497 }
00498 
00499 static INT_PTR cabinet_close_file_info(FDINOTIFICATIONTYPE fdint,
00500                                        PFDINOTIFICATION pfdin)
00501 {
00502     MSICABDATA *data = pfdin->pv;
00503     FILETIME ft;
00504     FILETIME ftLocal;
00505     HANDLE handle = (HANDLE)pfdin->hf;
00506 
00507     data->mi->is_continuous = FALSE;
00508 
00509     if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
00510         return -1;
00511     if (!LocalFileTimeToFileTime(&ft, &ftLocal))
00512         return -1;
00513     if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
00514         return -1;
00515 
00516     CloseHandle(handle);
00517 
00518     data->cb(data->package, data->curfile, MSICABEXTRACT_FILEEXTRACTED, NULL, NULL,
00519              data->user);
00520 
00521     msi_free(data->curfile);
00522     data->curfile = NULL;
00523 
00524     return 1;
00525 }
00526 
00527 static INT_PTR CDECL cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
00528 {
00529     switch (fdint)
00530     {
00531     case fdintPARTIAL_FILE:
00532         return cabinet_partial_file(fdint, pfdin);
00533 
00534     case fdintNEXT_CABINET:
00535         return cabinet_next_cabinet(fdint, pfdin);
00536 
00537     case fdintCOPY_FILE:
00538         return cabinet_copy_file(fdint, pfdin);
00539 
00540     case fdintCLOSE_FILE_INFO:
00541         return cabinet_close_file_info(fdint, pfdin);
00542 
00543     default:
00544         return 0;
00545     }
00546 }
00547 
00548 static INT_PTR CDECL cabinet_notify_stream( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
00549 {
00550     switch (fdint)
00551     {
00552     case fdintPARTIAL_FILE:
00553         return cabinet_partial_file( fdint, pfdin );
00554 
00555     case fdintNEXT_CABINET:
00556         return cabinet_next_cabinet_stream( fdint, pfdin );
00557 
00558     case fdintCOPY_FILE:
00559         return cabinet_copy_file( fdint, pfdin );
00560 
00561     case fdintCLOSE_FILE_INFO:
00562         return cabinet_close_file_info( fdint, pfdin );
00563 
00564     case fdintCABINET_INFO:
00565         return 0;
00566 
00567     default:
00568         ERR("Unexpected notification %d\n", fdint);
00569         return 0;
00570     }
00571 }
00572 
00573 static BOOL extract_cabinet( MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data )
00574 {
00575     LPSTR cabinet, cab_path = NULL;
00576     HFDI hfdi;
00577     ERF erf;
00578     BOOL ret = FALSE;
00579 
00580     TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
00581 
00582     hfdi = FDICreate( cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
00583                       cabinet_write, cabinet_close, cabinet_seek, 0, &erf );
00584     if (!hfdi)
00585     {
00586         ERR("FDICreate failed\n");
00587         return FALSE;
00588     }
00589 
00590     cabinet = strdupWtoA( mi->cabinet );
00591     if (!cabinet)
00592         goto done;
00593 
00594     cab_path = strdupWtoA( mi->sourcedir );
00595     if (!cab_path)
00596         goto done;
00597 
00598     ret = FDICopy( hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, data );
00599     if (!ret)
00600         ERR("FDICopy failed\n");
00601 
00602 done:
00603     FDIDestroy( hfdi );
00604     msi_free(cabinet );
00605     msi_free( cab_path );
00606 
00607     if (ret)
00608         mi->is_extracted = TRUE;
00609 
00610     return ret;
00611 }
00612 
00613 static BOOL extract_cabinet_stream( MSIPACKAGE *package, MSIMEDIAINFO *mi, LPVOID data )
00614 {
00615     static char filename[] = {'<','S','T','R','E','A','M','>',0};
00616     HFDI hfdi;
00617     ERF erf;
00618     BOOL ret = FALSE;
00619 
00620     TRACE("extracting %s disk id %u\n", debugstr_w(mi->cabinet), mi->disk_id);
00621 
00622     hfdi = FDICreate( cabinet_alloc, cabinet_free, cabinet_open_stream, cabinet_read_stream,
00623                       cabinet_write, cabinet_close_stream, cabinet_seek_stream, 0, &erf );
00624     if (!hfdi)
00625     {
00626         ERR("FDICreate failed\n");
00627         return FALSE;
00628     }
00629 
00630     package_disk.package = package;
00631     package_disk.id      = mi->disk_id;
00632 
00633     ret = FDICopy( hfdi, filename, NULL, 0, cabinet_notify_stream, NULL, data );
00634     if (!ret) ERR("FDICopy failed\n");
00635 
00636     FDIDestroy( hfdi );
00637     if (ret) mi->is_extracted = TRUE;
00638     return ret;
00639 }
00640 
00641 /***********************************************************************
00642  *            msi_cabextract
00643  *
00644  * Extract files from a cabinet file or stream.
00645  */
00646 BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data)
00647 {
00648     if (mi->cabinet[0] == '#')
00649     {
00650         return extract_cabinet_stream( package, mi, data );
00651     }
00652     return extract_cabinet( package, mi, data );
00653 }
00654 
00655 void msi_free_media_info(MSIMEDIAINFO *mi)
00656 {
00657     msi_free(mi->disk_prompt);
00658     msi_free(mi->cabinet);
00659     msi_free(mi->volume_label);
00660     msi_free(mi->first_volume);
00661     msi_free(mi);
00662 }
00663 
00664 static UINT get_drive_type(const WCHAR *path)
00665 {
00666     WCHAR root[MAX_PATH + 1];
00667 
00668     strcpyW(root, path);
00669     PathStripToRootW(root);
00670     PathAddBackslashW(root);
00671 
00672     return GetDriveTypeW(root);
00673 }
00674 
00675 UINT msi_load_media_info(MSIPACKAGE *package, UINT Sequence, MSIMEDIAINFO *mi)
00676 {
00677     static const WCHAR query[] = {
00678         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
00679         'W','H','E','R','E',' ','`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
00680         '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0};
00681     MSIRECORD *row;
00682     LPWSTR source_dir, source;
00683     DWORD options;
00684 
00685     if (Sequence <= mi->last_sequence) /* already loaded */
00686         return ERROR_SUCCESS;
00687 
00688     row = MSI_QueryGetRecord(package->db, query, Sequence);
00689     if (!row)
00690     {
00691         TRACE("Unable to query row\n");
00692         return ERROR_FUNCTION_FAILED;
00693     }
00694 
00695     mi->is_extracted = FALSE;
00696     mi->disk_id = MSI_RecordGetInteger(row, 1);
00697     mi->last_sequence = MSI_RecordGetInteger(row, 2);
00698     msi_free(mi->disk_prompt);
00699     mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3));
00700     msi_free(mi->cabinet);
00701     mi->cabinet = strdupW(MSI_RecordGetString(row, 4));
00702     msi_free(mi->volume_label);
00703     mi->volume_label = strdupW(MSI_RecordGetString(row, 5));
00704     msiobj_release(&row->hdr);
00705 
00706     if (!mi->first_volume)
00707         mi->first_volume = strdupW(mi->volume_label);
00708 
00709     msi_set_sourcedir_props(package, FALSE);
00710     source_dir = msi_dup_property(package->db, szSourceDir);
00711     lstrcpyW(mi->sourcedir, source_dir);
00712     PathAddBackslashW(mi->sourcedir);
00713     mi->type = get_drive_type(source_dir);
00714 
00715     options = MSICODE_PRODUCT;
00716     if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)
00717     {
00718         source = source_dir;
00719         options |= MSISOURCETYPE_MEDIA;
00720     }
00721     else if (package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL))
00722     {
00723         source = package->BaseURL;
00724         options |= MSISOURCETYPE_URL;
00725     }
00726     else
00727     {
00728         source = mi->sourcedir;
00729         options |= MSISOURCETYPE_NETWORK;
00730     }
00731 
00732     msi_package_add_media_disk(package, package->Context,
00733                                MSICODE_PRODUCT, mi->disk_id,
00734                                mi->volume_label, mi->disk_prompt);
00735 
00736     msi_package_add_info(package, package->Context,
00737                          options, INSTALLPROPERTY_LASTUSEDSOURCEW, source);
00738 
00739     msi_free(source_dir);
00740     TRACE("sequence %u -> cabinet %s disk id %u\n", Sequence, debugstr_w(mi->cabinet), mi->disk_id);
00741     return ERROR_SUCCESS;
00742 }
00743 
00744 /* FIXME: search URL sources as well */
00745 static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi)
00746 {
00747     WCHAR source[MAX_PATH];
00748     WCHAR volume[MAX_PATH];
00749     WCHAR prompt[MAX_PATH];
00750     DWORD volumesz, promptsz;
00751     DWORD index, size, id;
00752     WCHAR last_type[2];
00753     UINT r;
00754 
00755     size = 2;
00756     r = MsiSourceListGetInfoW(package->ProductCode, NULL,
00757                               package->Context, MSICODE_PRODUCT,
00758                               INSTALLPROPERTY_LASTUSEDTYPEW, last_type, &size);
00759     if (r != ERROR_SUCCESS)
00760         return r;
00761 
00762     size = MAX_PATH;
00763     r = MsiSourceListGetInfoW(package->ProductCode, NULL,
00764                               package->Context, MSICODE_PRODUCT,
00765                               INSTALLPROPERTY_LASTUSEDSOURCEW, source, &size);
00766     if (r != ERROR_SUCCESS)
00767         return r;
00768 
00769     if (last_type[0] == 'n')
00770     {
00771         WCHAR cabinet_file[MAX_PATH];
00772         BOOL check_all = FALSE;
00773 
00774         while(TRUE)
00775         {
00776             index = 0;
00777             volumesz = MAX_PATH;
00778             while (MsiSourceListEnumSourcesW(package->ProductCode, NULL,
00779                                              package->Context,
00780                                              MSISOURCETYPE_NETWORK, index++,
00781                                              volume, &volumesz) == ERROR_SUCCESS)
00782             {
00783                 if (check_all || !strncmpiW(source, volume, strlenW(source)))
00784                 {
00785                     lstrcpyW(cabinet_file, volume);
00786                     PathAddBackslashW(cabinet_file);
00787                     lstrcatW(cabinet_file, mi->cabinet);
00788 
00789                     if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES)
00790                     {
00791                         volumesz = MAX_PATH;
00792                         if(!check_all)
00793                             break;
00794                         continue;
00795                     }
00796 
00797                     lstrcpyW(mi->sourcedir, volume);
00798                     PathAddBackslashW(mi->sourcedir);
00799                     TRACE("Found network source %s\n", debugstr_w(mi->sourcedir));
00800                     return ERROR_SUCCESS;
00801                 }
00802             }
00803 
00804             if (!check_all)
00805                 check_all = TRUE;
00806             else
00807                 break;
00808         }
00809     }
00810 
00811     index = 0;
00812     volumesz = MAX_PATH;
00813     promptsz = MAX_PATH;
00814     while (MsiSourceListEnumMediaDisksW(package->ProductCode, NULL,
00815                                         package->Context,
00816                                         MSICODE_PRODUCT, index++, &id,
00817                                         volume, &volumesz, prompt, &promptsz) == ERROR_SUCCESS)
00818     {
00819         mi->disk_id = id;
00820         msi_free( mi->volume_label );
00821         if (!(mi->volume_label = msi_alloc( ++volumesz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
00822         strcpyW( mi->volume_label, volume );
00823 
00824         msi_free( mi->disk_prompt );
00825         if (!(mi->disk_prompt = msi_alloc( ++promptsz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
00826         strcpyW( mi->disk_prompt, prompt );
00827 
00828         if (source_matches_volume(mi, source))
00829         {
00830             /* FIXME: what about SourceDir */
00831             lstrcpyW(mi->sourcedir, source);
00832             PathAddBackslashW(mi->sourcedir);
00833             TRACE("Found disk source %s\n", debugstr_w(mi->sourcedir));
00834             return ERROR_SUCCESS;
00835         }
00836     }
00837 
00838     return ERROR_FUNCTION_FAILED;
00839 }
00840 
00841 UINT ready_media( MSIPACKAGE *package, BOOL compressed, MSIMEDIAINFO *mi )
00842 {
00843     UINT rc;
00844     WCHAR *cabinet_file = NULL;
00845 
00846     /* media info for continuous cabinet is already loaded */
00847     if (mi->is_continuous) return ERROR_SUCCESS;
00848 
00849     if (mi->cabinet)
00850     {
00851         /* cabinet is internal, no checks needed */
00852         if (mi->cabinet[0] == '#') return ERROR_SUCCESS;
00853 
00854         if (!(cabinet_file = get_cabinet_filename( mi ))) return ERROR_OUTOFMEMORY;
00855 
00856         /* package should be downloaded */
00857         if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES &&
00858             package->BaseURL && UrlIsW( package->BaseURL, URLIS_URL ))
00859         {
00860             WCHAR temppath[MAX_PATH], *p;
00861 
00862             if ((rc = msi_download_file( cabinet_file, temppath )) != ERROR_SUCCESS)
00863             {
00864                 ERR("failed to download %s (%u)\n", debugstr_w(cabinet_file), rc);
00865                 msi_free( cabinet_file );
00866                 return rc;
00867             }
00868             if ((p = strrchrW( temppath, '\\' ))) *p = 0;
00869             strcpyW( mi->sourcedir, temppath );
00870             PathAddBackslashW( mi->sourcedir );
00871             msi_free( mi->cabinet );
00872             mi->cabinet = strdupW( p + 1 );
00873             msi_free( cabinet_file );
00874             return ERROR_SUCCESS;
00875         }
00876     }
00877     /* check volume matches, change media if not */
00878     if (mi->volume_label && mi->disk_id > 1 && strcmpW( mi->first_volume, mi->volume_label ))
00879     {
00880         WCHAR *source = msi_dup_property( package->db, szSourceDir );
00881         BOOL match = source_matches_volume( mi, source );
00882         msi_free( source );
00883 
00884         if (!match && (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE))
00885         {
00886             if ((rc = msi_change_media( package, mi )) != ERROR_SUCCESS)
00887             {
00888                 msi_free( cabinet_file );
00889                 return rc;
00890             }
00891         }
00892     }
00893     if (mi->cabinet)
00894     {
00895         if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES)
00896         {
00897             if ((rc = find_published_source( package, mi )) != ERROR_SUCCESS)
00898             {
00899                 ERR("cabinet not found: %s\n", debugstr_w(cabinet_file));
00900                 msi_free( cabinet_file );
00901                 return ERROR_INSTALL_FAILURE;
00902             }
00903         }
00904     }
00905     msi_free( cabinet_file );
00906     return ERROR_SUCCESS;
00907 }
00908 
00909 UINT msi_add_cabinet_stream( MSIPACKAGE *package, UINT disk_id, IStorage *storage, const WCHAR *name )
00910 {
00911     MSICABINETSTREAM *cab, *item;
00912 
00913     TRACE("%p, %u, %p, %s\n", package, disk_id, storage, debugstr_w(name));
00914 
00915     LIST_FOR_EACH_ENTRY( item, &package->cabinet_streams, MSICABINETSTREAM, entry )
00916     {
00917         if (item->disk_id == disk_id)
00918         {
00919             TRACE("duplicate disk id %u\n", disk_id);
00920             return ERROR_FUNCTION_FAILED;
00921         }
00922     }
00923     if (!(cab = msi_alloc( sizeof(*cab) ))) return ERROR_OUTOFMEMORY;
00924     if (!(cab->stream = msi_alloc( (strlenW( name ) + 1) * sizeof(WCHAR ) )))
00925     {
00926         msi_free( cab );
00927         return ERROR_OUTOFMEMORY;
00928     }
00929     strcpyW( cab->stream, name );
00930     cab->disk_id = disk_id;
00931     cab->storage = storage;
00932     IStorage_AddRef( storage );
00933     list_add_tail( &package->cabinet_streams, &cab->entry );
00934 
00935     return ERROR_SUCCESS;
00936 }

Generated on Mon May 28 2012 04:23:12 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.