@@ -2,8 +2,7 @@ use crate::crypto::block::BlockLayout;
22use crate :: crypto:: cipher:: Cipher ;
33use crate :: crypto:: file:: { FileDecoder , FileEncoder } ;
44use crate :: crypto:: file_iv:: FileIv ;
5- use base64:: Engine ;
6- use base64:: engine:: general_purpose:: STANDARD_NO_PAD ;
5+ use crate :: xattr_name;
76use libc;
87use log:: { debug, error, warn} ;
98use std:: borrow:: Cow ;
@@ -1583,10 +1582,9 @@ impl EncFs {
15831582 libc:: EIO
15841583 } ) ?;
15851584
1586- // Store with "user.encfs." prefix + base64-encoded encrypted name
1587- // Use base64 encoding for the encrypted name to make it filesystem-safe
1588- let encoded_name = STANDARD_NO_PAD . encode ( & encrypted_name) ;
1589- let final_name = format ! ( "user.encfs.{}" , encoded_name) ;
1585+ // Store under the "user.encfs." prefix, with the encrypted name
1586+ // base64-encoded so it is a legal attribute name everywhere.
1587+ let final_name = xattr_name:: encode ( & encrypted_name) ;
15901588
15911589 let c_name = std:: ffi:: CString :: new ( final_name) . map_err ( |_| libc:: EINVAL ) ?;
15921590 let c_path = c_path ( & real_path) . map_err ( |e| e. raw ( ) ) ?;
@@ -1615,16 +1613,24 @@ impl EncFs {
16151613 } ) ?;
16161614
16171615 // Encode encrypted name for storage lookup
1618- let encoded_name = STANDARD_NO_PAD . encode ( & encrypted_name) ;
1619- let lookup_name = format ! ( "user.encfs.{}" , encoded_name) ;
1616+ let lookup_name = xattr_name:: encode ( & encrypted_name) ;
16201617
16211618 let c_name = std:: ffi:: CString :: new ( lookup_name) . map_err ( |_| libc:: EINVAL ) ?;
16221619 let c_path = c_path ( & real_path) . map_err ( |e| e. raw ( ) ) ?;
16231620
16241621 // Read the on-disk (encrypted) value; the caller's size limit is
16251622 // applied by the trait wrapper against the decrypted length.
1626- let encrypted_value =
1627- passthrough:: getxattr_value_nofollow ( & c_path, & c_name) . map_err ( |e| e. raw ( ) ) ?;
1623+ let encrypted_value = match passthrough:: getxattr_value_nofollow ( & c_path, & c_name) {
1624+ Ok ( value) => value,
1625+ // An attribute written before the alphabet change carries the
1626+ // older spelling; try that before reporting it missing.
1627+ Err ( e) if e == Errno :: ENOATTR => {
1628+ let legacy = xattr_name:: encode_legacy ( & encrypted_name) ;
1629+ let c_legacy = std:: ffi:: CString :: new ( legacy) . map_err ( |_| libc:: EINVAL ) ?;
1630+ passthrough:: getxattr_value_nofollow ( & c_path, & c_legacy) . map_err ( |e| e. raw ( ) ) ?
1631+ }
1632+ Err ( e) => return Err ( e. raw ( ) ) ,
1633+ } ;
16281634
16291635 // Decrypt value
16301636 let decrypted_value = self
@@ -1658,11 +1664,11 @@ impl EncFs {
16581664 Err ( _) => continue , // Invalid UTF-8, skip
16591665 } ;
16601666
1661- if let Some ( encoded_part) = name_str. strip_prefix ( "user.encfs." ) {
1667+ if let Some ( encoded_part) = name_str. strip_prefix ( xattr_name :: PREFIX ) {
16621668 // This is an encrypted encfs attribute stored on disk
16631669 // Extract the base64-encoded encrypted name
1664- match STANDARD_NO_PAD . decode ( encoded_part) {
1665- Ok ( encrypted_name_bytes) => {
1670+ match xattr_name :: decode ( encoded_part) {
1671+ Some ( encrypted_name_bytes) => {
16661672 match self
16671673 . cipher
16681674 . decrypt_xattr_name ( & encrypted_name_bytes, path_iv)
@@ -1678,7 +1684,7 @@ impl EncFs {
16781684 }
16791685 }
16801686 }
1681- Err ( _ ) => {
1687+ None => {
16821688 warn ! ( "Failed to decode base64 xattr name: {}" , name_str) ;
16831689 // Skip this name but continue
16841690 }
@@ -1715,14 +1721,21 @@ impl EncFs {
17151721 } ) ?;
17161722
17171723 // Encode encrypted name for storage lookup
1718- let encoded_name = STANDARD_NO_PAD . encode ( & encrypted_name) ;
1719- let lookup_name = format ! ( "user.encfs.{}" , encoded_name) ;
1724+ let lookup_name = xattr_name:: encode ( & encrypted_name) ;
17201725
17211726 let c_name = std:: ffi:: CString :: new ( lookup_name) . map_err ( |_| libc:: EINVAL ) ?;
17221727 let c_path = c_path ( & real_path) . map_err ( |e| e. raw ( ) ) ?;
17231728
1724- // Remove xattr from underlying filesystem
1725- passthrough:: removexattr_nofollow ( & c_path, & c_name) . map_err ( |e| e. raw ( ) )
1729+ // Remove xattr from underlying filesystem, falling back to the older
1730+ // spelling for attributes written before the alphabet change.
1731+ match passthrough:: removexattr_nofollow ( & c_path, & c_name) {
1732+ Err ( e) if e == Errno :: ENOATTR => {
1733+ let legacy = xattr_name:: encode_legacy ( & encrypted_name) ;
1734+ let c_legacy = std:: ffi:: CString :: new ( legacy) . map_err ( |_| libc:: EINVAL ) ?;
1735+ passthrough:: removexattr_nofollow ( & c_path, & c_legacy) . map_err ( |e| e. raw ( ) )
1736+ }
1737+ other => other. map_err ( |e| e. raw ( ) ) ,
1738+ }
17261739 }
17271740}
17281741
0 commit comments