예제 #1
0
    def writeImage(self, imagePath=None, newDisc=False, writeMulti=True):
        """
        Writes an ISO image to the media in the device.

        If ``newDisc`` is passed in as ``True``, we assume that the entire disc
        will be re-created from scratch.  Note that unlike ``CdWriter``,
        ``DvdWriter`` does not blank rewritable media before reusing it; however,
        ``growisofs`` is called such that the media will be re-initialized as
        needed.

        If ``imagePath`` is passed in as ``None``, then the existing image
        configured with ``initializeImage()`` will be used.  Under these
        circumstances, the passed-in ``newDisc`` flag will be ignored and the
        value passed in to ``initializeImage()`` will apply instead.

        The ``writeMulti`` argument is ignored.  It exists for compatibility with
        the Cedar Backup image writer interface.

        *Note:* The image size indicated in the log ("Image size will be...") is
        an estimate.  The estimate is conservative and is probably larger than
        the actual space that ``dvdwriter`` will use.

        Args:
           imagePath (String representing a path on disk): Path to an ISO image on disk, or ``None`` to use writer's image
           newDisc (Boolean true/false): Indicates whether the disc should be re-initialized
           writeMulti (Boolean true/false): Unused
        Raises:
           ValueError: If the image path is not absolute
           ValueError: If some path cannot be encoded properly
           IOError: If the media could not be written to for some reason
           ValueError: If no image is passed in and initializeImage() was not previously called
        """
        if not writeMulti:
            logger.warning("writeMulti value of [%s] ignored.", writeMulti)
        if imagePath is None:
            if self._image is None:
                raise ValueError(
                    "Must call initializeImage() before using this method with no image path."
                )
            size = self.getEstimatedImageSize()
            logger.info("Image size will be %s (estimated).",
                        displayBytes(size))
            available = self.retrieveCapacity(
                entireDisc=self._image.newDisc).bytesAvailable
            if size > available:
                logger.error(
                    "Image [%s] does not fit in available capacity [%s].",
                    displayBytes(size), displayBytes(available))
                raise IOError(
                    "Media does not contain enough capacity to store image.")
            self._writeImage(self._image.newDisc, None, self._image.entries,
                             self._image.mediaLabel)
        else:
            if not os.path.isabs(imagePath):
                raise ValueError("Image path must be absolute.")
            imagePath = encodePath(imagePath)
            self._writeImage(newDisc, imagePath, None)
예제 #2
0
def extractTar(tmpdir, filepath):
    """
    Extracts the indicated tar file to the indicated tmpdir.
    Args:
       tmpdir: Temp directory to extract to
       filepath: Path to tarfile to extract
    Raises:
       ValueError: If a path cannot be encoded properly
    """
    # pylint: disable=E1101
    tmpdir = encodePath(tmpdir)
    filepath = encodePath(filepath)
    with tarfile.open(filepath) as tar:
        try:
            tar.format = tarfile.GNU_FORMAT
        except AttributeError:
            tar.posix = False
        for tarinfo in tar:
            tar.extract(tarinfo, tmpdir)
예제 #3
0
def buildPath(components):
    """
    Builds a complete path from a list of components.
    For instance, constructs ``"/a/b/c"`` from ``["/a", "b", "c"]``.
    Args:
       components: List of components
    Returns:
        String path constructed from components
    Raises:
       ValueError: If a path cannot be encoded properly
    """
    path = components[0]
    for component in components[1:]:
        path = pathJoin(path, component)
    return encodePath(path)
예제 #4
0
    def initializeImage(self, newDisc, tmpdir, mediaLabel=None):
        """
        Initializes the writer's associated ISO image.

        This method initializes the ``image`` instance variable so that the caller
        can use the ``addImageEntry`` method.  Once entries have been added, the
        ``writeImage`` method can be called with no arguments.

        Args:
           newDisc (Boolean true/false): Indicates whether the disc should be re-initialized
           tmpdir (String representing a directory path on disk): Temporary directory to use if needed
           mediaLabel (String, no more than 25 characters long): Media label to be applied to the image, if any

        """
        self._image = _ImageProperties()
        self._image.newDisc = newDisc
        self._image.tmpdir = encodePath(tmpdir)
        self._image.mediaLabel = mediaLabel
        self._image.entries = {}  # mapping from path to graft point (if any)
예제 #5
0
    def writeImage(self, imagePath):
        """
        Writes this image to disk using the image path.

        Args:
           imagePath (String representing a path on disk): Path to write image out as
        Raises:
           IOError: If there is an error writing the image to disk
           ValueError: If there are no filesystem entries in the image
           ValueError: If a path cannot be encoded properly
        """
        imagePath = encodePath(imagePath)
        if len(list(self.entries.keys())) == 0:
            raise ValueError("Image does not contain any entries.")
        args = self._buildWriteArgs(self.entries, imagePath)
        command = resolveCommand(MKISOFS_COMMAND)
        (result, output) = executeCommand(command, args, returnOutput=False)
        if result != 0:
            raise IOError(
                "Error (%d) executing mkisofs command to build image." %
                result)
예제 #6
0
def validateDevice(device, unittest=False):
    """
    Validates a configured device.
    The device must be an absolute path, must exist, and must be writable.
    The unittest flag turns off validation of the device on disk.
    Args:
       device: Filesystem device path
       unittest: Indicates whether we're unit testing
    Returns:
        Device as a string, for instance ``"/dev/cdrw"``
    Raises:
       ValueError: If the device value is invalid
       ValueError: If some path cannot be encoded properly
    """
    if device is None:
        raise ValueError("Device must be filled in.")
    device = encodePath(device)
    if not os.path.isabs(device):
        raise ValueError("Backup device must be an absolute path.")
    if not unittest and not os.path.exists(device):
        raise ValueError("Backup device must exist on disk.")
    if not unittest and not os.access(device, os.W_OK):
        raise ValueError("Backup device is not writable by the current user.")
    return device
예제 #7
0
def changeFileAge(filename, subtract=None):
    """
    Changes a file age using the ``os.utime`` function.

    *Note:* Some platforms don't seem to be able to set an age precisely.  As a
    result, whereas we might have intended to set an age of 86400 seconds, we
    actually get an age of 86399.375 seconds.  When util.calculateFileAge()
    looks at that the file, it calculates an age of 0.999992766204 days, which
    then gets truncated down to zero whole days.  The tests get very confused.
    To work around this, I always subtract off one additional second as a fudge
    factor.  That way, the file age will be *at least* as old as requested
    later on.

    Args:
       filename: File to operate on
       subtract: Number of seconds to subtract from the current time
    Raises:
       ValueError: If a path cannot be encoded properly
    """
    filename = encodePath(filename)
    newTime = time.time() - 1
    if subtract is not None:
        newTime -= subtract
    os.utime(filename, (newTime, newTime))
예제 #8
0
def removedir(tree):
    """
    Recursively removes an entire directory.
    This is basically taken from an example on python.com.
    Args:
       tree: Directory tree to remove
    Raises:
       ValueError: If a path cannot be encoded properly
    """
    tree = encodePath(tree)
    for root, dirs, files in os.walk(tree, topdown=False):
        for name in files:
            path = pathJoin(root, name)
            if os.path.islink(path):
                os.remove(path)
            elif os.path.isfile(path):
                os.remove(path)
        for name in dirs:
            path = pathJoin(root, name)
            if os.path.islink(path):
                os.remove(path)
            elif os.path.isdir(path):
                os.rmdir(path)
    os.rmdir(tree)
예제 #9
0
    def addEntry(self,
                 path,
                 graftPoint=None,
                 override=False,
                 contentsOnly=False):
        """
        Adds an individual file or directory into the ISO image.

        The path must exist and must be a file or a directory.  By default, the
        entry will be placed into the image at the root directory, but this
        behavior can be overridden using the ``graftPoint`` parameter or instance
        variable.

        You can use the ``contentsOnly`` behavior to revert to the "original"
        ``mkisofs`` behavior for adding directories, which is to add only the
        items within the directory, and not the directory itself.

        *Note:* Things get *odd* if you try to add a directory to an image that
        will be written to a multisession disc, and the same directory already
        exists in an earlier session on that disc.  Not all of the data gets
        written.  You really wouldn't want to do this anyway, I guess.

        *Note:* An exception will be thrown if the path has already been added to
        the image, unless the ``override`` parameter is set to ``True``.

        *Note:* The method ``graftPoints`` parameter overrides the object-wide
        instance variable.  If neither the method parameter or object-wide value
        is set, the path will be written at the image root.  The graft point
        behavior is determined by the value which is in effect I{at the time this
        method is called}, so you *must* set the object-wide value before
        calling this method for the first time, or your image may not be
        consistent.

        *Note:* You *cannot* use the local ``graftPoint`` parameter to "turn off"
        an object-wide instance variable by setting it to ``None``.  Python's
        default argument functionality buys us a lot, but it can't make this
        method psychic. :)

        Args:
           path (String representing a path on disk): File or directory to be added to the image
           graftPoint (String representing a graft point path, as described above): Graft point to be used when adding this entry
           override (Boolean true/false): Override an existing entry with the same path
           contentsOnly (Boolean true/false): Add directory contents only (standard ``mkisofs`` behavior)
        Raises:
           ValueError: If path is not a file or directory, or does not exist
           ValueError: If the path has already been added, and override is not set
           ValueError: If a path cannot be encoded properly
        """
        path = encodePath(path)
        if not override:
            if path in list(self.entries.keys()):
                raise ValueError("Path has already been added to the image.")
        if os.path.islink(path):
            raise ValueError("Path must not be a link.")
        if os.path.isdir(path):
            if graftPoint is not None:
                if contentsOnly:
                    self.entries[path] = graftPoint
                else:
                    self.entries[path] = pathJoin(graftPoint,
                                                  os.path.basename(path))
            elif self.graftPoint is not None:
                if contentsOnly:
                    self.entries[path] = self.graftPoint
                else:
                    self.entries[path] = pathJoin(self.graftPoint,
                                                  os.path.basename(path))
            else:
                if contentsOnly:
                    self.entries[path] = None
                else:
                    self.entries[path] = os.path.basename(path)
        elif os.path.isfile(path):
            if graftPoint is not None:
                self.entries[path] = graftPoint
            elif self.graftPoint is not None:
                self.entries[path] = self.graftPoint
            else:
                self.entries[path] = None
        else:
            raise ValueError("Path must be a file or a directory.")