@@ -25,6 +25,17 @@ pub struct File<'a, IO: ReadWriteSeek, TP, OCC> {
25
25
fs : & ' a FileSystem < IO , TP , OCC > ,
26
26
}
27
27
28
+ /// An extent containing a file's data on disk.
29
+ ///
30
+ /// This is created by the `extents` method on `File`, and represents
31
+ /// a byte range on the disk that contains a file's data. All values
32
+ /// are in bytes.
33
+ #[ derive( Clone , Debug ) ]
34
+ pub struct Extent {
35
+ pub offset : u64 ,
36
+ pub size : u32 ,
37
+ }
38
+
28
39
impl < ' a , IO : ReadWriteSeek , TP , OCC > File < ' a , IO , TP , OCC > {
29
40
pub ( crate ) fn new (
30
41
first_cluster : Option < u32 > ,
@@ -74,6 +85,39 @@ impl<'a, IO: ReadWriteSeek, TP, OCC> File<'a, IO, TP, OCC> {
74
85
}
75
86
}
76
87
88
+ /// Get the extents of a file on disk.
89
+ ///
90
+ /// This returns an iterator over the byte ranges on-disk occupied by
91
+ /// this file.
92
+ pub fn extents ( & mut self ) -> impl Iterator < Item =Result < Extent , Error < IO :: Error > > > + ' a {
93
+
94
+ let fs = self . fs ;
95
+ let cluster_size = fs. cluster_size ( ) ;
96
+ let mut bytes_left = match self . size ( ) {
97
+ Some ( s) => s,
98
+ None => return None . into_iter ( ) . flatten ( ) ,
99
+ } ;
100
+ let first = match self . first_cluster {
101
+ Some ( f) => f,
102
+ None => return None . into_iter ( ) . flatten ( ) ,
103
+ } ;
104
+
105
+ Some ( core:: iter:: once ( Ok ( first) ) . chain ( fs. cluster_iter ( first) )
106
+ . map ( move |cluster_err| {
107
+ match cluster_err {
108
+ Ok ( cluster) => {
109
+ let size = cluster_size. min ( bytes_left) ;
110
+ bytes_left -= size;
111
+ Ok ( Extent {
112
+ offset : fs. offset_from_cluster ( cluster) ,
113
+ size : size,
114
+ } )
115
+ } ,
116
+ Err ( e) => Err ( e) ,
117
+ }
118
+ } ) ) . into_iter ( ) . flatten ( )
119
+ }
120
+
77
121
pub ( crate ) fn abs_pos ( & self ) -> Option < u64 > {
78
122
// Returns current position relative to filesystem start
79
123
// Note: when between clusters it returns position after previous cluster
0 commit comments