Exemple #1
0
// OpenDir - FUSE readdir call
func (rfs *ReverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
	relPath, err := rfs.decryptPath(cipherPath)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	// Read plaintext dir
	entries, status := rfs.loopbackfs.OpenDir(relPath, context)
	if entries == nil {
		return nil, status
	}
	if rfs.args.PlaintextNames {
		return rfs.openDirPlaintextnames(cipherPath, entries)
	}
	// Allocate maximum possible number of virtual files.
	// If all files have long names we need a virtual ".name" file for each,
	// plus one for gocryptfs.diriv.
	virtualFiles := make([]fuse.DirEntry, len(entries)+1)
	// Virtual gocryptfs.diriv file
	virtualFiles[0] = fuse.DirEntry{
		Mode: syscall.S_IFREG | 0400,
		Name: nametransform.DirIVFilename,
	}
	// Actually used entries
	nVirtual := 1

	// Encrypt names
	dirIV := derivePathIV(cipherPath, ivPurposeDirIV)
	for i := range entries {
		var cName string
		// ".gocryptfs.reverse.conf" in the root directory is mapped to "gocryptfs.conf"
		if cipherPath == "" && entries[i].Name == configfile.ConfReverseName {
			cName = configfile.ConfDefaultName
		} else {
			cName = rfs.nameTransform.EncryptName(entries[i].Name, dirIV)
			if len(cName) > syscall.NAME_MAX {
				cName = nametransform.HashLongName(cName)
				dotNameFile := fuse.DirEntry{
					Mode: syscall.S_IFREG | 0600,
					Name: cName + nametransform.LongNameSuffix,
				}
				virtualFiles[nVirtual] = dotNameFile
				nVirtual++
			}
		}
		entries[i].Name = cName
	}
	entries = append(entries, virtualFiles[:nVirtual]...)
	return entries, fuse.OK
}
// EncryptPath implements ctlsock.Backend.
// This is actually not used inside reverse mode, but we implement it because
// third-party tools want to encrypt paths through the control socket.
func (rfs *ReverseFS) EncryptPath(plainPath string) (string, error) {
	if rfs.args.PlaintextNames || plainPath == "" {
		return plainPath, nil
	}
	cipherPath := ""
	parts := strings.Split(plainPath, "/")
	for _, part := range parts {
		dirIV := derivePathIV(cipherPath, ivPurposeDirIV)
		encryptedPart := rfs.nameTransform.EncryptName(part, dirIV)
		if rfs.args.LongNames && len(encryptedPart) > syscall.NAME_MAX {
			encryptedPart = nametransform.HashLongName(encryptedPart)
		}
		cipherPath = filepath.Join(cipherPath, encryptedPart)
	}
	return cipherPath, nil
}
// findLongnameParent converts "gocryptfs.longname.XYZ" to the plaintext name
func (rfs *ReverseFS) findLongnameParent(dir string, dirIV []byte, longname string) (plaintextName string, err error) {
	longnameCacheLock.Lock()
	hit := longnameParentCache[longname]
	longnameCacheLock.Unlock()
	if hit != "" {
		return hit, nil
	}
	absDir := filepath.Join(rfs.args.Cipherdir, dir)
	dirfd, err := os.Open(absDir)
	if err != nil {
		tlog.Warn.Printf("findLongnameParent: opendir failed: %v\n", err)
		return "", err
	}
	dirEntries, err := dirfd.Readdirnames(-1)
	if err != nil {
		return "", err
	}
	longnameCacheLock.Lock()
	defer longnameCacheLock.Unlock()
	for _, plaintextName = range dirEntries {
		if len(plaintextName) <= shortNameMax {
			continue
		}
		cName := rfs.nameTransform.EncryptName(plaintextName, dirIV)
		if len(cName) <= syscall.NAME_MAX {
			log.Panic("logic error or wrong shortNameMax constant?")
		}
		hName := nametransform.HashLongName(cName)
		longnameParentCache[hName] = plaintextName
		if longname == hName {
			hit = plaintextName
		}
	}
	if hit == "" {
		return "", syscall.ENOENT
	}

	return hit, nil
}