src/modules/misc.py
changeset 873 b95d76c53b5e
parent 838 aafbe4737188
child 926 6ee411c9026a
--- a/src/modules/misc.py	Fri Feb 13 15:28:56 2009 +0000
+++ b/src/modules/misc.py	Fri Feb 13 13:47:30 2009 -0600
@@ -23,26 +23,26 @@
 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 
+import calendar
+import cStringIO
 import errno
 import httplib
+import locale
 import os
+import pkg.portable as portable
+import pkg.urlhelpers as urlhelpers
 import platform
 import re
 import sha
+import shutil
 import socket
+import sys
+import time
 import urllib
 import urllib2
 import urlparse
-import sys
 import zlib
-import time
-import calendar
-import shutil
-import locale
-from stat import *
 
-import pkg.urlhelpers as urlhelpers
-import pkg.portable as portable
 from pkg.client.imagetypes import img_type_names, IMG_NONE
 from pkg.client import global_settings
 from pkg import VERSION
@@ -59,10 +59,10 @@
 
 def copyfile(src_path, dst_path):
         """copy a file, preserving attributes, ownership, etc. where possible"""
-        stat = os.lstat(src_path)
+        fs = os.lstat(src_path)
         shutil.copy2(src_path, dst_path)
         try:
-                portable.chown(dst_path, stat.st_uid, stat.st_gid)
+                portable.chown(dst_path, fs.st_uid, fs.st_gid)
         except OSError, e:
                 if e.errno != errno.EPERM:
                         raise
@@ -484,6 +484,46 @@
                 res.sort(cmp=__fmri_cmp)
         return res
 
+def get_data_digest(data, length=None, return_content=False):
+        """Returns a tuple of (SHA-1 hexdigest, content).
+
+        'data' should be a file-like object or a pathname to a file.
+
+        'length' should be an integer value representing the size of
+        the contents of data in bytes.
+
+        'return_content' is a boolean value indicating whether the
+        second tuple value should contain the content of 'data' or
+        if the content should be discarded during processing."""
+
+        bufsz = 128 * 1024
+        if isinstance(data, basestring):
+                f = file(data, "rb", bufsz)
+        else:
+                f = data
+
+        if length is None:
+                length = os.lstat(data).st_size
+
+        # Read the data in chunks and compute the SHA1 hash as it comes in.  A
+        # large read on some platforms (e.g. Windows XP) may fail.
+        content = cStringIO.StringIO()
+        fhash = sha.new()
+        while length > 0:
+                data = f.read(min(bufsz, length))
+                if return_content:
+                        content.write(data)
+                fhash.update(data)
+
+                l = len(data)
+                if l == 0:
+                        break
+                length -= l
+        content.reset()
+        f.close()
+
+        return fhash.hexdigest(), content.read()
+
 class CfgCacheError(Exception):
         """Thrown when there are errors with the cfg cache."""
         def __init__(self, args=None):