config/nsinstall.py

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rwxr-xr-x

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 # This is a partial python port of nsinstall.
     6 # It's intended to be used when there's no natively compile nsinstall
     7 # available, and doesn't intend to be fully equivalent.
     8 # Its major use is for l10n repackaging on systems that don't have
     9 # a full build environment set up.
    10 # The basic limitation is, it doesn't even try to link and ignores
    11 # all related options.
    12 from __future__ import print_function
    13 from optparse import OptionParser
    14 import os
    15 import os.path
    16 import sys
    17 import shutil
    18 import stat
    20 def _nsinstall_internal(argv):
    21   usage = "usage: %prog [options] arg1 [arg2 ...] target-directory"
    22   p = OptionParser(usage=usage)
    24   p.add_option('-D', action="store_true",
    25                help="Create a single directory only")
    26   p.add_option('-t', action="store_true",
    27                help="Preserve time stamp")
    28   p.add_option('-m', action="store",
    29                help="Set mode", metavar="mode")
    30   p.add_option('-d', action="store_true",
    31                help="Create directories in target")
    32   p.add_option('-R', action="store_true",
    33                help="Use relative symbolic links (ignored)")
    34   p.add_option('-L', action="store", metavar="linkprefix",
    35                help="Link prefix (ignored)")
    36   p.add_option('-X', action="append", metavar="file",
    37                help="Ignore a file when installing a directory recursively.")
    39   # The remaining arguments are not used in our tree, thus they're not
    40   # implented.
    41   def BadArg(option, opt, value, parser):
    42     parser.error('option not supported: {0}'.format(opt))
    44   p.add_option('-C', action="callback", metavar="CWD",
    45                callback=BadArg,
    46                help="NOT SUPPORTED")
    47   p.add_option('-o', action="callback", callback=BadArg,
    48                help="Set owner (NOT SUPPORTED)", metavar="owner")
    49   p.add_option('-g', action="callback", callback=BadArg,
    50                help="Set group (NOT SUPPORTED)", metavar="group")
    52   (options, args) = p.parse_args(argv)
    54   if options.m:
    55     # mode is specified
    56     try:
    57       options.m = int(options.m, 8)
    58     except:
    59       sys.stderr.write('nsinstall: {0} is not a valid mode\n'
    60                        .format(options.m))
    61       return 1
    63   # just create one directory?
    64   def maybe_create_dir(dir, mode, try_again):
    65     dir = os.path.abspath(dir)
    66     if os.path.exists(dir):
    67       if not os.path.isdir(dir):
    68         print('nsinstall: {0} is not a directory'.format(dir), file=sys.stderr)
    69         return 1
    70       if mode:
    71         os.chmod(dir, mode)
    72       return 0
    74     try:
    75       if mode:
    76         os.makedirs(dir, mode)
    77       else:
    78         os.makedirs(dir)
    79     except Exception as e:
    80       # We might have hit EEXIST due to a race condition (see bug 463411) -- try again once
    81       if try_again:
    82         return maybe_create_dir(dir, mode, False)
    83       print("nsinstall: failed to create directory {0}: {1}".format(dir, e))
    84       return 1
    85     else:
    86       return 0
    88   if options.X:
    89     options.X = [os.path.abspath(p) for p in options.X]
    91   if options.D:
    92     return maybe_create_dir(args[0], options.m, True)
    94   # nsinstall arg1 [...] directory
    95   if len(args) < 2:
    96     p.error('not enough arguments')
    98   def copy_all_entries(entries, target):
    99     for e in entries:
   100       e = os.path.abspath(e)
   101       if options.X and e in options.X:
   102         continue
   104       dest = os.path.join(target, os.path.basename(e))
   105       dest = os.path.abspath(dest)
   106       handleTarget(e, dest)
   107       if options.m:
   108         os.chmod(dest, options.m)
   110   # set up handler
   111   if options.d:
   112     # we're supposed to create directories
   113     def handleTarget(srcpath, targetpath):
   114       # target directory was already created, just use mkdir
   115       os.mkdir(targetpath)
   116   else:
   117     # we're supposed to copy files
   118     def handleTarget(srcpath, targetpath):
   119       if os.path.isdir(srcpath):
   120         if not os.path.exists(targetpath):
   121           os.mkdir(targetpath)
   122         entries = [os.path.join(srcpath, e) for e in os.listdir(srcpath)]
   123         copy_all_entries(entries, targetpath)
   124         # options.t is not relevant for directories
   125         if options.m:
   126           os.chmod(targetpath, options.m)
   127       else:
   128         if os.path.exists(targetpath):
   129           # On Windows, read-only files can't be deleted
   130           os.chmod(targetpath, stat.S_IWUSR)
   131           os.remove(targetpath)
   132         if options.t:
   133           shutil.copy2(srcpath, targetpath)
   134         else:
   135           shutil.copy(srcpath, targetpath)
   137   # the last argument is the target directory
   138   target = args.pop()
   139   # ensure target directory (importantly, we do not apply a mode to the directory
   140   # because we want to copy files into it and the mode might be read-only)
   141   rv = maybe_create_dir(target, None, True)
   142   if rv != 0:
   143     return rv
   145   copy_all_entries(args, target)
   146   return 0
   148 # nsinstall as a native command is always UTF-8
   149 def nsinstall(argv):
   150   return _nsinstall_internal([unicode(arg, "utf-8") for arg in argv])
   152 if __name__ == '__main__':
   153   # sys.argv corrupts characters outside the system code page on Windows
   154   # <http://bugs.python.org/issue2128>. Use ctypes instead. This is also
   155   # useful because switching to Unicode strings makes python use the wide
   156   # Windows APIs, which is what we want here since the wide APIs normally do a
   157   # better job at handling long paths and such.
   158   if sys.platform == "win32":
   159     import ctypes
   160     from ctypes import wintypes
   161     GetCommandLine = ctypes.windll.kernel32.GetCommandLineW
   162     GetCommandLine.argtypes = []
   163     GetCommandLine.restype = wintypes.LPWSTR
   165     CommandLineToArgv = ctypes.windll.shell32.CommandLineToArgvW
   166     CommandLineToArgv.argtypes = [wintypes.LPWSTR, ctypes.POINTER(ctypes.c_int)]
   167     CommandLineToArgv.restype = ctypes.POINTER(wintypes.LPWSTR)
   169     argc = ctypes.c_int(0)
   170     argv_arr = CommandLineToArgv(GetCommandLine(), ctypes.byref(argc))
   171     # The first argv will be "python", the second will be the .py file
   172     argv = argv_arr[1:argc.value]
   173   else:
   174     # For consistency, do it on Unix as well
   175     if sys.stdin.encoding is not None:
   176       argv = [unicode(arg, sys.stdin.encoding) for arg in sys.argv]
   177     else:
   178       argv = [unicode(arg) for arg in sys.argv]
   180   sys.exit(_nsinstall_internal(argv[1:]))

mercurial