Alexandre Julliard : cabarc: Add support for listing and extracting cabinets.
Alexandre Julliard
julliard at winehq.org
Thu Feb 3 12:00:21 CST 2011
Module: wine
Branch: master
Commit: 8ebff12b0513efd541b459ed3858452a0f5c9fdd
URL: http://source.winehq.org/git/wine.git/?a=commit;h=8ebff12b0513efd541b459ed3858452a0f5c9fdd
Author: Alexandre Julliard <julliard at 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;
More information about the wine-cvs
mailing list