files.c

来自「一个类似windows」· C语言 代码 · 共 888 行 · 第 1/2 页

C
888
字号

static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
                                  MSIFILE *file )
{
    UINT rc = ERROR_SUCCESS;
    MSIRECORD * row = 0;
    static const WCHAR ExecSeqQuery[] =
        {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
         '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
         ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
         '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
    LPCWSTR cab, volume;
    DWORD sz;
    INT seq;
    UINT type;
    LPCWSTR prompt;
    MSICOMPONENT *comp = file->Component;

    if (file->Sequence <= mi->last_sequence)
    {
        set_file_source(package,file,comp,mi->last_path);
        TRACE("Media already ready (%u, %u)\n",file->Sequence,mi->last_sequence);
        return ERROR_SUCCESS;
    }

    mi->count ++;
    row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
    if (!row)
    {
        TRACE("Unable to query row\n");
        return ERROR_FUNCTION_FAILED;
    }

    seq = MSI_RecordGetInteger(row,2);
    mi->last_sequence = seq;

    volume = MSI_RecordGetString(row, 5);
    prompt = MSI_RecordGetString(row, 3);

    msi_free(mi->last_path);
    mi->last_path = NULL;

    if (file->Attributes & msidbFileAttributesNoncompressed)
    {
        mi->last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
        set_file_source(package,file,comp,mi->last_path);
        rc = ready_volume(package, file->SourcePath, mi->last_volume, row,&type);

        MsiSourceListAddMediaDiskW(package->ProductCode, NULL, 
            MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume,
            prompt);

        if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || 
                type == DRIVE_RAMDISK)
            MsiSourceListSetInfoW(package->ProductCode, NULL, 
                MSIINSTALLCONTEXT_USERMANAGED, 
                MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
                INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
        else
            MsiSourceListSetInfoW(package->ProductCode, NULL, 
                MSIINSTALLCONTEXT_USERMANAGED, 
                MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
                INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
        msiobj_release(&row->hdr);
        return rc;
    }

    cab = MSI_RecordGetString(row,4);
    if (cab)
    {
        TRACE("Source is CAB %s\n",debugstr_w(cab));
        /* the stream does not contain the # character */
        if (cab[0]=='#')
        {
            LPWSTR path;

            writeout_cabinet_stream(package,&cab[1],mi->source);
            mi->last_path = strdupW(mi->source);
            *(strrchrW(mi->last_path,'\\')+1)=0;

            path = msi_dup_property( package, cszSourceDir );

            MsiSourceListAddMediaDiskW(package->ProductCode, NULL, 
                MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count,
                volume, prompt);

            MsiSourceListSetInfoW(package->ProductCode, NULL,
                MSIINSTALLCONTEXT_USERMANAGED,
                MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
                INSTALLPROPERTY_LASTUSEDSOURCEW, path);

            msi_free(path);
        }
        else
        {
            sz = MAX_PATH;
            mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
            if (MSI_GetPropertyW(package, cszSourceDir, mi->source, &sz))
            {
                ERR("No Source dir defined\n");
                rc = ERROR_FUNCTION_FAILED;
            }
            else
            {
                strcpyW(mi->last_path,mi->source);
                strcatW(mi->source,cab);

                rc = ready_volume(package, mi->source, mi->last_volume, row, &type);
                if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || 
                        type == DRIVE_RAMDISK)
                    MsiSourceListSetInfoW(package->ProductCode, NULL,
                            MSIINSTALLCONTEXT_USERMANAGED,
                            MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
                            INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
                else
                    MsiSourceListSetInfoW(package->ProductCode, NULL,
                            MSIINSTALLCONTEXT_USERMANAGED,
                            MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
                            INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);

                /* extract the cab file into a folder in the temp folder */
                sz = MAX_PATH;
                if (MSI_GetPropertyW(package, cszTempFolder,mi->last_path, &sz) 
                                    != ERROR_SUCCESS)
                    GetTempPathW(MAX_PATH,mi->last_path);
            }
        }
        rc = !extract_cabinet_file(package, mi->source, mi->last_path);
    }
    else
    {
        sz = MAX_PATH;
        mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
        MSI_GetPropertyW(package,cszSourceDir,mi->source,&sz);
        strcpyW(mi->last_path,mi->source);
        rc = ready_volume(package, mi->last_path, mi->last_volume, row, &type);

        if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || 
                type == DRIVE_RAMDISK)
            MsiSourceListSetInfoW(package->ProductCode, NULL,
                    MSIINSTALLCONTEXT_USERMANAGED,
                    MSICODE_PRODUCT|MSISOURCETYPE_MEDIA,
                    INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
        else
            MsiSourceListSetInfoW(package->ProductCode, NULL,
                    MSIINSTALLCONTEXT_USERMANAGED,
                    MSICODE_PRODUCT|MSISOURCETYPE_NETWORK,
                    INSTALLPROPERTY_LASTUSEDSOURCEW, mi->last_path);
    }
    set_file_source(package, file, comp, mi->last_path);

    MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
            MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, mi->count, volume,
            prompt);

    msiobj_release(&row->hdr);

    return rc;
}

static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, 
                                   LPWSTR* file_source)
{
    MSIFILE *file;

    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
    {
        if (lstrcmpW( file_key, file->File )==0)
        {
            if (file->state >= msifs_overwrite)
            {
                *file_source = strdupW( file->TargetPath );
                return ERROR_SUCCESS;
            }
            else
                return ERROR_FILE_NOT_FOUND;
        }
    }

    return ERROR_FUNCTION_FAILED;
}

/*
 * ACTION_InstallFiles()
 * 
 * For efficiency, this is done in two passes:
 * 1) Correct all the TargetPaths and determine what files are to be installed.
 * 2) Extract Cabinets and copy files.
 */
UINT ACTION_InstallFiles(MSIPACKAGE *package)
{
    struct media_info *mi;
    UINT rc = ERROR_SUCCESS;
    LPWSTR ptr;
    MSIFILE *file;

    /* increment progress bar each time action data is sent */
    ui_progress(package,1,1,0,0);

    /* handle the keys for the SourceList */
    ptr = strrchrW(package->PackagePath,'\\');
    if (ptr)
    {
        ptr ++;
        MsiSourceListSetInfoW(package->ProductCode, NULL,
                MSIINSTALLCONTEXT_USERMANAGED,
                MSICODE_PRODUCT,
                INSTALLPROPERTY_PACKAGENAMEW, ptr);
    }
    /* FIXME("Write DiskPrompt\n"); */
    
    /* Pass 1 */
    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
    {
        if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL ))
        {
            ui_progress(package,2,file->FileSize,0,0);
            TRACE("File %s is not scheduled for install\n",
                   debugstr_w(file->File));

            file->state = msifs_skipped;
        }
    }

    /*
     * Despite MSDN specifying that the CreateFolders action
     * should be called before InstallFiles, some installers don't
     * do that, and they seem to work correctly.  We need to create
     * directories here to make sure that the files can be copied.
     */
    msi_create_component_directories( package );

    mi = create_media_info();

    /* Pass 2 */
    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
    {
        if (file->state != msifs_missing && file->state != msifs_overwrite)
            continue;

        TRACE("Pass 2: %s\n",debugstr_w(file->File));

        rc = ready_media_for_file( package, mi, file );
        if (rc != ERROR_SUCCESS)
        {
            ERR("Unable to ready media\n");
            rc = ERROR_FUNCTION_FAILED;
            break;
        }

        TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
              debugstr_w(file->TargetPath));

        if (file->state != msifs_missing && file->state != msifs_overwrite)
            continue;

        /* compressed files are extracted in ready_media_for_file */
        if (~file->Attributes & msidbFileAttributesNoncompressed)
        {
            if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(file->TargetPath))
                ERR("compressed file wasn't extracted (%s)\n",
                    debugstr_w(file->TargetPath));
            continue;
        }

        rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
        if (!rc)
        {
            rc = GetLastError();
            ERR("Unable to copy file (%s -> %s) (error %d)\n",
                debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), rc);
            if (rc == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite)
            {
                rc = 0;
            }
            else if (rc == ERROR_FILE_NOT_FOUND)
            {
                ERR("Source File Not Found!  Continuing\n");
                rc = 0;
            }
            else if (file->Attributes & msidbFileAttributesVital)
            {
                ERR("Ignoring Error and continuing (nonvital file)...\n");
                rc = 0;
            }
        }
        else
        {
            file->state = msifs_installed;
            rc = ERROR_SUCCESS;
        }
    }

    /* cleanup */
    free_media_info( mi );
    return rc;
}

static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
{
    MSIPACKAGE *package = (MSIPACKAGE*)param;
    WCHAR *file_source = NULL;
    WCHAR dest_name[0x100];
    LPWSTR dest_path, dest;
    LPCWSTR file_key, component;
    DWORD sz;
    DWORD rc;
    MSICOMPONENT *comp;

    component = MSI_RecordGetString(row,2);
    comp = get_loaded_component(package,component);

    if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
    {
        TRACE("Skipping copy due to disabled component %s\n",
                        debugstr_w(component));

        /* the action taken was the same as the current install state */        
        comp->Action = comp->Installed;

        return ERROR_SUCCESS;
    }

    comp->Action = INSTALLSTATE_LOCAL;

    file_key = MSI_RecordGetString(row,3);
    if (!file_key)
    {
        ERR("Unable to get file key\n");
        return ERROR_FUNCTION_FAILED;
    }

    rc = get_file_target(package,file_key,&file_source);

    if (rc != ERROR_SUCCESS)
    {
        ERR("Original file unknown %s\n",debugstr_w(file_key));
        msi_free(file_source);
        return ERROR_SUCCESS;
    }

    if (MSI_RecordIsNull(row,4))
        strcpyW(dest_name,strrchrW(file_source,'\\')+1);
    else
    {
        sz=0x100;
        MSI_RecordGetStringW(row,4,dest_name,&sz);
        reduce_to_longfilename(dest_name);
    }

    if (MSI_RecordIsNull(row,5))
    {
        LPWSTR p;
        dest_path = strdupW(file_source);
        p = strrchrW(dest_path,'\\');
        if (p)
            *p=0;
    }
    else
    {
        LPCWSTR destkey;
        destkey = MSI_RecordGetString(row,5);
        dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
        if (!dest_path)
        {
            /* try a Property */
            dest_path = msi_dup_property( package, destkey );
            if (!dest_path)
            {
                FIXME("Unable to get destination folder, try AppSearch properties\n");
                msi_free(file_source);
                return ERROR_SUCCESS;
            }
        }
    }

    dest = build_directory_name(2, dest_path, dest_name);

    TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
                    debugstr_w(dest)); 

    if (strcmpW(file_source,dest))
        rc = !CopyFileW(file_source,dest,TRUE);
    else
        rc = ERROR_SUCCESS;

    if (rc != ERROR_SUCCESS)
        ERR("Failed to copy file %s -> %s, last error %ld\n",
            debugstr_w(file_source), debugstr_w(dest_path), GetLastError());

    FIXME("We should track these duplicate files as well\n");   

    msi_free(dest_path);
    msi_free(dest);
    msi_free(file_source);

    return ERROR_SUCCESS;
}

UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
{
    UINT rc;
    MSIQUERY * view;
    static const WCHAR ExecSeqQuery[] =
        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
         '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};

    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
    if (rc != ERROR_SUCCESS)
        return ERROR_SUCCESS;

    rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package);
    msiobj_release(&view->hdr);

    return rc;
}

UINT ACTION_RemoveFiles( MSIPACKAGE *package )
{
    MSIFILE *file;

    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
    {
        if ( !file->Component )
            continue;
        if ( file->Component->Installed == INSTALLSTATE_LOCAL )
            continue;

        if ( file->state == msifs_installed )
            ERR("removing installed file %s\n", debugstr_w(file->TargetPath));

        if ( file->state != msifs_present )
            continue;

        TRACE("removing %s\n", debugstr_w(file->File) );
        if ( !DeleteFileW( file->TargetPath ) )
            ERR("failed to delete %s\n",  debugstr_w(file->TargetPath) );
        file->state = msifs_missing;
    }

    return ERROR_SUCCESS;
}

⌨️ 快捷键说明

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