@@ -134,17 +134,12 @@ fn export_filesystem_walk<W: Write>(
134134 root_dir : & cap_std_ext:: cap_std:: fs:: Dir ,
135135 sepolicy : Option < & ostree:: SePolicy > ,
136136) -> Result < ( ) > {
137- use cap_std_ext:: cap_primitives:: fs:: MetadataExt ;
138137 use std:: path:: Path ;
139138
140- // Get the device number of the root directory - we should never see a different device
141- // since we use noxdev() which prevents crossing mount points
142- let root_meta = root_dir. dir_metadata ( ) ?;
143- let expected_dev = root_meta. dev ( ) ;
144-
145- // Track hardlinks: maps inode -> first path seen
146- // We only track inode since all files must be on the same device
147- let mut hardlinks: HashMap < u64 , std:: path:: PathBuf > = HashMap :: new ( ) ;
139+ // Track hardlinks: maps (dev, inode) -> first path seen.
140+ // We key on (dev, ino) because overlay filesystems may present
141+ // different device numbers for directories vs regular files.
142+ let mut hardlinks: HashMap < ( u64 , u64 ) , std:: path:: PathBuf > = HashMap :: new ( ) ;
148143
149144 // The target mount shouldn't have submounts, but just in case we use noxdev
150145 let walk_config = WalkConfiguration :: default ( )
@@ -192,7 +187,6 @@ fn export_filesystem_walk<W: Write>(
192187 path,
193188 relative_path,
194189 sepolicy,
195- expected_dev,
196190 & mut hardlinks,
197191 )
198192 . map_err ( std:: io:: Error :: other) ?;
@@ -250,34 +244,21 @@ fn add_file_to_tar_from_walk<W: Write>(
250244 absolute_path : & std:: path:: Path ,
251245 relative_path : & std:: path:: Path ,
252246 sepolicy : Option < & ostree:: SePolicy > ,
253- expected_dev : u64 ,
254- hardlinks : & mut HashMap < u64 , std:: path:: PathBuf > ,
247+ hardlinks : & mut HashMap < ( u64 , u64 ) , std:: path:: PathBuf > ,
255248) -> Result < ( ) > {
256249 use cap_std_ext:: cap_primitives:: fs:: { MetadataExt , PermissionsExt } ;
257250 use std:: path:: Path ;
258251
259252 let filename_path = Path :: new ( filename) ;
260253 let metadata = dir. metadata ( filename_path) ?;
261254
262- // Skip files on different devices (e.g., bind mounts in containers like /etc/hosts).
263- // The noxdev() option prevents descending into directories on different devices,
264- // but individual files can still be bind-mounted from other filesystems.
265- let dev = metadata. dev ( ) ;
266- if dev != expected_dev {
267- tracing:: debug!(
268- "Skipping file on different device: {} (expected dev {}, found {})" ,
269- relative_path. display( ) ,
270- expected_dev,
271- dev
272- ) ;
273- return Ok ( ( ) ) ;
274- }
275-
276- // Check for hardlinks: if nlink > 1, this file may have other links
255+ // Check for hardlinks: if nlink > 1, this file may have other links.
256+ // We key on (dev, ino) because overlay filesystems may present
257+ // different device numbers for directories vs regular files.
277258 let nlink = metadata. nlink ( ) ;
278259 if nlink > 1 {
279- let ino = metadata. ino ( ) ;
280- if let Some ( first_path) = hardlinks. get ( & ino ) {
260+ let key = ( metadata. dev ( ) , metadata . ino ( ) ) ;
261+ if let Some ( first_path) = hardlinks. get ( & key ) {
281262 // This is a hardlink to a file we've already written
282263 let mut header = tar_header_from_meta ( tar:: EntryType :: Link , 0 , & metadata) ;
283264
@@ -293,7 +274,7 @@ fn add_file_to_tar_from_walk<W: Write>(
293274 return Ok ( ( ) ) ;
294275 } else {
295276 // First time seeing this inode, record it
296- hardlinks. insert ( ino , relative_path. to_path_buf ( ) ) ;
277+ hardlinks. insert ( key , relative_path. to_path_buf ( ) ) ;
297278 }
298279 }
299280
0 commit comments