Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

beebox / crossover   deb

Repository URL to install this package:

/ opt / cxoffice / bin / wineprefixcreate

#!/usr/bin/perl
# (c) Copyright 2002-2012. CodeWeavers, Inc.
use warnings;
use strict;

# The WinePrefixCreate script is responsible for taking a managed bottle
# and replicating it to the specified location.
#
# It can be invoked in two ways:
# * wineprefixcreate --snapshot
#   Takes a 'snapshot' of the reference directory. Depending on the algorithm
#   in use this could be a 'no-operation', or this could mean gathering some
#   information to help the replication process.
# * wineprefixcreate destination_directory
#   Replicates the managed bottle's directory to the specified location. In
#   this mode the exit code should be 0 if the update was successful or
#   3 if no update was needed. All other exit codes indicate errors.

BEGIN {
    unshift @INC, "$ENV{CX_ROOT}/lib/perl";
}
use CXLog;
use CXUtils;

my $FILES="files";



###
# Main
###
my $refdir;
my $wineprefix;

my $opt_snapshot;
my $opt_copy;
my $opt_dry_run;
my $opt_force;
my $opt_verbose;
my $opt_help;
require CXOpts;
my $cxopts=CXOpts->new(["stop_on_non_option"]);
$cxopts->add_options(["snapshot"  => \$opt_snapshot,
                      "copy"      => \$opt_copy,
                      "dry-run"   => \$opt_dry_run,
                      "force!"    => \$opt_force,
                      "ref-dir=s" => \$refdir,
                      "verbose!"  => \$opt_verbose,
                      "?|h|help"  => \$opt_help
                     ]);
my $err=$cxopts->parse();
$wineprefix=shift @ARGV if (@ARGV);

my $fd_log=($opt_dry_run?1:($opt_verbose?2:undef));
CXLog::fdopen($fd_log) if ($fd_log);


# Validate the command line options
my $usage;
if ($err)
{
    cxerr("$err\n");
    $usage=2;
}
elsif ($opt_help)
{
    $usage=0;
}
elsif (@ARGV)
{
    cxerr("unknown option '$ARGV[0]'\n");
    $usage=2;
}
else
{
    if (!defined $refdir)
    {
        if (defined $wineprefix)
        {
            my $bottle=$wineprefix;
            $bottle =~ s%^.*/%%;
            $refdir=$ENV{CX_ROOT};
            $refdir.="/" if ($refdir !~ m%/$%);
            $refdir.="support/$bottle";
        }
        else
        {
            $refdir=$ENV{WINEPREFIX};
        }
    }
    if (!-d $refdir)
    {
        cxerr("'$refdir' is not a directory\n");
        exit 1;
    }
    if ($opt_snapshot and defined $wineprefix)
    {
        cxerr("cannot specify a destination directory in snapshot mode\n");
        $usage=2;
    }
    if (!$opt_snapshot and !defined $wineprefix)
    {
        cxerr("you must specify the wineprefix directory\n");
        $usage=2;
    }
}

if (defined $usage)
{
    my $name0=cxname0();
    if ($usage)
    {
        cxerr("try '$name0 --help' for more information\n");
        exit $usage;
    }
    print "Usage: $name0 [--ref-dir DIR] [--verbose] --snapshot\n";
    print "    or $name0 [--ref-dir DIR] [--verbose] [--force] [--dry-run]\n";
    print "           [--copy] destination_directory\n";

    print "\n";
    print "Where options are:\n";
    print "  --snapshot    Take a snapshot of the reference tree. For the administrator\n";
    print "  --copy        Convert the environment to a standalone user copy\n";
    print "  --force       Go through all the steps even if already up to date\n";
    print "  --dry-run     Do not do anything, just print what would have been done\n";
    print "  --ref-dir DIR Specifies the reference directory\n";
    print "  --verbose     Turns on verbose messages\n";
    print "  --help, -h    Shows this help message\n";
    exit 0;
}

if ($opt_snapshot)
{
    require CXReplicateDir;
    my $file_list=CXReplicateDir::scan_tree($refdir, "^dosdevices\$");
    if (!defined $opt_dry_run)
    {
        # We don't really need the full list of files, only the timestamp
        # will be used. But the file list is not big and it can be useful
        # to the administrator.
        my $now=time;
        $file_list->{$FILES}=$now;
        utime $now, $now, "$refdir/cxbottle.conf";
        CXReplicateDir::write_file_list("$refdir/$FILES", $file_list);

        # And make sure the timestamp matches what's in the file
        utime $now, $now, "$refdir/$FILES";
    }

    # Check the policy
    require CXConfig;
    my $cxconfig=CXConfig->new("$refdir/cxbottle.conf");
    my $cxreplicate=CXReplicateDir->new($refdir, $wineprefix);
    $cxreplicate->set_policy_settings($cxconfig->get_section("ManagedUpdatePolicy"), 1);
}
else
{
    my ($action, $old_file_list);
    if (!-d $wineprefix)
    {
        if (!cxmkpath($wineprefix))
        {
            cxerr("unable to create the '$wineprefix' WinePrefix directory: $@\n");
            exit 1;
        }
        $old_file_list->{types}={};
        $action="create";
    }
    else
    {
        my $fake_windows="$wineprefix/fake_windows";
        my $drive_c="$wineprefix/drive_c";
        if (-d $fake_windows and !-l $fake_windows and !-e $drive_c and
            -d "$refdir/drive_c")
        {
            # Rename fake_windows to drive_c to match the reference directory
            # before we do anything else
            if (rename $fake_windows, $drive_c)
            {
                if (!symlink "drive_c", $fake_windows)
                {
                    cxwarn("unable to create '$fake_windows' link: $!\n");
                }
            }
            else
            {
                cxwarn("unable to rename 'fake_windows' to 'drive_c': $!\n");
            }
        }

        # Fix the profiles directory
        my @profiles=CXUtils::cxglob($wineprefix, "drive_c/Windows/profiles/*", "i");
        if (!grep m!/drive_c/Windows/profiles/crossover$!i, @profiles)
        {
            my $username=(getpwuid($>))[0];
            if ($username)
            {
                @profiles=grep m!/drive_c/Windows/profiles/$username$!i, @profiles;
                if (@profiles == 1 and -d $profiles[0])
                {
                    cxlog("Renaming '$profiles[0]' to 'crossover'\n");
                    my $dir=cxdirname($profiles[0]) . "/crossover";
                    if (!rename $profiles[0], $dir or !symlink "crossover", $profiles[0])
                    {
                        cxlog("unable to move and symlink '$profiles[0]' to '$dir'\n");
                    }
                }
            }
        }

        if (!$opt_force and !$opt_copy)
        {
            my $old_mtime=(stat("$wineprefix/$FILES"))[9];
            my $new_mtime=(stat("$refdir/$FILES"))[9];
            if (defined $new_mtime and defined $old_mtime)
            {
                if ($old_mtime == $new_mtime)
                {
                    # There is nothing to do
                    cxlog("Already up to date\n");
                    exit 3;
                }
            }
        }
        if (-r "$wineprefix/$FILES")
        {
            require CXReplicateDir;
            $old_file_list=CXReplicateDir::read_file_list("$wineprefix/$FILES");
        }
        else
        {
            cxwarn("unable to find the file list from the previous merge\n");
            $old_file_list->{types}={};
        }
        $action="update";
    }

    if (!defined $opt_dry_run)
    {
        cxsystem("$ENV{CX_ROOT}/bin/wine", "--cx-hooks", "pre-$action-stub", $refdir);
    }

    # Retrieve and check the merge settings
    require CXConfig;
    my $cxconfig=CXConfig->new("$refdir/cxbottle.conf");
    require CXReplicateDir;
    my $cxreplicate=CXReplicateDir->new($refdir, $wineprefix);
    $cxreplicate->{old}=$old_file_list;
    $cxreplicate->set_link_type($cxconfig->get("Bottle", "ManagedLinkType"));
    $cxreplicate->set_policy_settings($cxconfig->get_section("ManagedUpdatePolicy"), CXLog::is_on());
    $cxreplicate->set_full_copy(1) if ($opt_copy);

    # - Do not use "$refdir/$FILES" as a basis of what's new as it could be
    #   outdated if Wine has been run since, and may cause problems when
    #   comparing to the date on our links.
    # - Skip dosdevices because we are not merging it using the usual
    #   algorithm.
    $cxreplicate->{new}=CXReplicateDir::scan_tree($refdir, "^dosdevices\$");

    $cxreplicate->merge_tree("^(?:$FILES|dosdevices(?:/[a-z]:)?)\$");
    $cxreplicate->dump_task_list();

    if (!defined $opt_dry_run)
    {
        $cxreplicate->apply_changes();

        # Update the special folder symbolic links
        # Note: this is the first time we run a wine process in the new prefix.
        # We skipped making a dosdevices directory above, so wine
        # will automatically create a minimal one for us.
        # If we are going to merge other drives (e.g., from a published bottle),
        # we will do so later.
        cxsystem("$ENV{CX_ROOT}/bin/wine", "--wl-app", "rundll32.exe", "shell32.dll,wine_update_symbolic_links");

        my $devdir="$wineprefix/dosdevices";
        # Recreate the drive symlinks
        if (opendir(my $dh, $devdir))
        {
            foreach my $dentry (readdir $dh)
            {
                next if ($dentry =~ /^\.\.?$/);
                my $drive="$devdir/$dentry";

                my $delete;
                if (-l $drive)
                {
                    if (!-e $drive)
                    {
                        $delete=1;
                    }
                    else
                    {
                        if ($opt_copy and readlink($drive) eq "$refdir/dosdevices/$dentry")
                        {
                            # Delete the link so we can recreate it later
                            $delete=1;
                        }
                    }
                }
                if ($delete and !unlink $drive)
                {
                    cxwarn("unable to delete '$drive': $!\n");
                }
            }
            closedir($dh);

            # Recreate the c: and y: drives
            if (!-e "$devdir/c:" and !symlink("../drive_c", "$devdir/c:"))
            {
                cxwarn("unable to create '$devdir/c:': $!\n");
            }
            if (!-e "$devdir/z:" and !symlink("/", "$devdir/z:"))
            {
                cxwarn("unable to create '$devdir/z:': $!\n");
            }
            if (defined $ENV{HOME})
            {
                # Also check that the link points to the current $HOME
                my $dst=readlink("$devdir/y:");
                if (!defined $dst or $dst ne $ENV{HOME})
                {
                    unlink "$devdir/y:";
                    if (!symlink($ENV{HOME}, "$devdir/y:"))
                    {
                        cxwarn("unable to create '$devdir/y:': $!\n");
                    }
                }
            }
        }
        if (opendir(my $dh, "$refdir/dosdevices"))
        {
            foreach my $dentry (readdir $dh)
            {
                next if ($dentry =~ /^(\.\.?|[cy]:)$/);
                next if (-e "$devdir/$dentry");

                my $drive="$refdir/dosdevices/$dentry";
                my $target=($opt_copy ? readlink($drive) : $drive);
                if (defined $target and !symlink($target, "$devdir/$dentry"))
                {
                    cxwarn("unable to link '$devdir/$dentry': $!\n");
                }
            }
            closedir($dh);
        }
Loading ...