Newer
Older
# Installsystems is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# Installsystems is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with Installsystems. If not, see <http://www.gnu.org/licenses/>.
from installsystems.exception import *
'''
Tarball wrapper
'''
def add_str(self, name, content, ftype, mode, mtime=None,
uid=None, gid=None, uname=None, gname=None):
'''
Add a string in memory as a file in tarball
'''
if isinstance(name, unicode):
name = name.encode("UTF-8")
# set tarinfo attribute
for v in ("name", "ftype", "mode", "mtime", "uid", "gid", "uname", "gname"):
if vars()[v] is not None:
vars(ti)[v] = vars()[v]
# set mtime to current if not specified
if mtime is None:
ti.mtime = int(time.time())
# unicode char is encoded in UTF-8, has changelog must be in UTF-8
if isinstance(content, unicode):
content = content.encode("UTF-8")
ti.size = len(content) if content is not None else 0
self.addfile(ti, StringIO.StringIO(content))
def get_str(self, name):
'''
Return a string from a filename in a tarball
'''
if isinstance(name, unicode):
name = name.encode("UTF-8")
fd = self.extractfile(ti)
return fd.read() if fd is not None else ""
def get_utf8(self, name):
'''
Return an unicode string from a file encoded in UTF-8 inside tarball
'''
if isinstance(name, unicode):
name = name.encode("UTF-8")
try:
return unicode(self.get_str(name), "UTF-8")
except UnicodeDecodeError:
raise ISError(u"Invalid UTF-8 character in %s" % name)
def getnames(self, re_pattern=None, glob_pattern=None, dir=True):
names = super(Tarball, self).getnames()
names = filter(lambda x: re.match(re_pattern, x), names)
names = fnmatch.filter(names, glob_pattern)
# dir filering
if not dir:
names = filter(lambda x: not self.getmember(x).isdir(), names)
# unicode encoding
return map(lambda x: unicode(x, "UTF-8"), names)
'''
Return real (uncompressed) size of the tarball
'''
total_sz = 0
for ti in self.getmembers():
total_sz += ti.size
return total_sz
def chown(self, tarinfo, targetpath):
'''
Override real chown method from tarfile which make crazy check about
uid/gid before chowning. This leads to bug when a uid/gid doesn't
exitsts on the running system
This overide as a sexy side effect which allow badly create tarball
(whithout --numeric-owner) to be extracted correctly
This was reported upstream: http://bugs.python.org/issue12841
'''
if hasattr(os, "geteuid") and os.geteuid() == 0:
# We have to be root to do so.
try:
if tarinfo.issym() and hasattr(os, "lchown"):
os.lchown(targetpath, tarinfo.uid, tarinfo.gid)
else:
if sys.platform != "os2emx":
os.chown(targetpath, tarinfo.uid, tarinfo.gid)
except EnvironmentError, e:
raise ExtractError("could not change owner")