Module: wine Branch: master Commit: 8ebff12b0513efd541b459ed3858452a0f5c9fdd URL: http://source.winehq.org/git/wine.git/?a=commit;h=8ebff12b0513efd541b459ed38...
Author: Alexandre Julliard julliard@winehq.org Date: Wed Feb 2 22:48:40 2011 +0100
cabarc: Add support for listing and extracting cabinets.
---
programs/cabarc/cabarc.c | 204 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 200 insertions(+), 4 deletions(-)
diff --git a/programs/cabarc/cabarc.c b/programs/cabarc/cabarc.c index 5a10d21..2aeb88e 100644 --- a/programs/cabarc/cabarc.c +++ b/programs/cabarc/cabarc.c @@ -69,6 +69,7 @@ static int opt_recurse; static int opt_preserve_paths; static int opt_reserve_space; static int opt_verbose; +static WCHAR *opt_dest_dir; static WCHAR **opt_files;
static void * CDECL cab_alloc( ULONG size ) @@ -258,6 +259,194 @@ static INT_PTR CDECL fci_get_open_info( char *name, USHORT *date, USHORT *time, return (INT_PTR)handle; }
+static INT_PTR CDECL fdi_open( char *file, int oflag, int pmode ) +{ + int err; + return fci_open( file, oflag, pmode, &err, NULL ); +} + +static UINT CDECL fdi_read( INT_PTR hf, void *pv, UINT cb ) +{ + int err; + return fci_read( hf, pv, cb, &err, NULL ); +} + +static UINT CDECL fdi_write( INT_PTR hf, void *pv, UINT cb ) +{ + int err; + return fci_write( hf, pv, cb, &err, NULL ); +} + +static int CDECL fdi_close( INT_PTR hf ) +{ + int err; + return fci_close( hf, &err, NULL ); +} + +static LONG CDECL fdi_lseek( INT_PTR hf, LONG dist, int whence ) +{ + int err; + return fci_lseek( hf, dist, whence, &err, NULL ); +} + + +/* create directories leading to a given file */ +static void create_directories( const WCHAR *name ) +{ + WCHAR *path, *p; + + /* create the directory/directories */ + path = cab_alloc( (strlenW(name) + 1) * sizeof(WCHAR) ); + strcpyW(path, name); + + p = strchrW(path, '\'); + while (p != NULL) + { + *p = 0; + if (!CreateDirectoryW( path, NULL )) + WINE_TRACE("Couldn't create directory %s - error: %d\n", wine_dbgstr_w(path), GetLastError()); + *p = '\'; + p = strchrW(p+1, '\'); + } + cab_free( path ); +} + +/* check if file name matches against one of the files specification */ +static BOOL match_files( const WCHAR *name ) +{ + int i; + + if (!*opt_files) return TRUE; + for (i = 0; opt_files[i]; i++) + { + unsigned int len = strlenW( opt_files[i] ); + /* FIXME: do smarter matching, and wildcards */ + if (!len) continue; + if (strncmpiW( name, opt_files[i], len )) continue; + if (opt_files[i][len - 1] == '\' || !name[len] || name[len] == '\') return TRUE; + } + return FALSE; +} + +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; + } +} + +static int list_cabinet( char *cab_dir, char *cab_file ) +{ + ERF erf; + int ret = 0; + HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read, + fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf ); + + if (!FDICopy( fdi, cab_file, cab_dir, 0, list_notify, NULL, NULL )) ret = GetLastError(); + FDIDestroy( fdi ); + return ret; +} + +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; + + default: + WINE_FIXME( "Unexpected notification type %d.\n", fdint ); + return 0; + } +} + +static int extract_cabinet( char *cab_dir, char *cab_file ) +{ + ERF erf; + int ret = 0; + HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read, + fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf ); + + if (!FDICopy( fdi, cab_file, cab_dir, 0, extract_notify, NULL, NULL )) ret = GetLastError(); + FDIDestroy( fdi ); + return ret; +}
static BOOL add_file( HFCI fci, WCHAR *name ) { @@ -468,15 +657,22 @@ int wmain( int argc, WCHAR *argv[] ) { case 'l': case 'L': - WINE_FIXME( "list not implemented\n" ); - return 1; + return list_cabinet( buffer, file_part ); case 'n': case 'N': return new_cabinet( buffer, file_part ); case 'x': case 'X': - WINE_FIXME( "extraction not implemented\n" ); - return 1; + 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; + } + } + return extract_cabinet( buffer, file_part ); default: usage(); return 1;