                             for x in output.stdout.split('\n')
                                 v = misc.split(x)
                                 if v.length == 2
-                                    if opts.delete
-                                        local_files[v[1]] = true
-                                    if db_files[v[1]] != parseInt(v[0])   # true if diff size or not there
-                                        to_copy.push(v[1])
+                                    local_files[v[1]] = parseInt(v[0])
                             cb()
-            (cb) =>
-                if to_copy.length == 0
+        ], (err) =>
+            if err
+                opts.cb(err)
+            else
+                local_only_files = (name for name, size of local_files when db_files[name] != size)
+                db_only_files    = (name for name, size of db_files when local_files[name] != size)
+                opts.cb(undefined, {local_only:local_only_files, db_only:db_only_files})
+        )
+
+
+    # Copy any files in path not in database *to* the database.
+    sync_put: (opts) =>
+        opts = defaults opts,
+            path   : required
+            delete : false          # if true, deletes anything in the database not in the path
+            cb     : undefined
+        dbg = (m) => @dbg('sync_put', opts.path, m)
+        diff = undefined
+        copied = {}
+        async.series([
+            (cb) =>
+                @sync_diff
+                    path : opts.path
+                    cb   : (err, x) =>
+                        diff = x
+                        cb(err)
+            (cb) =>
+                if diff.local_only.length == 0
                     cb(); return
-                dbg("copy all new files to database")
+                dbg("copy all new local files to database")
                 f = (name, c) =>
+                    copied[name] = true
                     @put
                         name     : name
                         filename : opts.path + '/'+name
                         cb       : c
-                async.mapLimit(to_copy, 5, f, cb)  # up to 5 files at once
+                async.mapLimit(diff.local_only, 3, f, cb)  # up to 3 files at once
 
             (cb) =>
                 if opts.delete
-                    to_delete = (name for name, size of db_files when not local_files[name])
+                    to_delete = (name for name in diff.db_only when not copied[name])
                     if to_delete.length == 0
                         cb(); return
                     dbg("delete #{to_delete.length} files in database not in local path")

                        else
                            if result.length > 0
                                chunk_ids = result[0][0]
                                dbg("chunk ids=#{misc.to_json(chunk_ids)}")
                            else
                                dbg("nothing there")

                            dbg("chunk ids=#{misc.to_json(chunk_ids)}")
                            cb()
            (cb) =>
                if not chunk_ids?  # 0-length file
                    cb(); return
                dbg("get chunks")
                f = (i, c) =>
                    t = misc.walltime()
