aboutsummaryrefslogtreecommitdiff
path: root/filesystem/filesystem.go
diff options
context:
space:
mode:
authorJoe Richey joerichey@google.com <joerichey@google.com>2017-05-31 17:52:15 -0700
committerJoe Richey joerichey@google.com <joerichey@google.com>2017-06-15 22:32:35 -0700
commit67879f7a69e2040f2266d81ba239324534e24405 (patch)
tree7b2a6725daec02f4868fa8c835ba18acd913a160 /filesystem/filesystem.go
parentd4160e07cfc1942844160fdb8e6c9525da0bd2c8 (diff)
filesystem: change support detection and bug-fixes
Instead of checking if the filesystem type is correct, we now detect if a filesystem supports encryption by trying to read a policy on its root directory. The error returned tells us if there is support or not. This commit also fixes a bug in the use libblkid. Throughout all of fscrypt, cannonicalizePath() is used before any path comparison or lookup. However, the canonical device path in the blkid cache may differ from our idea of a canonical path. Additional blkid functions are needed to perform the necessary translation. This is noted in the documentation of makeLink(). Finally, this commit makes a few API changes. AllSupporedFilesystems() now returns an error, and a GetProtector() method now replaces the GetLinkedProtector() and GetEitherProtector() methods. A PathSorter has also been added so Mounts can be sorted in a reliable order. Change-Id: I664f46fafd1483ebecb743c061b03d708b3233a4
Diffstat (limited to 'filesystem/filesystem.go')
-rw-r--r--filesystem/filesystem.go120
1 files changed, 73 insertions, 47 deletions
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 649345f..434826b 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -110,6 +110,13 @@ type Mount struct {
Device string
}
+// PathSorter allows mounts to be sorted by Path.
+type PathSorter []*Mount
+
+func (p PathSorter) Len() int { return len(p) }
+func (p PathSorter) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p PathSorter) Less(i, j int) bool { return p[i].Path < p[j].Path }
+
const (
// Names of the various directories used in fscrypt
baseDirName = ".fscrypt"
@@ -128,6 +135,13 @@ const (
filePermissions = 0644
)
+func (m *Mount) String() string {
+ return fmt.Sprintf(`%s
+ Filsystem: %s
+ Options: %v
+ Device: %s`, m.Path, m.Filesystem, m.Options, m.Device)
+}
+
// baseDir returns the path of the base fscrypt directory on this filesystem.
func (m *Mount) baseDir() string {
return filepath.Join(m.Path, baseDirName)
@@ -183,15 +197,18 @@ func (m *Mount) err(err error) error {
}
}
-// IsSetup returns true if all the fscrypt metadata directories exist. Will log
-// any unexpected errors, or if any permissions are incorrect.
-func (m *Mount) IsSetup() bool {
+// CheckSetup returns an error if all the fscrypt metadata directories exist.
+// Will log any unexpected errors, or if any permissions are incorrect.
+func (m *Mount) CheckSetup() error {
// Run all the checks so we will always get all the warnings
baseGood := isDirCheckPerm(m.baseDir(), basePermissions)
policyGood := isDirCheckPerm(m.policyDir(), dirPermissions)
protectorGood := isDirCheckPerm(m.protectorDir(), dirPermissions)
- return baseGood && policyGood && protectorGood
+ if baseGood && policyGood && protectorGood {
+ return nil
+ }
+ return m.err(ErrNotSetup)
}
// makeDirectories creates the three metadata directories with the correct
@@ -217,10 +234,9 @@ func (m *Mount) makeDirectories() error {
// the filesystem's feature flags. This operation is atomic, it either succeeds
// or no files in the baseDir are created.
func (m *Mount) Setup() error {
- if m.IsSetup() {
+ if m.CheckSetup() == nil {
return m.err(ErrAlreadySetup)
}
-
// We build the directories under a temp Mount and then move into place.
temp, err := m.tempMount()
if err != nil {
@@ -247,10 +263,9 @@ func (m *Mount) Setup() error {
// WARNING: Will cause data loss if the metadata is used to encrypt
// directories (this could include directories on other filesystems).
func (m *Mount) RemoveAllMetadata() error {
- if !m.IsSetup() {
- return m.err(ErrNotSetup)
+ if err := m.CheckSetup(); err != nil {
+ return err
}
-
// temp will hold the old metadata temporarily
temp, err := m.tempMount()
if err != nil {
@@ -267,32 +282,28 @@ func (m *Mount) RemoveAllMetadata() error {
func (m *Mount) writeDataAtomic(path string, data []byte) error {
// Write the file to a temporary file then move into place so that the
// operation will be atomic.
- tmpFile, err := ioutil.TempFile(filepath.Dir(path), tempPrefix)
+ tempPath := filepath.Join(filepath.Dir(path), tempPrefix+filepath.Base(path))
+ // We use O_SYNC so the write actually gets to stable storage.
+ tempFile, err := os.OpenFile(tempPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, filePermissions)
if err != nil {
return err
}
- defer os.Remove(tmpFile.Name())
+ defer os.Remove(tempPath)
- // Make sure the write actually gets to stable storage.
- if _, err = tmpFile.Write(data); err != nil {
- return err
- }
- if err = tmpFile.Sync(); err != nil {
+ if _, err = tempFile.Write(data); err != nil {
+ tempFile.Close()
return err
}
- if err = tmpFile.Close(); err != nil {
+ if err = tempFile.Close(); err != nil {
return err
}
- return os.Rename(tmpFile.Name(), path)
+ return os.Rename(tempPath, path)
}
// addMetadata writes the metadata structure to the file with the specified
// path this will overwrite any existing data. The operation is atomic.
func (m *Mount) addMetadata(path string, md metadata.Metadata) error {
- if !m.IsSetup() {
- return ErrNotSetup
- }
if !md.IsValid() {
return ErrInvalidMetadata
}
@@ -309,10 +320,6 @@ func (m *Mount) addMetadata(path string, md metadata.Metadata) error {
// getMetadata reads the metadata structure from the file with the specified
// path. Only reads normal metadata files, not linked metadata.
func (m *Mount) getMetadata(path string, md metadata.Metadata) error {
- if !m.IsSetup() {
- return ErrNotSetup
- }
-
data, err := ioutil.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
@@ -354,6 +361,9 @@ func (m *Mount) removeMetadata(path string) error {
// will fail with ErrLinkedProtector if a linked protector with this descriptor
// already exists on the filesystem.
func (m *Mount) AddProtector(data *metadata.ProtectorData) error {
+ if err := m.CheckSetup(); err != nil {
+ return err
+ }
if isRegularFile(m.linkedProtectorPath(data.ProtectorDescriptor)) {
return m.err(ErrLinkedProtector)
}
@@ -364,6 +374,9 @@ 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 {
+ if err := m.CheckSetup(); err != nil {
+ return err
+ }
// Check that the link is good (descriptor exists, filesystem has UUID).
if _, err := dest.GetRegularProtector(descriptor); err != nil {
return err
@@ -382,19 +395,28 @@ func (m *Mount) AddLinkedProtector(descriptor string, dest *Mount) error {
// GetRegularProtector looks up the protector metadata by descriptor. This will
// fail with ErrNoMetadata if the descriptor is a linked protector.
func (m *Mount) GetRegularProtector(descriptor string) (*metadata.ProtectorData, error) {
+ if err := m.CheckSetup(); err != nil {
+ return nil, err
+ }
data := new(metadata.ProtectorData)
path := m.protectorPath(descriptor)
return data, m.err(m.getMetadata(path, data))
}
-// GetLinkedProtector returns the Mount of the filesystem containing the
-// information for a linked protector and that protector's data.
-func (m *Mount) GetLinkedProtector(descriptor string) (*Mount, *metadata.ProtectorData, error) {
+// GetProtector returns the Mount of the filesystem containing the information
+// and that protector's data. If the descriptor is a regular (not linked)
+// protector, the mount will return itself.
+func (m *Mount) GetProtector(descriptor string) (*Mount, *metadata.ProtectorData, error) {
+ if err := m.CheckSetup(); err != nil {
+ return nil, nil, err
+ }
// Get the link data from the link file
link, err := ioutil.ReadFile(m.linkedProtectorPath(descriptor))
if err != nil {
+ // If the link doesn't exist, try for a regular protector.
if os.IsNotExist(err) {
- err = ErrNoMetadata
+ data, err := m.GetRegularProtector(descriptor)
+ return m, data, err
}
return nil, nil, m.err(err)
}
@@ -414,19 +436,12 @@ func (m *Mount) GetLinkedProtector(descriptor string) (*Mount, *metadata.Protect
return nil, nil, m.err(ErrOldLink)
}
-// GetEitherProtector looks up the protector metadata by descriptor. It will
-// return the data for a linked protector or a regular protector.
-func (m *Mount) GetEitherProtector(descriptor string) (*metadata.ProtectorData, error) {
- if isRegularFile(m.linkedProtectorPath(descriptor)) {
- _, data, err := m.GetLinkedProtector(descriptor)
- return data, err
- }
- return m.GetRegularProtector(descriptor)
-}
-
// RemoveProtector deletes the protector metadata (or an link to another
// filesystem's metadata) from the filesystem storage.
func (m *Mount) RemoveProtector(descriptor string) error {
+ if err := m.CheckSetup(); err != nil {
+ return err
+ }
// We first try to remove the linkedProtector. If that metadata does not
// exist, we try to remove the normal protector.
err := m.removeMetadata(m.linkedProtectorPath(descriptor))
@@ -439,39 +454,51 @@ func (m *Mount) RemoveProtector(descriptor string) error {
// ListProtectors lists the descriptors of all protectors on this filesystem.
// This does not include linked protectors.
func (m *Mount) ListProtectors() ([]string, error) {
+ if err := m.CheckSetup(); err != nil {
+ return nil, err
+ }
protectors, err := m.listDirectory(m.protectorDir())
return protectors, m.err(err)
}
// AddPolicy adds the policy metadata to the filesystem storage.
func (m *Mount) AddPolicy(data *metadata.PolicyData) error {
+ if err := m.CheckSetup(); err != nil {
+ return err
+ }
+
return m.err(m.addMetadata(m.policyPath(data.KeyDescriptor), data))
}
// GetPolicy looks up the policy metadata by descriptor.
func (m *Mount) GetPolicy(descriptor string) (*metadata.PolicyData, error) {
+ if err := m.CheckSetup(); err != nil {
+ return nil, err
+ }
data := new(metadata.PolicyData)
return data, m.err(m.getMetadata(m.policyPath(descriptor), data))
}
// RemovePolicy deletes the policy metadata from the filesystem storage.
func (m *Mount) RemovePolicy(descriptor string) error {
+ if err := m.CheckSetup(); err != nil {
+ return err
+ }
return m.err(m.removeMetadata(m.policyPath(descriptor)))
}
// ListPolicies lists the descriptors of all policies on this filesystem.
func (m *Mount) ListPolicies() ([]string, error) {
+ if err := m.CheckSetup(); err != nil {
+ return nil, err
+ }
policies, err := m.listDirectory(m.policyDir())
return policies, m.err(err)
}
// listDirectory returns a list of descriptors for a metadata directory,
-// excluding files which are links to other filesystem's metadata.
+// including files which are links to other filesystem's metadata.
func (m *Mount) listDirectory(directoryPath string) ([]string, error) {
- if !m.IsSetup() {
- return nil, ErrNotSetup
- }
-
log.Printf("listing descriptors in %q", directoryPath)
dir, err := os.Open(directoryPath)
if err != nil {
@@ -486,9 +513,8 @@ func (m *Mount) listDirectory(directoryPath string) ([]string, error) {
var descriptors []string
for _, name := range names {
- if !strings.HasSuffix(name, linkFileExtension) {
- descriptors = append(descriptors, name)
- }
+ // Be sure to include links as well
+ descriptors = append(descriptors, strings.TrimSuffix(name, linkFileExtension))
}
log.Printf("found %d descriptor(s)", len(descriptors))