class MagicFolder(service.MultiService):
name = 'magic-folder'
- def __init__(self, client, upload_dircap, collective_dircap, local_path_u, dbfile,
+ def __init__(self, client, upload_dircap, collective_dircap, local_path_u, dbfile, umask,
pending_delay=1.0, clock=None):
precondition_abspath(local_path_u)
self.uploader = Uploader(client, local_path_u, db, upload_dirnode, pending_delay, clock, immediate)
self.downloader = Downloader(client, local_path_u, db, collective_dirnode,
- upload_dirnode.get_readonly_uri(), clock, self.uploader.is_pending)
+ upload_dirnode.get_readonly_uri(), clock, self.uploader.is_pending, umask)
def startService(self):
# TODO: why is this being called more than once?
# ensure parent directory exists
head, tail = os.path.split(abspath_u)
- mode = 0777 # XXX
- fileutil.make_dirs(head, mode)
- fileutil.write(replacement_path_u, file_contents)
+ old_mask = os.umask(self._umask)
+ try:
+ fileutil.make_dirs(head, (~ self._umask) & 0777)
+ fileutil.write(replacement_path_u, file_contents)
+ finally:
+ os.umask(old_mask)
+
+ # FUDGE_SECONDS is used to determine if another process
+ # has written to the same file concurrently. This is described
+ # in the Earth Dragon section of our design document:
+ # docs/proposed/magic-folder/remote-to-local-sync.rst
os.utime(replacement_path_u, (now, now - self.FUDGE_SECONDS))
if is_conflict:
print "0x00 ------------ <><> is conflict; calling _rename_conflicted_file... %r %r" % (abspath_u, replacement_path_u)
REMOTE_SCAN_INTERVAL = 3 # facilitates tests
def __init__(self, client, local_path_u, db, collective_dirnode,
- upload_readonly_dircap, clock, is_upload_pending):
+ upload_readonly_dircap, clock, is_upload_pending, umask):
QueueMixin.__init__(self, client, local_path_u, db, 'downloader', clock)
if not IDirectoryNode.providedBy(collective_dirnode):
self._collective_dirnode = collective_dirnode
self._upload_readonly_dircap = upload_readonly_dircap
self._is_upload_pending = is_upload_pending
-
- self._turn_delay = self.REMOTE_SCAN_INTERVAL
+ self._umask = umask
def start_scanning(self):
self._log("start_scanning")
node = None
for success, result in deferredList:
if success:
+ if 'version' not in result[1]:
+ self._log("invalid remote metadata detected")
+ continue
+
if result[1]['version'] > max_version:
node, metadata = result
max_version = result[1]['version']
file_node, metadata = listing_map[encoded_relpath_u]
local_version = self._get_local_latest(relpath_u)
- remote_version = metadata.get('version', None)
+
+ if 'version' not in metadata:
+ self._log("invalid remote metadata detected for %r" % (relpath_u,))
+ continue
+
+ remote_version = metadata['version']
self._log("%r has local version %r, remote version %r" % (relpath_u, local_version, remote_version))
- if local_version is None or remote_version is None or local_version < remote_version:
+ if local_version is None or local_version < remote_version:
self._log("%r added to download queue" % (relpath_u,))
if scan_batch.has_key(relpath_u):
scan_batch[relpath_u] += [(file_node, metadata)]
return d
def _when_queue_is_empty(self):
- d = task.deferLater(self._clock, self._turn_delay, self._scan_remote_collective)
+ d = task.deferLater(self._clock, self.REMOTE_SCAN_INTERVAL, self._scan_remote_collective)
d.addBoth(self._logcb, "after _scan_remote_collective 1")
d.addCallback(lambda ign: self._turn_deque())
return d