diff --git a/model/sharing/shared.go b/model/sharing/shared.go index 439941c6d6c..719b0ee1693 100644 --- a/model/sharing/shared.go +++ b/model/sharing/shared.go @@ -552,6 +552,38 @@ func extractDocReferenceFromID(id string) *couchdb.DocReference { return &ref } +func (s *Sharing) fixMissingShared(inst *instance.Instance, fileDoc *vfs.FileDoc) (SharedRef, error) { + var ref SharedRef + ref.SID = consts.Files + "/" + fileDoc.ID() + ref.Revisions = &RevsTree{Rev: fileDoc.Rev()} + + rule, ruleIndex := s.findRuleForNewFile(fileDoc) + if rule == nil { + return ref, ErrSafety + } + + sharingDir, err := s.GetSharingDir(inst) + if err != nil { + return ref, err + } + fs := inst.VFS() + pth, err := fileDoc.Path(fs) + if err != nil || !strings.HasPrefix(pth, sharingDir.Fullpath+"/") { + return ref, ErrSafety + } + + ref.Infos = map[string]SharedInfo{ + s.SID: { + Rule: ruleIndex, + Binary: true, + Removed: false, + }, + } + + err = couchdb.CreateNamedDoc(inst, &ref) + return ref, err +} + // CheckShared will scan all the io.cozy.shared documents and check their // revision tree for inconsistencies. func CheckShared(inst *instance.Instance) ([]*CheckSharedError, error) { diff --git a/model/sharing/upload.go b/model/sharing/upload.go index b5399104fcc..3077f37096d 100644 --- a/model/sharing/upload.go +++ b/model/sharing/upload.go @@ -247,7 +247,7 @@ func (b *batchUpload) findNextFileToUpload() (map[string]interface{}, int, error if len(results) == 0 { b.Instance.Logger().WithNamespace("upload"). Warnf("missing results for bulk get %v", query) - return nil, 0, ErrInternalServerError + continue } if results[0]["_deleted"] == true { b.Instance.Logger().WithNamespace("upload"). @@ -472,10 +472,19 @@ func (s *Sharing) SyncFile(inst *instance.Instance, target *FileDocWithRevisions err = couchdb.GetDoc(inst, consts.Shared, sid, &ref) if err != nil { - if couchdb.IsNotFoundError(err) { + if !couchdb.IsNotFoundError(err) { + return nil, err + } + // XXX It happens that the job for creating the io.cozy.shared has + // been lost (stack restart for example), and we need to do + // something to avoid having the sharing stuck. The most efficient + // way to do that is to check that the file is actually in the + // sharing directory, and if it is the case, to create the missing + // io.cozy.shared. + ref, err = s.fixMissingShared(inst, current) + if err != nil { return nil, ErrSafety } - return nil, err } if infos, ok := ref.Infos[s.SID]; !ok || (infos.Removed && !infos.Dissociated) { return nil, ErrSafety diff --git a/tests/system/lib/couch.rb b/tests/system/lib/couch.rb index bae05e78bdd..e13a0ee9f90 100644 --- a/tests/system/lib/couch.rb +++ b/tests/system/lib/couch.rb @@ -49,7 +49,7 @@ def update_doc(domain, doctype, doc) opts = { content_type: "application/json" } - id = doc["_id"] + id = doc["_id"].gsub("/", "%2F") doctype = doctype.gsub(/\W/, '-') @client["/#{prefix domain}%2F#{doctype}/#{id}"].put(doc.to_json, opts) end diff --git a/tests/system/tests/multiple_sharings.rb b/tests/system/tests/multiple_sharings.rb index e8b998d921f..2f8bd6f9770 100644 --- a/tests/system/tests/multiple_sharings.rb +++ b/tests/system/tests/multiple_sharings.rb @@ -95,6 +95,13 @@ child1_charlie = Folder.find inst_charlie, child1_charlie_id assert_equal child1_charlie.name, child1_bob.name + # Check that the stack is not stuck when an io.cozy.shared has not been created + shared_bob = Helpers.couch.get_doc inst_bob.domain, "io.cozy.shared", "io.cozy.files%2f#{file_bob.couch_id}" + shared_bob["_deleted"] = true + Helpers.couch.update_doc inst_bob.domain, "io.cozy.shared", shared_bob + file.overwrite inst_alice + sleep 12 + # Check that the files are the same on disk da = File.join Helpers.current_dir, inst_alice.domain, folder.name db = File.join Helpers.current_dir, inst_bob.domain,