/*********************************************************************** * msidbExportStream * * Exports a stream to a file with an .idb extension. * * Examples (note wildcard escape for *nix/bash): * msidb -d <pathtomsi>.msi -f <workdir> -x <streamname> * msidb -d <pathtomsi>.msi -f <workdir> -x data.cab **********************************************************************/ static BOOL msidbExportStream(LPCWSTR dbfile, LPCWSTR wdir, LPCWSTR streamName) { static const char ext[] = {'.', 'i', 'd', 'b', 0}; UINT r, len; MSIHANDLE dbhandle, streamListView, rec; char queryBuffer[100]; FILE *fp = 0; char *streamNameA = strdupWtoA(CP_ACP, streamName); char *wdirA = strdupWtoA(CP_ACP, wdir); char *streamFileA = 0; char streamPath[MAX_PATH]; char *dataBuffer; DWORD dataLen = 0; r = MsiOpenDatabaseW(dbfile, (LPCWSTR) MSIDBOPEN_READONLY, &dbhandle); if (r != ERROR_SUCCESS) return FALSE; sprintf(queryBuffer, "SELECT * FROM _Streams WHERE Name = '%s'", streamNameA); MsiDatabaseOpenView(dbhandle, queryBuffer, &streamListView); MsiViewExecute(streamListView, 0); r = MsiViewFetch(streamListView, &rec); if (r != ERROR_SUCCESS) return FALSE; if (MsiRecordReadStream(rec, 2, 0, &dataLen) != ERROR_SUCCESS) return FALSE; dataBuffer = malloc(dataLen); if (!dataBuffer) return FALSE; if (MsiRecordReadStream(rec, 2, dataBuffer, &dataLen) != ERROR_SUCCESS) return FALSE; len = strlen(streamNameA) + 5; streamFileA = malloc(len); if (streamFileA == NULL) return FALSE; strcpy(streamFileA, streamNameA); strcat(streamFileA, ext); strcpy(streamPath, wdirA); strcat(streamPath, PATH_DELIMITER); strcat(streamPath, streamFileA); fp = fopen(streamPath , "wb"); if (fp != NULL) { fwrite(dataBuffer, 1, dataLen, fp); fclose(fp); } free(streamFileA); MsiCloseHandle(rec); MsiViewClose(streamListView); MsiCloseHandle(streamListView); MsiCloseHandle(dbhandle); free(wdirA); free(streamNameA); return TRUE; }
/*********************************************************************** * extract_cabinet_file * * Extract files from a cab file. */ static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source, LPCWSTR path) { HFDI hfdi; ERF erf; BOOL ret; char *cabinet; char *cab_path; CabData data; TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path)); hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read, cabinet_write, cabinet_close, cabinet_seek, 0, &erf); if (!hfdi) { ERR("FDICreate failed\n"); return FALSE; } if (!(cabinet = strdupWtoA( source ))) { FDIDestroy(hfdi); return FALSE; } if (!(cab_path = strdupWtoA( path ))) { FDIDestroy(hfdi); msi_free(cabinet); return FALSE; } data.package = package; data.cab_path = cab_path; ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); if (!ret) ERR("FDICopy failed\n"); FDIDestroy(hfdi); msi_free(cabinet); msi_free(cab_path); return ret; }
static BOOL msidbExportStorage(LPCWSTR dbfile, LPCWSTR wdir, LPWSTR storageName) { UINT r, len; MSIHANDLE dbhandle, view, rec; char queryBuffer[100]; char *storageNameA = strdupWtoA(CP_ACP, storageName); char *wdirA = strdupWtoA(CP_ACP, wdir); char *storagePath = NULL; char *dataBuffer; DWORD dataLen = 0; FILE *fp = NULL; sprintf(queryBuffer, "SELECT * FROM _Storages WHERE Name = '%s'", storageNameA); r = MsiOpenDatabaseW(dbfile, (LPWSTR) MSIDBOPEN_READONLY, &dbhandle); if (r != ERROR_SUCCESS) return FALSE; MsiDatabaseOpenView(dbhandle, queryBuffer, &view); MsiViewExecute(view, 0); r = MsiViewFetch(view, &rec); if (r != ERROR_SUCCESS) return FALSE; if ((r = MsiRecordReadStream(rec, 2, 0, &dataLen)) != ERROR_SUCCESS) { return FALSE; } if ((dataBuffer = malloc(dataLen)) == NULL) return FALSE; if (MsiRecordReadStream(rec, 2, dataBuffer, &dataLen) != ERROR_SUCCESS) return FALSE; len = strlen(wdirA) + strlen(storageNameA) + 2; storagePath = malloc(len * sizeof(WCHAR)); if (storagePath == NULL) return FALSE; strcpy(storagePath, wdirA); strcat(storagePath, "/"); strcat(storagePath, storageNameA); fp = fopen(storagePath , "wb"); if (fp != NULL) { fwrite(dataBuffer, 1, dataLen, fp); fclose(fp); } free(storagePath); MsiCloseHandle(rec); MsiViewClose(view); MsiCloseHandle(view); MsiCloseHandle(dbhandle); free(storageNameA); free(wdirA); return TRUE; }
static INT_PTR CDECL list_notify( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin ) { WCHAR *nameW; switch (fdint) { case fdintCABINET_INFO: return 0; case fdintCOPY_FILE: nameW = strdupAtoW( (pfdin->attribs & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP, pfdin->psz1 ); if (match_files( nameW )) { char *nameU = strdupWtoA( CP_UNIXCP, nameW ); if (opt_verbose) { char attrs[] = "rxash"; if (!(pfdin->attribs & _A_RDONLY)) attrs[0] = '-'; if (!(pfdin->attribs & _A_EXEC)) attrs[1] = '-'; if (!(pfdin->attribs & _A_ARCH)) attrs[2] = '-'; if (!(pfdin->attribs & _A_SYSTEM)) attrs[3] = '-'; if (!(pfdin->attribs & _A_HIDDEN)) attrs[4] = '-'; printf( " %s %9u %04u/%02u/%02u %02u:%02u:%02u ", attrs, pfdin->cb, (pfdin->date >> 9) + 1980, (pfdin->date >> 5) & 0x0f, pfdin->date & 0x1f, pfdin->time >> 11, (pfdin->time >> 5) & 0x3f, (pfdin->time & 0x1f) * 2 ); } printf( "%s\n", nameU ); cab_free( nameU ); } cab_free( nameW ); return 0; default: WINE_FIXME( "Unexpected notification type %d.\n", fdint ); return 0; } }
/*********************************************************************** * extract_cabinet_file * * Extract files from a cab file. */ static BOOL extract_cabinet_file(MSIPACKAGE* package, struct media_info *mi) { LPSTR cabinet, cab_path = NULL; LPWSTR ptr; HFDI hfdi; ERF erf; BOOL ret = FALSE; CabData data; TRACE("Extracting %s\n", debugstr_w(mi->source)); hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read, cabinet_write, cabinet_close, cabinet_seek, 0, &erf); if (!hfdi) { ERR("FDICreate failed\n"); return FALSE; } ptr = strrchrW(mi->source, '\\') + 1; cabinet = strdupWtoA(ptr); if (!cabinet) goto done; cab_path = strdupWtoA(mi->source); if (!cab_path) goto done; cab_path[ptr - mi->source] = '\0'; data.package = package; data.mi = mi; ret = FDICopy(hfdi, cabinet, cab_path, 0, cabinet_notify, NULL, &data); if (!ret) ERR("FDICopy failed\n"); done: FDIDestroy(hfdi); msi_free(cabinet); msi_free(cab_path); if (ret) mi->is_extracted = TRUE; return ret; }
/* downloads a remote cabinet and extracts it if it exists */ static UINT msi_extract_remote_cabinet( MSIPACKAGE *package, struct media_info *mi ) { FDICABINETINFO cabinfo; WCHAR temppath[MAX_PATH]; WCHAR src[MAX_PATH]; LPSTR cabpath; LPCWSTR file; LPWSTR ptr; HFDI hfdi; ERF erf; int hf; /* the URL is the path prefix of the package URL and the filename * of the file to download */ ptr = strrchrW(package->PackagePath, '/'); lstrcpynW(src, package->PackagePath, ptr - package->PackagePath + 2); ptr = strrchrW(mi->source, '\\'); lstrcatW(src, ptr + 1); file = msi_download_file( src, temppath ); lstrcpyW(mi->source, file); /* check if the remote cabinet still exists, ignore if it doesn't */ hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read, cabinet_write, cabinet_close, cabinet_seek, 0, &erf); if (!hfdi) { ERR("FDICreate failed\n"); return ERROR_FUNCTION_FAILED; } cabpath = strdupWtoA(mi->source); hf = cabinet_open(cabpath, _O_RDONLY, 0); if (!FDIIsCabinet(hfdi, hf, &cabinfo)) { WARN("Remote cabinet %s does not exist.\n", debugstr_w(mi->source)); msi_free(cabpath); return ERROR_SUCCESS; } msi_free(cabpath); return !extract_cabinet_file(package, mi->source, mi->last_path); }
static BOOL add_file( HFCI fci, WCHAR *name ) { BOOL ret; char *filename, *path = strdupWtoA( CP_UTF8, name ); if (!opt_preserve_paths) { if ((filename = strrchr( path, '\\' ))) filename++; else filename = path; } else { filename = path; while (*filename == '\\') filename++; /* remove leading backslashes */ } ret = FCIAddFile( fci, path, filename, FALSE, fci_get_next_cab, fci_status, fci_get_open_info, opt_compression ); cab_free( path ); return ret; }
static UINT msi_change_media( MSIPACKAGE *package, struct media_info *mi ) { LPSTR msg; LPWSTR error, error_dialog; LPWSTR source_dir; UINT r = ERROR_SUCCESS; static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0}; if ( (msi_get_property_int(package, szUILevel, 0) & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE && !gUIHandlerA ) return ERROR_SUCCESS; error = generate_error_string( package, 1302, 1, mi->disk_prompt ); error_dialog = msi_dup_property( package, error_prop ); source_dir = msi_dup_property( package, cszSourceDir ); PathStripToRootW(source_dir); while ( r == ERROR_SUCCESS && !source_matches_volume(mi, source_dir) ) { r = msi_spawn_error_dialog( package, error_dialog, error ); if (gUIHandlerA) { msg = strdupWtoA( error ); gUIHandlerA( gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, msg ); msi_free(msg); } } msi_free( error ); msi_free( error_dialog ); msi_free( source_dir ); return r; }
/*********************************************************************** * msidbImportTables * * Takes a list of tables or '*' (for all) to import from text archive * files in specified folder * * For each table, a file called <tablename>.idt is imported containing * tab separated ASCII. * * Examples (note wildcard escape for *nix/bash): * msidb -d <pathtomsi>.msi -f <workdir> -i \* * msidb -d <pathtomsi>.msi -f <workdir> -i File Directory Binary **********************************************************************/ static BOOL msidbImportTables(LPCWSTR dbfile, LPCWSTR wdir, LPWSTR tables[], BOOL create) { static const WCHAR ext[] = {'.', 'i', 'd', 't', 0}; static const WCHAR all[] = {'*', 0}; UINT r, len; char *dirNameA; char *fileName; DIR *dir; struct dirent *ent; int i = 0; MSIHANDLE dbhandle; LPWSTR tableFile = 0; LPCWSTR oFlag = (LPCWSTR) MSIDBOPEN_TRANSACT; if (create == TRUE) oFlag = (LPCWSTR) MSIDBOPEN_CREATE; r = MsiOpenDatabaseW(dbfile, oFlag, &dbhandle); if (r != ERROR_SUCCESS) { return FALSE; } if (strcmpW(tables[0], all) == 0) { dirNameA = strdupWtoA(CP_ACP, wdir); dir = opendir(dirNameA); if (dir) { while ((ent = readdir(dir)) != NULL) { if (ent->d_type != DT_REG) continue; fileName = ent->d_name; if (strcmp(fileName+strlen(fileName)-4*sizeof(fileName[0]), ".idt") != 0) continue; if (strcmp(fileName, ".") == 0 || strcmp(fileName, "..") == 0) continue; tableFile = strdupAtoW(CP_ACP, fileName); r = MsiDatabaseImportW(dbhandle, wdir, tableFile); free(tableFile); } } else return FALSE; closedir(dir); free(dirNameA); } else { for (i = 0; i < MAX_TABLES && tables[i] != 0; ++i) { len = lstrlenW(tables[i]) + 5; tableFile = malloc(len * sizeof (WCHAR)); if (tableFile == NULL) return FALSE; lstrcpyW(tableFile, tables[i]); lstrcatW(tableFile, ext); r = MsiDatabaseImportW(dbhandle, wdir, tableFile); free(tableFile); if (r != ERROR_SUCCESS) { return FALSE; } } } MsiDatabaseCommit(dbhandle); MsiCloseHandle(dbhandle); return TRUE; }
int wmain( int argc, WCHAR *argv[] ) { static const WCHAR noneW[] = {'n','o','n','e',0}; static const WCHAR mszipW[] = {'m','s','z','i','p',0}; WCHAR *p, *command; char buffer[MAX_PATH]; char filename[MAX_PATH]; char *cab_file, *file_part; int i; while (argv[1] && argv[1][0] == '-') { switch (argv[1][1]) { case 'd': argv++; argc--; opt_cabinet_size = atoiW( argv[1] ); if (opt_cabinet_size < 50000) { WINE_MESSAGE( "cabarc: Cabinet size must be at least 50000\n" ); return 1; } break; case 'h': usage(); return 0; case 'i': argv++; argc--; opt_cabinet_id = atoiW( argv[1] ); break; case 'm': argv++; argc--; if (!strcmpiW( argv[1], noneW )) opt_compression = tcompTYPE_NONE; else if (!strcmpiW( argv[1], mszipW )) opt_compression = tcompTYPE_MSZIP; else { WINE_MESSAGE( "cabarc: Unknown compression type '%s'\n", optarg ); return 1; } break; case 'p': opt_preserve_paths = 1; break; case 'r': opt_recurse = 1; break; case 's': argv++; argc--; opt_reserve_space = atoiW( argv[1] ); break; case 'v': opt_verbose++; break; default: usage(); return 1; } argv++; argc--; } command = argv[1]; if (argc < 3 || !command[0] || command[1]) { usage(); return 1; } cab_file = strdupWtoA( CP_ACP, argv[2] ); argv += 2; argc -= 2; if (!GetFullPathNameA( cab_file, MAX_PATH, buffer, &file_part ) || !file_part) { WINE_ERR( "cannot get full name for %s\n", wine_dbgstr_a( cab_file )); return 1; } strcpy(filename, file_part); file_part[0] = 0; /* map slash to backslash in all file arguments */ for (i = 1; i < argc; i++) for (p = argv[i]; *p; p++) if (*p == '/') *p = '\\'; opt_files = argv + 1; opt_cab_file = filename; switch (*command) { case 'l': case 'L': return list_cabinet( buffer ); case 'n': case 'N': return new_cabinet( buffer ); case 'x': case 'X': if (argc > 1) /* check for destination dir as last argument */ { WCHAR *last = argv[argc - 1]; if (last[0] && last[strlenW(last) - 1] == '\\') { opt_dest_dir = last; argv[--argc] = NULL; } } WINE_TRACE("Extracting file(s) from cabinet %s\n", wine_dbgstr_a(cab_file)); return extract_cabinet( buffer ); default: usage(); return 1; } }
static INT_PTR CDECL extract_notify( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin ) { WCHAR *file, *nameW, *path = NULL; INT_PTR ret; switch (fdint) { case fdintCABINET_INFO: return 0; case fdintCOPY_FILE: nameW = strdupAtoW( (pfdin->attribs & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP, pfdin->psz1 ); if (opt_preserve_paths) { file = nameW; while (*file == '\\') file++; /* remove leading backslashes */ } else { if ((file = strrchrW( nameW, '\\' ))) file++; else file = nameW; } if (opt_dest_dir) { path = cab_alloc( (strlenW(opt_dest_dir) + strlenW(file) + 1) * sizeof(WCHAR) ); strcpyW( path, opt_dest_dir ); strcatW( path, file ); } else path = file; if (match_files( file )) { if (opt_verbose) { char *nameU = strdupWtoA( CP_UNIXCP, path ); printf( "extracting %s\n", nameU ); cab_free( nameU ); } create_directories( path ); /* FIXME: check for existing file and overwrite mode */ ret = (INT_PTR)CreateFileW( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } else ret = 0; cab_free( nameW ); if (path != file) cab_free( path ); return ret; case fdintCLOSE_FILE_INFO: CloseHandle( (HANDLE)pfdin->hf ); return 0; case fdintNEXT_CABINET: WINE_TRACE("Next cab: status %u, path '%s', file '%s'\n", pfdin->fdie, pfdin->psz3, pfdin->psz1); return pfdin->fdie == FDIERROR_NONE ? 0 : -1; case fdintENUMERATE: return 0; default: WINE_FIXME( "Unexpected notification type %d.\n", fdint ); return 0; } }