[Zope3-checkins] CVS: Zope3/src/zope/app/fssync - committer.py:1.15.2.1 classes.py:1.4.2.1 configure.zcml:1.2.4.1 fsregistry.py:1.3.2.1 syncer.py:1.19.2.1

Grégoire Weber zope@i-con.ch
Sun, 22 Jun 2003 10:24:05 -0400


Update of /cvs-repository/Zope3/src/zope/app/fssync
In directory cvs.zope.org:/tmp/cvs-serv24874/src/zope/app/fssync

Modified Files:
      Tag: cw-mail-branch
	classes.py configure.zcml fsregistry.py syncer.py 
Added Files:
      Tag: cw-mail-branch
	committer.py 
Log Message:
Synced up with HEAD

=== Added File Zope3/src/zope/app/fssync/committer.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Commit changes from the filesystem.

$Id: committer.py,v 1.15.2.1 2003/06/22 14:23:03 gregweb Exp $
"""

import os
import shutil

from zope.component import getAdapter, queryAdapter, getService
from zope.xmlpickle import dumps, loads
from zope.configuration.name import resolve
from zope.proxy import removeAllProxies

from zope.fssync.metadata import Metadata
from zope.fssync import fsutil

from zope.app.interfaces.fssync \
     import IObjectEntry, IObjectDirectory, IObjectFile

from zope.app.context import ContextWrapper
from zope.app.interfaces.container import IContainer, IZopeContainer
from zope.app.fssync.classes import Default
from zope.app.traversing import getPath, traverseName, getName
from zope.app.interfaces.file import IFileFactory, IDirectoryFactory
from zope.app.event import publish
from zope.app.event.objectevent import ObjectCreatedEvent
from zope.app.event.objectevent import ObjectModifiedEvent

class SynchronizationError(Exception):
    pass

class Checker(object):
    """Check that the filesystem is consistent with the object database.

    The public API consists of __init__(), check() and errors() only.
    """

    def __init__(self, metadata=None, raise_on_conflicts=False):
        """Constructor.  Optionally pass a metadata database."""
        if metadata is None:
            metadata = Metadata()
        self.metadata = metadata
        self.raise_on_conflicts = raise_on_conflicts
        self.conflicts = []

    def errors(self):
        """Return a list of errors (conflicts).

        The return value is a list of filesystem pathnames for which
        a conflict exists.  A conflict usually refers to a file that
        was modified on the filesystem while the corresponding object
        was also modified in the database.  Other forms of conflicts
        are possible, e.g. a file added while an object was added in
        the corresponding place, or inconsistent labeling of the
        filesystem objects (e.g. an existing file marked as removed,
        or a non-existing file marked as added).
        """
        return self.conflicts

    def check(self, container, name, fspath):
        """Compare an object or object tree from the filesystem.

        If the originals on the filesystem are not uptodate, errors
        are reported by calling conflict().

        Invalid object names are reported by raising
        SynchronizationError.
        """

        if (os.sep in name or
            (os.altsep and os.altsep in name) or
            name == os.curdir or
            name == os.pardir or
            name == "." or
            name == ".." or
            "/" in name):
            # This name can't be mapped safely to the filesystem
            # or it is a magic value for traverseName (".", "..", "/")
            raise SynchronizationError("invalid separator in name %r" % name)

        if not name:
            self.check_dir(container, fspath)
        else:
            try:
                traverseName(container, name)
            except:
                self.check_new(fspath)
            else:
                self.check_old(container, name, fspath)

            # Now check extra and annotations
            try:
                obj = traverseName(container, name)
            except:
                pass
            else:
                adapter = get_adapter(obj)
                extra = adapter.extra()
                extrapath = fsutil.getextra(fspath)
                if extra is not None and os.path.exists(extrapath):
                    self.check_dir(extra, extrapath)
                ann = adapter.annotations()
                annpath = fsutil.getannotations(fspath)
                if ann is not None and os.path.exists(annpath):
                    self.check_dir(ann, annpath)

    def check_dir(self, container, fspath):
        """Helper to check a directory."""
        adapter = get_adapter(container)
        nameset = {}
        if IObjectDirectory.isImplementedBy(adapter):
            for name, obj in adapter.contents():
                nameset[name] = 1
        else:
            for name in container:
                nameset[name] = 1
        for name in self.metadata.getnames(fspath):
            nameset[name] = 1
        # Sort the list of keys for repeatability
        names = nameset.keys()
        names.sort()
        for name in names:
            self.check(container, name, os.path.join(fspath, name))

    def check_new(self, fspath):
        """Helper to check a new object."""
        entry = self.metadata.getentry(fspath)
        if entry:
            if entry.get("flag") != "added":
                self.conflict(fspath)
            else:
                if not os.path.exists(fspath):
                    self.conflict(fspath)
            if os.path.isdir(fspath):
                # Recursively check registered contents
                for name in self.metadata.getnames(fspath):
                    self.check_new(os.path.join(fspath, name))

    def check_old(self, container, name, fspath):
        """Helper to check an existing object."""
        entry = self.metadata.getentry(fspath)
        if not entry:
            self.conflict(fspath)
        if "conflict" in entry:
            self.conflict(fspath)
        flag = entry.get("flag")
        if flag == "removed":
            if os.path.exists(fspath):
                self.conflict(fspath)
        else:
            if not os.path.exists(fspath):
                self.conflict(fspath)
        obj = traverseName(container, name)
        adapter = get_adapter(obj)
        if IObjectDirectory.isImplementedBy(adapter):
            if flag != "removed" or os.path.exists(fspath):
                self.check_dir(obj, fspath)
        else:
            if flag == "added":
                self.conflict(fspath)
            oldfspath = fsutil.getoriginal(fspath)
            if not os.path.exists(oldfspath):
                self.conflict(fspath)
            else:
                olddata = read_file(oldfspath)
                curdata = adapter.getBody()
                if curdata != olddata:
                    self.conflict(fspath)

    def conflict(self, fspath):
        """Helper to report a conflict.

        Conflicts can be retrieved by calling errors().
        """
        if self.raise_on_conflicts:
            raise SynchronizationError(fspath)
        if fspath not in self.conflicts:
            self.conflicts.append(fspath)

class Committer(object):
    """Commit changes from the filesystem to the object database.

    The filesystem's originals must consistent with the object
    database; this should be checked beforehand by a Checker instance
    with the same arguments.

    The public API consists of __init__() and synch() only.
    """

    def __init__(self, metadata=None):
        """Constructor.  Optionally pass a metadata database."""
        if metadata is None:
            metadata = Metadata()
        self.metadata = metadata

    def synch(self, container, name, fspath):
        """Synchronize an object or object tree from the filesystem.

        SynchronizationError is raised for errors that can't be
        corrected by a update operation, including invalid object
        names.
        """

        if (os.sep in name or
            (os.altsep and os.altsep in name) or
            name == os.curdir or
            name == os.pardir or
            name == "." or
            name == ".." or
            "/" in name):
            # This name can't be mapped safely to the filesystem
            # or it is a magic value for traverseName (".", "..", "/")
            raise SynchronizationError("invalid separator in name %r" % name)

        if not name:
            self.synch_dir(container, fspath)
        else:
            try:
                traverseName(container, name)
            except:
                self.synch_new(container, name, fspath)
            else:
                self.synch_old(container, name, fspath)

            # Now update extra and annotations
            try:
                obj = traverseName(container, name)
            except:
                pass
            else:
                adapter = get_adapter(obj)
                extra = adapter.extra()
                extrapath = fsutil.getextra(fspath)
                if extra is not None and os.path.exists(extrapath):
                    self.synch_dir(extra, extrapath)
                ann = adapter.annotations()
                annpath = fsutil.getannotations(fspath)
                if ann is not None and os.path.exists(annpath):
                    self.synch_dir(ann, annpath)

    def synch_dir(self, container, fspath):
        """Helper to synchronize a directory."""
        adapter = get_adapter(container)
        nameset = {}
        if IObjectDirectory.isImplementedBy(adapter):
            for name, obj in adapter.contents():
                nameset[name] = os.path.join(fspath, name)
        else:
            for name in container:
                nameset[name] = os.path.join(fspath, name)
        for name in self.metadata.getnames(fspath):
            nameset[name] = os.path.join(fspath, name)
        # Sort the list of keys for repeatability
        names_paths = nameset.items()
        names_paths.sort()
        subdirs = []
        # Do the non-directories first
        for name, path in names_paths:
            if os.path.isdir(path):
                subdirs.append((name, path))
            else:
                self.synch(container, name, path)
        # Now do the directories
        for name, path in subdirs:
            self.synch(container, name, path)

    def synch_new(self, container, name, fspath):
        """Helper to synchronize a new object."""
        entry = self.metadata.getentry(fspath)
        if entry:
            create_object(container, name, entry, fspath)
            obj = traverseName(container, name)
            adapter = get_adapter(obj)
            if IObjectDirectory.isImplementedBy(adapter):
                self.synch_dir(obj, fspath)

    def synch_old(self, container, name, fspath):
        """Helper to synchronize an existing object."""
        entry = self.metadata.getentry(fspath)
        if entry.get("flag") == "removed":
            delete_item(container, name)
            return
        if not entry:
            # This object was not included on the filesystem; skip it
            return
        obj = traverseName(container, name)
        adapter = get_adapter(obj)
        if IObjectDirectory.isImplementedBy(adapter):
            self.synch_dir(obj, fspath)
        else:
            if adapter.typeIdentifier() != entry.get("type"):
                create_object(container, name, entry, fspath, replace=True)
            else:
                olddata = read_file(fsutil.getoriginal(fspath))
                newdata = read_file(fspath)
                if newdata != olddata:
                    if not entry.get("factory"):
                        # If there's no factory, we can't call setBody()
                        create_object(container, name, entry, fspath, True)
                        obj = traverseName(container, name)
                    else:
                        adapter.setBody(newdata)
                    # Now publish an event, but not for annotations or
                    # extras.  To know which case we have, see if
                    # getName() works.  XXX This is a hack.
                    try:
                        getName(obj)
                    except:
                        pass
                    else:
                        publish(obj, ObjectModifiedEvent(obj))

# Functions below this point are all helpers and not part of the
# API offered by this module.  They can be functions because they
# don't use the metadata database or add to the list of conflicts.

def create_object(container, name, entry, fspath, replace=False):
    """Helper to create an item in a container or mapping."""
    factory_name = entry.get("factory")
    if factory_name:
        # A given factory overrides everything
        factory = resolve(factory_name)
        obj = factory()
        obj = ContextWrapper(obj, container, name=name)
        adapter = get_adapter(obj)
        if IObjectFile.isImplementedBy(adapter):
            data = read_file(fspath)
            adapter.setBody(data)
    else:
        # No factory; try using IFileFactory or IDirectoryFactory
        as = getService(container, "Adapters")
        isuffix = name.rfind(".")
        if isuffix >= 0:
            suffix = name[isuffix:]
        else:
            suffix = "."

        if os.path.isdir(fspath):
            iface = IDirectoryFactory
        else:
            iface = IFileFactory

        factory = as.queryNamedAdapter(container, iface, suffix)
        if factory is None:
            factory = as.queryAdapter(container, iface)

        if iface is IDirectoryFactory:
            if factory:
                obj = factory(name)
                obj = removeAllProxies(obj)
            else:
                raise SynchronizationError(
                    "don't know how to create a directory",
                    container,
                    name)
        else:
            if factory:
                data = read_file(fspath)
                obj = factory(name, None, data)
                obj = removeAllProxies(obj)
            else:
                # Oh well, assume the file is an xml pickle
                obj = load_file(fspath)

    set_item(container, name, obj, replace)

def set_item(container, name, obj, replace=False):
    """Helper to set an item in a container or mapping."""
    if IContainer.isImplementedBy(container):
        if not replace:
            publish(container, ObjectCreatedEvent(obj))
        container = getAdapter(container, IZopeContainer)
        if replace:
            del container[name]
        newname = container.setObject(name, obj)
        if newname != name:
            raise SynchronizationError(
                "Container generated new name for %s (new name %s)" %
                (name, newname))
    else:
        # Not a container, must be a mapping
        # (This is used for extras and annotations)
        container[name] = obj

def delete_item(container, name):
    """Helper to delete an item from a container or mapping."""
    if IContainer.isImplementedBy(container):
        container = getAdapter(container, IZopeContainer)
    del container[name]

def load_file(fspath):
    """Helper to load an xml pickle from a file."""
    return loads(read_file(fspath, "r"))

def read_file(fspath, mode="rb"):
    """Helper to read the data from a file."""
    assert mode in ("r", "rb")
    f = open(fspath, mode)
    try:
        data = f.read()
    finally:
        f.close()
    return data

def get_adapter(obj):
    """Helper to get the special fssync adapter."""
    syncService = getService(obj, 'FSRegistryService')
    return syncService.getSynchronizer(obj)


=== Zope3/src/zope/app/fssync/classes.py 1.4 => 1.4.2.1 ===
--- Zope3/src/zope/app/fssync/classes.py:1.4	Thu May 15 12:19:04 2003
+++ Zope3/src/zope/app/fssync/classes.py	Sun Jun 22 10:23:03 2003
@@ -18,38 +18,19 @@
 
 import os
 
-from zope.app.content.file import File
-from zope.app.content.folder import Folder
-from zope.app.interfaces.fssync import IFSAddView, IObjectFile
+from zope.app.interfaces.fssync import IObjectFile
+from zope.app.interfaces.annotation import IAnnotations
+from zope.component import queryAdapter
 from zope.component.interfaces import IPresentationRequest
 from zope.xmlpickle import dumps
-from zope.proxy.introspection import removeAllProxies
-
-class FSAddView(object):
-    """See IFSAddView."""
-
-    __implements__ = IFSAddView
-
-    def __init__(self, context, request):
-        self.context = context
-        self.request = request
-
-class AddView(FSAddView):
-    """Supports to create a file system representation of zope
-       file type objects
-    """
-
-    def create(self, fs_path=None):
-        if os.path.isdir(fs_path):
-            return Folder()
-        else:
-            return File()
+from zope.proxy import removeAllProxies
+from zope.interface import implements
 
 class AttrMapping(object):
     """Convenience object implementing a mapping on selected object attributes
     """
 
-    def __init__(self, context, attrs, schema=None):
+    def __init__(self, context, attrs):
         self.attrs = attrs
         self.context = context
 
@@ -88,16 +69,20 @@
         self.context = context
 
     def extra(self):
-        "See Zope.App.FSSync.IObjectEntry.IObjectEntry"
+        "See IObjectEntry"
         return None
 
+    def annotations(self):
+        "See IObjectEntry"
+        return queryAdapter(self.context, IAnnotations)
+
     def typeIdentifier(self):
-        "See Zope.App.FSSync.IObjectEntry.IObjectEntry"
+        "See IObjectEntry"
         class_ = self.context.__class__
         return "%s.%s" % (class_.__module__, class_.__name__)
 
     def factory(self):
-        "See Zope.App.FSSync.IObjectEntry.IObjectEntry"
+        "See IObjectEntry"
         # Return the dotted class name, assuming that it can be used
         class_ = self.context.__class__
         return "%s.%s" % (class_.__module__, class_.__name__)
@@ -105,7 +90,7 @@
 class Default(ObjectEntryAdapter):
     """Default File-system representation for objects."""
 
-    __implements__ =  IObjectFile
+    implements(IObjectFile)
 
     def __init__(self, context):
         # XXX for now, remove all proxies.
@@ -118,20 +103,14 @@
         return dumps(self.context)
 
     def setBody(self, body):
-        pass
+        "See IObjectFile"
+        raise NotImplementedError
 
     def factory(self):
         "See IObjectEntry"
         # We have no factory, cause we're a pickle.
         return None
 
-class FSAddRequest(object):
-    """XXX docstring???"""
-
-    __implements__ = IPresentationRequest
-
-    def getPresentationType(self):
-        return IFSAddView
-
-    def getPresentationSkin(self):
-        return 'default'
+    def annotations(self):
+        # The annotations are already stored in the pickle.
+        return None


=== Zope3/src/zope/app/fssync/configure.zcml 1.2 => 1.2.4.1 ===
--- Zope3/src/zope/app/fssync/configure.zcml:1.2	Mon May  5 14:01:01 2003
+++ Zope3/src/zope/app/fssync/configure.zcml	Sun Jun 22 10:23:03 2003
@@ -10,11 +10,4 @@
     component="zope.app.fssync.fsregistry.fsRegistry"
     />
 
-  <view 
-    factory="zope.app.fssync.classes.AddView"
-    for="zope.app.interfaces.fssync.IContentDirectory"
-    type="zope.app.interfaces.fssync.IFSAddView"
-    name="."
-    />
-
 </zopeConfigure>


=== Zope3/src/zope/app/fssync/fsregistry.py 1.3 => 1.3.2.1 ===
--- Zope3/src/zope/app/fssync/fsregistry.py:1.3	Thu May 15 14:45:33 2003
+++ Zope3/src/zope/app/fssync/fsregistry.py	Sun Jun 22 10:23:03 2003
@@ -20,6 +20,7 @@
 
 from zope.app.interfaces.fssync import IGlobalFSSyncService
 from zope.exceptions import DuplicationError, NotFoundError
+from zope.interface import implements
 
 class FSRegistry(object):
     """Registry Wrapper class.
@@ -27,7 +28,7 @@
     This is a maping from Class -> Serializer Factory Method.
     """
 
-    __implements__ = IGlobalFSSyncService
+    implements(IGlobalFSSyncService)
 
     def __init__(self):
         self._class_factory_reg = {}


=== Zope3/src/zope/app/fssync/syncer.py 1.19 => 1.19.2.1 ===
--- Zope3/src/zope/app/fssync/syncer.py:1.19	Wed May 21 16:29:45 2003
+++ Zope3/src/zope/app/fssync/syncer.py	Sun Jun 22 10:23:03 2003
@@ -23,34 +23,33 @@
 from zope.app.interfaces.fssync \
      import IObjectEntry, IObjectDirectory, IObjectFile
 
-from zope.app.interfaces.annotation import IAnnotations
 from zope.app.interfaces.container import IContainer
 from zope.configuration.name import resolve
 from zope.app.fssync.classes import Default
 from zope.app.traversing import getPath
 from zope.app.fssync.fsregistry import getSynchronizer
 from zope.app.interfaces.file import IFileFactory
-from zope.proxy.introspection import removeAllProxies
+from zope.proxy import removeAllProxies
 
-def readFile(path):
-    f = open(path)
+def readFile(path, mode="rb"):
+    f = open(path, mode)
     try:
         return f.read()
     finally:
         f.close()
 
-def writeFile(data, path):
-    f = open(path, "w")
+def writeFile(data, path, mode="wb"):
+    f = open(path, mode)
     try:
         f.write(data)
     finally:
         f.close()
 
 def loadFile(path):
-    return loads(readFile(path))
+    return loads(readFile(path, "r"))
 
 def dumpFile(obj, path):
-    writeFile(dumps(obj), path)
+    writeFile(dumps(obj), path, "w")
 
 def toFS(ob, name, location):
     """Check an object out to the file system
@@ -89,7 +88,7 @@
 
     try:
         objectPath = str(getPath(ob))
-    except TypeError:
+    except (TypeError, KeyError):
         objectPath = ''
     else:
         entries[name]['path'] = objectPath
@@ -111,7 +110,7 @@
             toFS(edata, ename, extra_dir)
 
     # Handle annotations
-    annotations = queryAdapter(ob, IAnnotations)
+    annotations = adapter.annotations()
     if annotations is not None:
         annotation_dir = os.path.join(admin_dir, 'Annotations')
         if not os.path.exists(annotation_dir):
@@ -133,219 +132,13 @@
     else:
         # Directory
         assert IObjectDirectory.isImplementedBy(adapter)
-        if os.path.exists(path):
-            dir_entries = os.path.join(path, '@@Zope', 'Entries.xml')
-            if os.path.exists(dir_entries):
-                dumpFile({}, dir_entries)
-        else:
+        if not os.path.exists(path):
             os.mkdir(path)
+        admin_dir = os.path.join(path, '@@Zope')
+        if not os.path.exists(admin_dir):
+            os.mkdir(admin_dir)
+        dir_entries = os.path.join(admin_dir, 'Entries.xml')
+        dumpFile({}, dir_entries)
 
         for cname, cob in adapter.contents():
             toFS(cob, cname, path)
-
-
-class SynchronizationError(Exception):
-    pass
-
-
-def _setItem(container, name, ob, old=False):
-    # Set an item in a container or in a mapping
-    if IContainer.isImplementedBy(container):
-        if old:
-            del container[name]
-        newName = container.setObject(name, ob)
-        if newName != name:
-            raise SynchronizationError(
-                "Container generated new name for %s (new name %s)" %
-                (name, newName))
-    else:
-        # Not a container, must be a mapping
-        container[name] = ob
-
-
-def _create(container, name, factory, path, old=False):
-    # Create an item in a container or in a mapping
-    if factory:
-        # A given factory overrides everything
-        newOb = resolve(factory)()
-    else:
-        # No factory; try using the newfangled IFileFactory feature
-        as = getService(container, "Adapters")
-        isuffix = name.rfind(".")
-        if isuffix >= 0:
-            suffix = name[isuffix:]
-        else:
-            suffix = "."
-            
-        factory = as.queryNamedAdapter(container, IFileFactory, suffix)
-        if factory is None:
-            factory = as.queryAdapter(container, IFileFactory)
-
-        if factory:
-            newOb = factory(name, None, readFile(path))
-            newOb = removeAllProxies(newOb)
-        else:
-            # Oh well, do it the oldfashioned way
-            newOb = loadFile(path)
-
-    _setItem(container, name, newOb, old)
-
-    return newOb
-
-
-def fromFS(container, name, location):
-    """Synchromize a file from what's on the file system.
-
-    container -- parent of new object
-
-    name -- name of new object in container
-
-    location -- filesystem directory containing name
-    """
-    if not name:
-        # Special case: loading the root folder.
-        # Don't make changes to the root, but change everything underneath.
-        path = os.path.join(location, "root")
-        if not os.path.isdir(path):
-            raise SynchronizationError("root folder not found")
-
-        dir_entries_path = os.path.join(path, '@@Zope', 'Entries.xml')
-        if os.path.exists(dir_entries_path):
-            dir_entries = loadFile(dir_entries_path)
-        else:
-            dir_entries = {}
-        for cname in dir_entries:
-            fromFS(container, cname, path)
-
-        return
-
-    # Look for location admin dir
-    admin_dir = os.path.join(location, '@@Zope')
-    if not os.path.exists(admin_dir):
-        raise SynchronizationError("No @@Zope admin directory, %s" % admin_dir)
-
-    # Open Entries file
-    entries_path = os.path.join(admin_dir, "Entries.xml")
-    entries = loadFile(entries_path)
-    entry = entries[name]
-    factory = entry.get('factory')
-
-    # Get name path and check that name is not an absolute path
-    path = os.path.join(location, name)
-    if path == name:
-        raise ValueError("Invalid absolute path name")
-
-    # See if this is an existing object
-    if name not in container:
-        # Not there; we need to create a new object
-        assert entry.get("flag") == "added", name
-        newOb = _create(container, name, factory, path)
-
-    else:
-        # It's there; let's see if we need to delete it
-        if entry.get("flag") == "removed":
-            del container[name]
-            return # That was easy!
-
-        # No, updating.  Let's see if we have the same kind of object
-
-        # Get the object adapter
-        ob = container[name]
-        syncService = getService(ob, 'FSRegistryService')
-        adapter = syncService.getSynchronizer(ob)
-
-        # Replace the object if the type is different
-        if adapter.typeIdentifier() != entry.get('type'):
-            # We have a different object, replace the one that's there
-
-            newOb = _create(container, name, factory, path, old=True)
-
-        elif not factory:
-            if entry.get('type') == '__builtin__.str':
-                newOb = readFile(path)
-                _setItem(container, name, newOb, old=True)
-            else:
-                # Special case pickle data
-                oldOb = container[name]
-                oldOb = removeAllProxies(oldOb)
-                newOb = loadFile(path)
-                try:
-                    # See if we can and should just copy the state
-                    oldOb._p_oid # Is it persistent?
-                    getstate = newOb.__getstate__
-                except AttributeError:
-                    # Nope, we have to replace
-                    _setItem(container, name, newOb, old=True)
-                else:
-                    oldOb.__setstate__(getstate())
-                    oldOb._p_changed = True
-        # XXX else, what?
-
-    # Get the object adapter again
-    ob = container[name]
-    syncService = getService(ob, 'FSRegistryService')
-    adapter = syncService.getSynchronizer(ob)
-
-    # Handle extra
-    extra = adapter.extra()
-    extra_dir = os.path.join(admin_dir, 'Extra', name)
-    extra_entries_path = os.path.join(extra_dir, "@@Zope", "Entries.xml")
-    if extra:
-        if not os.path.exists(extra_entries_path):
-            if entry.get("flag") != "added":
-                # The file system has no extras, so delete all of the
-                # object's extras.
-                for key in list(extra):
-                    del extra[key]
-        else:
-            extra_entries = loadFile(extra_entries_path)
-            for ename in extra_entries:
-                fromFS(extra, ename, extra_dir)
-    elif os.path.exists(extra_entries_path):
-        extra_entries = loadFile(extra_entries_path)
-        if extra_entries:
-            raise SynchronizationError(
-                "File-system extras for object with no extra data")
-
-    # Handle annotations
-    annotations = queryAdapter(ob, IAnnotations)
-    annotation_dir = os.path.join(admin_dir, 'Annotations', name)
-    annotation_entries_path = os.path.join(
-        annotation_dir, "@@Zope", "Entries.xml")
-    if annotations is not None:
-        if not os.path.exists(annotation_entries_path):
-            if entry.get("flag") != "added":
-                # The file system has no annotations, so delete all of
-                # the object's annotations.
-                for key in list(annotations):
-                    del annotations[key]
-        else:
-            annotation_entries = loadFile(annotation_entries_path)
-            for ename in annotation_entries:
-                fromFS(annotations, ename, annotation_dir)
-    elif os.path.exists(annotation_entries_path):
-        annotation_entries = loadFile(annotation_entries_path)
-        if annotation_entries:
-            raise SynchronizationError(
-                "File-system annotations for non annotatable object")
-
-    # Handle data
-    if IObjectFile.isImplementedBy(adapter):
-        # File
-        if os.path.isdir(path):
-            raise SynchronizationError("Object is file, but data is directory")
-        adapter.setBody(readFile(path))
-
-    else:
-        # Directory
-        assert IObjectDirectory.isImplementedBy(adapter)
-        if not os.path.isdir(path):
-            raise SynchronizationError("Object is directory, but data is file")
-
-        dir_entries_path = os.path.join(path, '@@Zope', 'Entries.xml')
-        if os.path.exists(dir_entries_path):
-            dir_entries = loadFile(dir_entries_path)
-        else:
-            dir_entries = {}
-        for cname in dir_entries:
-            fromFS(ob, cname, path)