fix archive files being created with perms 000

In python 2.5 and earlier, ZipFile.writestr(filename, data) results in
the file being added to the archive with permissions 000.  (See
http://svn.python.org/view?view=rev&revision=65235.)  Work around this
by creating a ZipInfo object and setting the permissions explicitly.
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 686c6ef..033ba22 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -21,6 +21,7 @@
 import subprocess
 import sys
 import tempfile
+import zipfile
 
 # missing in Python 2.4 and before
 if not hasattr(os, "SEEK_SET"):
@@ -70,7 +71,7 @@
   img = BuildBootableImage(sourcedir)
 
   CheckSize(img, targetname)
-  output_zip.writestr(targetname, img)
+  ZipWriteStr(output_zip, targetname, img)
 
 def BuildBootableImage(sourcedir):
   """Take a kernel, cmdline, and ramdisk directory from the input (in
@@ -381,3 +382,12 @@
       if e.errno != errno.ENOENT:
         print "error reading password file: ", str(e)
     return result
+
+
+def ZipWriteStr(zip, filename, data, perms=0644):
+  # use a fixed timestamp so the output is repeatable.
+  zinfo = zipfile.ZipInfo(filename=filename,
+                          date_time=(2009, 1, 1, 0, 0, 0))
+  zinfo.compress_type = zip.compression
+  zinfo.external_attr = perms << 16
+  zip.writestr(zinfo, data)
diff --git a/tools/releasetools/img_from_target_files b/tools/releasetools/img_from_target_files
index 3451352..1d154b9 100755
--- a/tools/releasetools/img_from_target_files
+++ b/tools/releasetools/img_from_target_files
@@ -96,7 +96,7 @@
   img.close()
 
   common.CheckSize(data, "system.img")
-  output_zip.writestr("system.img", data)
+  common.ZipWriteStr(output_zip, "system.img", data)
 
 
 def CopyInfo(output_zip):
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index 7e36da2..1ac035a 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -267,11 +267,8 @@
 
 
 def AddScript(script, output_zip):
-  now = time.localtime()
-  i = zipfile.ZipInfo("META-INF/com/google/android/update-script",
-                      (now.tm_year, now.tm_mon, now.tm_mday,
-                       now.tm_hour, now.tm_min, now.tm_sec))
-  output_zip.writestr(i, "\n".join(script) + "\n")
+  common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-script",
+                     "\n".join(script) + "\n")
 
 
 def SignOutput(temp_zip_name, output_zip_name):
@@ -328,7 +325,7 @@
       data = open(input_path).read()
     else:
       data = input_zip.read(os.path.join("OTA/bin", name))
-    output_zip.writestr(name, data)
+    common.ZipWriteStr(output_zip, name, data, perms=0755)
   except IOError:
     raise ExternalError('unable to include device binary "%s"' % (name,))
 
@@ -346,7 +343,7 @@
   script.append("format BOOT:")
   script.append("show_progress 0.1 0")
 
-  output_zip.writestr("radio.img", input_zip.read("RADIO/image"))
+  common.ZipWriteStr(output_zip, "radio.img", input_zip.read("RADIO/image"))
   script.append("write_radio_image PACKAGE:radio.img")
   script.append("show_progress 0.5 0")
 
@@ -390,7 +387,7 @@
     return t
 
   def AddToZip(self, z):
-    z.writestr(self.name, self.data)
+    common.ZipWriteStr(z, self.name, self.data)
 
 
 def LoadSystemFiles(z):
@@ -486,7 +483,7 @@
         tf.AddToZip(output_zip)
         verbatim_targets.append((fn, tf.size))
       else:
-        output_zip.writestr("patch/" + fn + ".p", d)
+        common.ZipWriteStr(output_zip, "patch/" + fn + ".p", d)
         patch_list.append((fn, tf, sf, tf.size))
         largest_source_size = max(largest_source_size, sf.size)
     else:
@@ -552,7 +549,7 @@
     print "recovery  target: %d  source: %d  diff: %d" % (
         target_recovery.size, source_recovery.size, len(d))
 
-    output_zip.writestr("patch/recovery.img.p", d)
+    common.ZipWriteStr(output_zip, "patch/recovery.img.p", d)
 
     script.append(("run_program PACKAGE:applypatch -c "
                    "MTD:recovery:%d:%s:%d:%s") %
@@ -564,7 +561,7 @@
     print "boot      target: %d  source: %d  diff: %d" % (
         target_boot.size, source_boot.size, len(d))
 
-    output_zip.writestr("patch/boot.img.p", d)
+    common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
 
     script.append(("run_program PACKAGE:applypatch -c "
                    "MTD:boot:%d:%s:%d:%s") %
@@ -617,7 +614,7 @@
   if updating_radio:
     script.append("show_progress 0.3 10")
     script.append("write_radio_image PACKAGE:radio.img")
-    output_zip.writestr("radio.img", target_radio)
+    common.ZipWriteStr(output_zip, "radio.img", target_radio)
     print "radio image changed; including."
   else:
     print "radio image unchanged; skipping."
diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks
index 9f393c8..bc04956 100755
--- a/tools/releasetools/sign_target_files_apks
+++ b/tools/releasetools/sign_target_files_apks
@@ -283,7 +283,7 @@
   data, _ = p.communicate()
   if p.returncode != 0:
     raise ExternalError("failed to run dumpkeys")
-  output_tf_zip.writestr("RECOVERY/RAMDISK/res/keys", data)
+  common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", data)
 
   # SystemUpdateActivity uses the x509.pem version of the keys, but
   # put into a zipfile system/etc/security/otacerts.zip.
@@ -293,8 +293,8 @@
   for k in mapped_keys:
     certs_zip.write(k)
   certs_zip.close()
-  output_tf_zip.writestr("SYSTEM/etc/security/otacerts.zip",
-                         tempfile.getvalue())
+  common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip",
+                     tempfile.getvalue())
 
 
 def main(argv):