server/sources/storages.py
changeset 8180 1f6ba9afb925
parent 8148 b7a195d54fd4
child 8307 8be58694f416
--- a/server/sources/storages.py	Mon Jan 23 12:39:21 2012 +0100
+++ b/server/sources/storages.py	Wed Jan 18 15:27:08 2012 +0100
@@ -18,6 +18,7 @@
 """custom storages for the system source"""
 
 import os
+import sys
 from os import unlink, path as osp
 from contextlib import contextmanager
 
@@ -112,11 +113,29 @@
 
 class BytesFileSystemStorage(Storage):
     """store Bytes attribute value on the file system"""
-    def __init__(self, defaultdir, fsencoding='utf-8'):
+    def __init__(self, defaultdir, fsencoding='utf-8', wmode=0444):
         if type(defaultdir) is unicode:
             defaultdir = defaultdir.encode(fsencoding)
         self.default_directory = defaultdir
         self.fsencoding = fsencoding
+        # extra umask to use when creating file
+        # 0444 as in "only allow read bit in permission"
+        self._wmode = wmode
+
+    def _writecontent(self, path, binary):
+        """write the content of a binary in readonly file
+
+        As the bfss never alter a create file it does not prevent it to work as
+        intended. This is a beter safe than sorry approach.
+        """
+        write_flag = os.O_WRONLY | os.O_CREAT | os.O_EXCL
+        if sys.platform == 'win32':
+            write_flag |= os.O_BINARY
+        fd = os.open(path, write_flag, self._wmode)
+        fileobj = os.fdopen(fd, 'wb')
+        binary.to_file(fileobj)
+        fileobj.close()
+
 
     def callback(self, source, session, value):
         """sql generator callback when some attribute with a custom storage is
@@ -138,7 +157,7 @@
             fpath = self.new_fs_path(entity, attr)
             # bytes storage used to store file's path
             entity.cw_edited.edited_attribute(attr, Binary(fpath))
-            binary.to_file(fpath)
+            self._writecontent(fpath, binary)
             AddFileOp.get_instance(entity._cw).add_data(fpath)
         return binary
 
@@ -171,7 +190,7 @@
                 fpath = self.new_fs_path(entity, attr)
                 assert not osp.exists(fpath)
                 # write attribute value on disk
-                binary.to_file(fpath)
+                self._writecontent(fpath, binary)
                 # Mark the new file as added during the transaction.
                 # The file will be removed on rollback
                 AddFileOp.get_instance(entity._cw).add_data(fpath)