diff --git a/internal/fusefrontend_reverse/rpath.go b/internal/fusefrontend_reverse/rpath.go index edffc1e..af49776 100644 --- a/internal/fusefrontend_reverse/rpath.go +++ b/internal/fusefrontend_reverse/rpath.go @@ -44,46 +44,54 @@ func (rfs *ReverseFS) abs(relPath string, err error) (string, error) { return filepath.Join(rfs.args.Cipherdir, relPath), nil } +func (rfs *ReverseFS) rDecryptName(cName string, dirIV []byte, pDir string) (pName string, err error) { + nameType := nametransform.NameType(cName) + if nameType == nametransform.LongNameNone { + pName, err = rfs.nameTransform.DecryptName(cName, dirIV) + if err != nil { + // We get lots of decrypt requests for names like ".Trash" that + // are invalid base64. Convert them to ENOENT so the correct + // error gets returned to the user. + if _, ok := err.(base64.CorruptInputError); ok { + return "", syscall.ENOENT + } + // Stat attempts on the link target of encrypted symlinks. + // These are always valid base64 but the length is not a + // multiple of 16. + if err == syscall.EINVAL { + return "", syscall.ENOENT + } + return "", err + } + } else if nameType == nametransform.LongNameContent { + pName, err = rfs.findLongnameParent(pDir, dirIV, cName) + if err != nil { + return "", err + } + } else { + // It makes no sense to decrypt a ".name" file. This is a virtual file + // that has no represantation in the plaintext filesystem. ".name" + // files should have already been handled in virtualfile.go. + tlog.Warn.Printf("decryptPath: tried to decrypt %q!? Returning EINVAL.", cName) + return "", syscall.EINVAL + } + return pName, nil +} + func (rfs *ReverseFS) decryptPath(relPath string) (string, error) { if rfs.args.PlaintextNames || relPath == "" { return relPath, nil } - var err error - var transformedParts []string parts := strings.Split(relPath, "/") - for i, part := range parts { + var transformedParts []string + for i := range parts { // Start at the top and recurse currentCipherDir := filepath.Join(parts[:i]...) - nameType := nametransform.NameType(part) + currentPlainDir := filepath.Join(transformedParts[:i]...) dirIV := derivePathIV(currentCipherDir, ivPurposeDirIV) - var transformedPart string - if nameType == nametransform.LongNameNone { - transformedPart, err = rfs.nameTransform.DecryptName(part, dirIV) - if err != nil { - // We get lots of decrypt requests for names like ".Trash" that - // are invalid base64. Convert them to ENOENT so the correct - // error gets returned to the user. - if _, ok := err.(base64.CorruptInputError); ok { - return "", syscall.ENOENT - } - // Stat attempts on the link target of encrypted symlinks. - // These are always valid base64 but the length is not a - // multiple of 16. - if err == syscall.EINVAL { - return "", syscall.ENOENT - } - return "", err - } - } else if nameType == nametransform.LongNameContent { - currentPlainDir := filepath.Join(transformedParts[:i]...) - transformedPart, err = rfs.findLongnameParent(currentPlainDir, dirIV, part) - if err != nil { - return "", err - } - } else { - // It makes no sense to decrypt a ".name" file - tlog.Warn.Printf("decryptPath: tried to decrypt %q!? Returning EINVAL.", part) - return "", syscall.EINVAL + transformedPart, err := rfs.rDecryptName(parts[i], dirIV, currentPlainDir) + if err != nil { + return "", err } transformedParts = append(transformedParts, transformedPart) }