aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--actions/policy.go2
-rw-r--r--filesystem/filesystem.go37
-rw-r--r--filesystem/filesystem_test.go12
3 files changed, 40 insertions, 11 deletions
diff --git a/actions/policy.go b/actions/policy.go
index 41e108e..9d644c1 100644
--- a/actions/policy.go
+++ b/actions/policy.go
@@ -315,7 +315,7 @@ func (policy *Policy) AddProtector(protector *Protector) error {
// to it on the policy's filesystem.
if policy.Context.Mount != protector.Context.Mount {
log.Printf("policy on %s\n protector on %s\n", policy.Context.Mount, protector.Context.Mount)
- err := policy.Context.Mount.AddLinkedProtector(
+ _, err := policy.Context.Mount.AddLinkedProtector(
protector.Descriptor(), protector.Context.Mount)
if err != nil {
return err
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 9bae72b..e0ef110 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -393,24 +393,43 @@ func (m *Mount) AddProtector(data *metadata.ProtectorData) error {
}
// AddLinkedProtector adds a link in this filesystem to the protector metadata
-// in the dest filesystem.
-func (m *Mount) AddLinkedProtector(descriptor string, dest *Mount) error {
+// in the dest filesystem, if one doesn't already exist. On success, the return
+// value is a nil error and a bool that is true iff the link is newly created.
+func (m *Mount) AddLinkedProtector(descriptor string, dest *Mount) (bool, error) {
if err := m.CheckSetup(); err != nil {
- return err
+ return false, err
}
// Check that the link is good (descriptor exists, filesystem has UUID).
if _, err := dest.GetRegularProtector(descriptor); err != nil {
- return err
+ return false, err
+ }
+
+ linkPath := m.linkedProtectorPath(descriptor)
+
+ // Check whether the link already exists.
+ existingLink, err := ioutil.ReadFile(linkPath)
+ if err == nil {
+ existingLinkedMnt, err := getMountFromLink(string(existingLink))
+ if err != nil {
+ return false, err
+ }
+ if existingLinkedMnt != dest {
+ return false, errors.Wrapf(ErrFollowLink, "link %q points to %q, but expected %q",
+ linkPath, existingLinkedMnt.Path, dest.Path)
+ }
+ return false, nil
+ }
+ if !os.IsNotExist(err) {
+ return false, err
}
// Right now, we only make links using UUIDs.
- link, err := makeLink(dest, "UUID")
+ var newLink string
+ newLink, err = makeLink(dest, "UUID")
if err != nil {
- return dest.err(err)
+ return false, dest.err(err)
}
-
- path := m.linkedProtectorPath(descriptor)
- return m.err(m.writeDataAtomic(path, []byte(link)))
+ return true, m.err(m.writeDataAtomic(linkPath, []byte(newLink)))
}
// GetRegularProtector looks up the protector metadata by descriptor. This will
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index b85ead5..4bed96a 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -351,9 +351,19 @@ func TestLinkedProtector(t *testing.T) {
}
// Add the link to the second filesystem
- if err = fakeMnt.AddLinkedProtector(protector.ProtectorDescriptor, realMnt); err != nil {
+ var isNewLink bool
+ if isNewLink, err = fakeMnt.AddLinkedProtector(protector.ProtectorDescriptor, realMnt); err != nil {
t.Fatal(err)
}
+ if !isNewLink {
+ t.Fatal("Link was not new")
+ }
+ if isNewLink, err = fakeMnt.AddLinkedProtector(protector.ProtectorDescriptor, realMnt); err != nil {
+ t.Fatal(err)
+ }
+ if isNewLink {
+ t.Fatal("Link was new")
+ }
// Get the protector though the second system
_, err = fakeMnt.GetRegularProtector(protector.ProtectorDescriptor)