summaryrefslogtreecommitdiffstats
path: root/tails_installer/source.py
blob: 96cb7857eb5d90db87f825bab2d5871d89183024 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# -*- coding: utf-8 -*-

import os
import shutil
import sys
import subprocess
from stat import ST_SIZE
from tails_installer import _
from tails_installer.releases import releases
from tails_installer.config import config
from tails_installer.utils import (_to_unicode, _dir_size, iso_is_live_system,
                           unicode_to_utf8, unicode_to_filesystemencoding,
                           _set_liberal_perms_recursive,
                           underlying_physical_device)

class SourceError(Exception):
    """ A generic error message that is thrown by the Source classes """

class Source(object):
    def clone(self, destination):
        raise NotImplementedError

class LocalIsoSource(Source):
    def __init__(self, path):
        self.path = os.path.abspath(_to_unicode(path))
        self.size = os.stat(self.path)[ST_SIZE]
        if not iso_is_live_system(self.path):
            raise SourceError(_("Unable to find LiveOS on ISO"))
        self.dev  = None
        # This can fail for devices not supported by UDisks such as aufs mounts
        try:
            self.dev = underlying_physical_device(self.path)
        except Exception, e:
            print >> sys.stderr, _("Could not guess underlying block device: %s"
                                   % e.args[0])
            pass

    def clone(self, destination):
        cmd = ['7z', 'x', self.path,
               '-x![BOOT]', '-y', '-o%s' % (destination)]
        cmd_decoded = u' '.join(cmd)
        cmd_bytes = [ unicode_to_filesystemencoding(el) for el in cmd ]
        proc = subprocess.Popen(cmd_bytes, stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        out, err = proc.communicate()
        out = out.decode('utf-8')
        err = err.decode('utf-8')
        if proc.returncode:
            raise SourceError(_("There was a problem executing `%s`.\n"
                                "%s\n%s" % (cmd_decoded, out, err)))
        _set_liberal_perms_recursive(destination)

    def get_release(self):
        """ If the ISO is for a known release, return it. """
        isoname = os.path.basename(self.path)
        for release in releases:
            if os.path.basename(release['url']) == isoname:
                return release

class RunningLiveSystemSource(Source):
    def __init__(self, path):
        if not os.path.exists(path):
            raise SourceError(_("'%s' does not exist") % path)
        if not os.path.isdir(path):
            raise SourceError(_("'%s' is not a directory") % path)
        self.path = path
        self.size = _dir_size(self.path)
        self.dev  = underlying_physical_device(self.path)
    def clone(self, destination):
        for f in config['liveos_toplevel_files']:
            src = os.path.join(self.path, f)
            dst = os.path.join(destination, f)
            if os.path.isfile(src):
                if src.lower().endswith('.iso'):
                    print >> sys.stderr, _("Skipping '%(filename)s'" % {
                        'filename': src
                    })
                else:
                    shutil.copy(src, dst)
            elif os.path.islink(src):
                linkto = os.readlink(src)
                os.symlink(linkto, dst)
            elif os.path.isdir(src):
                shutil.copytree(src, dst)
        _set_liberal_perms_recursive(destination)