⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 queue.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * Setupapi file queue routines
 *
 * Copyright 2002 Alexandre Julliard for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "setupapi_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(setupapi);

/* Unicode constants */
static const WCHAR DotSecurity[]     = {'.','S','e','c','u','r','i','t','y',0};

/* context structure for the default queue callback */
struct default_callback_context
{
    HWND owner;
    HWND progress;
    UINT message;
};

struct file_op
{
    struct file_op       *next;
    UINT                  style;
    WCHAR                *src_root;
    WCHAR                *src_path;
    WCHAR                *src_file;
    WCHAR                *src_descr;
    WCHAR                *src_tag;
    WCHAR                *dst_path;
    WCHAR                *dst_file;
    PSECURITY_DESCRIPTOR  dst_sd;
};

struct file_op_queue
{
    struct file_op *head;
    struct file_op *tail;
    unsigned int count;
};

struct file_queue
{
    struct file_op_queue copy_queue;
    struct file_op_queue delete_queue;
    struct file_op_queue rename_queue;
    DWORD                flags;
};


inline static WCHAR *strdupW( const WCHAR *str )
{
    WCHAR *ret = NULL;
    if (str)
    {
        int len = (strlenW(str) + 1) * sizeof(WCHAR);
        if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
    }
    return ret;
}


inline static WCHAR *strdupAtoW( const char *str )
{
    WCHAR *ret = NULL;
    if (str)
    {
        DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
        if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
            MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
    }
    return ret;
}

inline static char *strdupWtoA( const WCHAR *str )
{
    char *ret = NULL;
    if (str)
    {
        DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
        if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
            WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
    }
    return ret;
}

/* append a file operation to a queue */
inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
{
    op->next = NULL;
    if (queue->tail) queue->tail->next = op;
    else queue->head = op;
    queue->tail = op;
    queue->count++;
}

/* free all the file operations on a given queue */
static void free_file_op_queue( struct file_op_queue *queue )
{
    struct file_op *t, *op = queue->head;

    while( op )
    {
        HeapFree( GetProcessHeap(), 0, op->src_root );
        HeapFree( GetProcessHeap(), 0, op->src_path );
        HeapFree( GetProcessHeap(), 0, op->src_file );
        HeapFree( GetProcessHeap(), 0, op->src_descr );
        HeapFree( GetProcessHeap(), 0, op->src_tag );
        HeapFree( GetProcessHeap(), 0, op->dst_path );
        if (op->dst_sd) LocalFree( op->dst_sd);
        if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
        t = op;
        op = op->next;
        HeapFree( GetProcessHeap(), 0, t );
    }
}

/* concat 3 strings to make a path, handling separators correctly */
static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
{
    *buffer = 0;
    if (src1 && *src1)
    {
        strcpyW( buffer, src1 );
        buffer += strlenW(buffer );
        if (buffer[-1] != '\\') *buffer++ = '\\';
        if (src2) while (*src2 == '\\') src2++;
    }

    if (src2)
    {
        strcpyW( buffer, src2 );
        buffer += strlenW(buffer );
        if (buffer[-1] != '\\') *buffer++ = '\\';
        if (src3) while (*src3 == '\\') src3++;
    }
    if (src3)
    {
        strcpyW( buffer, src3 );
        buffer += strlenW(buffer );
    }
}


/***********************************************************************
 *            build_filepathsW
 *
 * Build a FILEPATHS_W structure for a given file operation.
 */
static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
{
    unsigned int src_len = 1, dst_len = 1;
    WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;

    if (op->src_root) src_len += strlenW(op->src_root) + 1;
    if (op->src_path) src_len += strlenW(op->src_path) + 1;
    if (op->src_file) src_len += strlenW(op->src_file) + 1;
    if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
    if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
    src_len *= sizeof(WCHAR);
    dst_len *= sizeof(WCHAR);

    if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
    {
        HeapFree( GetProcessHeap(), 0, source );
        paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
    }
    if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
    {
        HeapFree( GetProcessHeap(), 0, target );
        paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
    }
    if (!source || !target) return FALSE;
    concat_W( source, op->src_root, op->src_path, op->src_file );
    concat_W( target, NULL, op->dst_path, op->dst_file );
    paths->Win32Error = 0;
    paths->Flags      = 0;
    return TRUE;
}


/***********************************************************************
 *            QUEUE_callback_WtoA
 *
 * Map a file callback parameters from W to A and call the A callback.
 */
UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
                                   UINT_PTR param1, UINT_PTR param2 )
{
    struct callback_WtoA_context *callback_ctx = context;
    char buffer[MAX_PATH];
    UINT ret;
    UINT_PTR old_param2 = param2;

    switch(notification)
    {
    case SPFILENOTIFY_COPYERROR:
        param2 = (UINT_PTR)&buffer;
        /* fall through */
    case SPFILENOTIFY_STARTDELETE:
    case SPFILENOTIFY_ENDDELETE:
    case SPFILENOTIFY_DELETEERROR:
    case SPFILENOTIFY_STARTRENAME:
    case SPFILENOTIFY_ENDRENAME:
    case SPFILENOTIFY_RENAMEERROR:
    case SPFILENOTIFY_STARTCOPY:
    case SPFILENOTIFY_ENDCOPY:
        {
            FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
            FILEPATHS_A pathsA;

            pathsA.Source     = strdupWtoA( pathsW->Source );
            pathsA.Target     = strdupWtoA( pathsW->Target );
            pathsA.Win32Error = pathsW->Win32Error;
            pathsA.Flags      = pathsW->Flags;
            ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
                                              (UINT_PTR)&pathsA, param2 );
            HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
            HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
        }
        if (notification == SPFILENOTIFY_COPYERROR)
            MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
        break;

    case SPFILENOTIFY_STARTREGISTRATION:
    case SPFILENOTIFY_ENDREGISTRATION:
        {
            SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
            SP_REGISTER_CONTROL_STATUSA statusA;

            statusA.cbSize = sizeof(statusA);
            statusA.FileName = strdupWtoA( statusW->FileName );
            statusA.Win32Error  = statusW->Win32Error;
            statusA.FailureCode = statusW->FailureCode;
            ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
                                              (UINT_PTR)&statusA, param2 );
            HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
        }
        break;

    case SPFILENOTIFY_NEEDMEDIA:
    case SPFILENOTIFY_QUEUESCAN:
        FIXME("mapping for %d not implemented\n",notification);
    case SPFILENOTIFY_STARTQUEUE:
    case SPFILENOTIFY_ENDQUEUE:
    case SPFILENOTIFY_STARTSUBQUEUE:
    case SPFILENOTIFY_ENDSUBQUEUE:
    default:
        ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
        break;
    }
    return ret;
}


/***********************************************************************
 *            get_src_file_info
 *
 * Retrieve the source file information for a given file.
 */
static void get_src_file_info( HINF hinf, struct file_op *op )
{
    static const WCHAR SourceDisksNames[] =
        {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
    static const WCHAR SourceDisksFiles[] =
        {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};

    INFCONTEXT file_ctx, disk_ctx;
    INT id, diskid;
    DWORD len, len2;

    /* find the SourceDisksFiles entry */
    if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
    {
        if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
        /* no specific info, use .inf file source directory */
        if (!op->src_root) op->src_root = PARSER_get_src_root( hinf );
        return;
    }
    if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;

    /* now find the diskid in the SourceDisksNames section */
    if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
    for (;;)
    {
        if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
        if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
    }

    /* and fill in the missing info */

    if (!op->src_descr)
    {
        if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
            (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
            SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
    }
    if (!op->src_tag)
    {
        if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
            (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
            SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
    }
    if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
    {
        len = len2 = 0;
        if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
        {
            /* retrieve relative path for this disk */
            if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
        }
        /* retrieve relative path for this file */
        if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;

        if ((len || len2) &&
            (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
        {
            WCHAR *ptr = op->src_path;
            if (len)
            {
                SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
                ptr = op->src_path + strlenW(op->src_path);
                if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
            }
            if (!SetupGetStringFieldW( &file_ctx, 2, ptr, len2, NULL )) *ptr = 0;
        }
    }
    if (!op->src_root) op->src_root = PARSER_get_src_root(hinf);
}


/***********************************************************************
 *            get_destination_dir
 *
 * Retrieve the destination dir for a given section.
 */
static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
{
    static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
    static const WCHAR Def[]  = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
    INFCONTEXT context;

    if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
        !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
    return PARSER_get_dest_dir( &context );
}


static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );

/***********************************************************************
 *            extract_cabinet_file
 *
 * Extract a file from a .cab file.
 */
static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
                                  const WCHAR *src, const WCHAR *dst )
{
    static const WCHAR extW[] = {'.','c','a','b',0};
    static HMODULE advpack;

    char *cab_path, *cab_file;
    int len = strlenW( cabinet );

    /* make sure the cabinet file has a .cab extension */
    if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
    if (!pExtractFiles)
    {
        if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
        {
            ERR( "could not load advpack.dll\n" );
            return FALSE;
        }
        if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
        {
            ERR( "could not find ExtractFiles in advpack.dll\n" );
            return FALSE;
        }
    }

    if (!(cab_path = strdupWtoA( root ))) return FALSE;
    len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
    if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
    {
        HeapFree( GetProcessHeap(), 0, cab_path );
        return FALSE;
    }
    strcpy( cab_file, cab_path );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -