@@ -916,68 +916,77 @@ impl Filesystem for OverlayFs {
916916
917917 let st = node. stat64 ( req) . await ?;
918918 if utils:: is_dir ( & st. attr . kind ) {
919- // Special handling and security restrictions for directory operations
920- let handles = self . handles . lock ( ) . await ;
921- let handle_data = handles. get ( & fh) . ok_or_else ( || {
922- Error :: new ( ErrorKind :: InvalidInput , "Invalid directory handle" )
923- } ) ?;
924-
925- // Verify handle type and permissions
926- if let Some ( ref rh) = handle_data. real_handle {
927- // Verify that this handle is indeed a directory handle
928- let handle_stat = if let Ok ( stat) = rh. layer
929- . getattr ( req, rh. inode , Some ( rh. handle . load ( Ordering :: Relaxed ) ) , 0 )
930- . await
931- {
932- stat
933- } else {
934- return Err ( Error :: from_raw_os_error ( libc:: EBADF ) . into ( ) ) ;
935- } ;
919+ // Special handling and security restrictions for directory operations.
920+ // Use the common API to obtain the underlying layer and handle info.
921+ let ( layer, real_inode, real_handle) = self . find_real_info_from_handle ( fh) . await ?;
936922
937- if !utils:: is_dir ( & handle_stat. attr . kind ) {
938- return Err ( Error :: from_raw_os_error ( libc:: ENOTDIR ) . into ( ) ) ;
939- }
923+ // Verify that the underlying handle refers to a directory.
924+ let handle_stat = match layer
925+ . getattr ( req, real_inode, Some ( real_handle) , 0 )
926+ . await
927+ {
928+ Ok ( s) => s,
929+ Err ( _) => return Err ( Error :: from_raw_os_error ( libc:: EBADF ) . into ( ) ) ,
930+ } ;
931+
932+ if !utils:: is_dir ( & handle_stat. attr . kind ) {
933+ return Err ( Error :: from_raw_os_error ( libc:: ENOTDIR ) . into ( ) ) ;
934+ }
940935
941- match whence {
942- libc:: SEEK_SET => {
943- // Validate offset bounds
944- if offset > i64:: MAX as u64 {
936+ // Handle directory lseek operations according to POSIX standard
937+ // This enables seekdir/telldir functionality on directories
938+ match whence {
939+ // SEEK_SET: Set the directory position to an absolute value
940+ libc:: SEEK_SET => {
941+ // Validate offset bounds to prevent overflow
942+ // Directory offsets should not exceed i64::MAX
943+ if offset > i64:: MAX as u64 {
944+ return Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) ) ;
945+ }
946+
947+ // Perform the seek operation on the underlying layer
948+ // Delegate to the lower layer implementation
949+ layer. lseek ( req, real_inode, real_handle, offset, whence) . await
950+ }
951+ // SEEK_CUR: Move relative to the current directory position
952+ libc:: SEEK_CUR => {
953+ // Get current position from underlying layer
954+ // This is needed to calculate the new position
955+ let current = match layer
956+ . lseek ( req, real_inode, real_handle, 0 , libc:: SEEK_CUR )
957+ . await
958+ {
959+ Ok ( r) => r. offset ,
960+ Err ( _) => return Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) ) ,
961+ } ;
962+
963+ // Check for potential overflow when adding the provided offset
964+ // This prevents invalid position calculations
965+ if let Some ( new_offset) = current. checked_add ( offset) {
966+ // Ensure the new offset is within valid bounds
967+ if new_offset > i64:: MAX as u64 {
945968 return Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) ) ;
946969 }
947970
948- // Perform the seek operation
949- rh. layer
950- . lseek ( req, rh. inode , rh. handle . load ( Ordering :: Relaxed ) , offset, whence)
951- . await
952- } ,
953- libc:: SEEK_CUR => {
954- // Get current position
955- let current = if let Ok ( reply) = rh. layer
956- . lseek ( req, rh. inode , rh. handle . load ( Ordering :: Relaxed ) , 0 , libc:: SEEK_CUR )
971+ // Actually set the underlying offset to the new value so behavior
972+ // matches passthrough which uses libc::lseek64 to set the fd offset.
973+ match layer
974+ . lseek ( req, real_inode, real_handle, new_offset, libc:: SEEK_SET )
957975 . await
958976 {
959- reply. offset
960- } else {
961- return Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) ) ;
962- } ;
963-
964- // Check for potential overflow
965- if let Some ( new_offset) = current. checked_add ( offset) {
966- if new_offset > i64:: MAX as u64 {
967- return Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) ) ;
968- }
969- Ok ( ReplyLSeek { offset : new_offset } )
970- } else {
971- Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) )
977+ Ok ( _) => Ok ( ReplyLSeek { offset : new_offset } ) ,
978+ Err ( _) => Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) ) ,
972979 }
973- } ,
974- _ => Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) ) ,
980+ } else {
981+ Err ( Error :: from_raw_os_error ( libc:: EINVAL ) . into ( ) )
982+ }
975983 }
976- } else {
977- Err ( Error :: new ( ErrorKind :: InvalidInput , "Invalid directory handle" ) . into ( ) )
984+ // Any other whence value is invalid for directories
985+ _ => Err ( Error :: from_raw_os_error ( libc :: EINVAL ) . into ( ) ) ,
978986 }
979987 } else {
980988 // Keep the original lseek behavior for regular files
989+ // Delegate directly to the underlying layer
981990 let ( layer, real_inode, real_handle) = self . find_real_info_from_handle ( fh) . await ?;
982991 layer
983992 . lseek ( req, real_inode, real_handle, offset, whence)
0 commit comments