@@ -697,6 +697,131 @@ pub fn fallocate(
697
697
Errno :: result( res) . map( drop)
698
698
}
699
699
700
+ /// Argument to [`fspacectl`] describing the range to zero. The first member is
701
+ /// the file offset, and the second is the length of the region.
702
+ #[ cfg( any( target_os = "freebsd" ) ) ]
703
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
704
+ pub struct SpacectlRange ( pub libc:: off_t, pub libc:: off_t) ;
705
+
706
+ #[ cfg( any( target_os = "freebsd" ) ) ]
707
+ impl SpacectlRange {
708
+ #[ inline]
709
+ pub fn is_empty( & self ) -> bool {
710
+ self . 1 == 0
711
+ }
712
+
713
+ #[ inline]
714
+ pub fn len( & self ) -> libc:: off_t {
715
+ self . 1
716
+ }
717
+
718
+ #[ inline]
719
+ pub fn offset( & self ) -> libc:: off_t {
720
+ self . 0
721
+ }
722
+ }
723
+
724
+ /// Punch holes in a file.
725
+ ///
726
+ /// `fspacectl` instructs the file system to deallocate a portion of a file.
727
+ /// After a successful operation, this region of the file will return all zeroes
728
+ /// if read. If the file system supports deallocation, then it may free the
729
+ /// underlying storage, too.
730
+ ///
731
+ /// # Arguments
732
+ ///
733
+ /// - `fd` - File to operate on
734
+ /// - `range.0` - File offset at which to begin deallocation
735
+ /// - `range.1` - Length of the region to deallocate
736
+ ///
737
+ /// # Returns
738
+ ///
739
+ /// The operation may deallocate less than the entire requested region. On
740
+ /// success, it returns the region that still remains to be deallocated. The
741
+ /// caller should loop until the returned region is empty.
742
+ ///
743
+ /// # Example
744
+ ///
745
+ // no_run because it fails to link until FreeBSD 14.0
746
+ /// ```no_run
747
+ /// # use std::io::Write;
748
+ /// # use std::os::unix::fs::FileExt;
749
+ /// # use std::os::unix::io::AsRawFd;
750
+ /// # use nix::fcntl::*;
751
+ /// # use tempfile::tempfile;
752
+ /// const INITIAL: &[u8] = b"0123456789abcdef";
753
+ /// let mut f = tempfile().unwrap();
754
+ /// f.write_all(INITIAL).unwrap();
755
+ /// let mut range = SpacectlRange(3, 6);
756
+ /// while (!range.is_empty()) {
757
+ /// range = fspacectl(f.as_raw_fd(), range).unwrap();
758
+ /// }
759
+ /// let mut buf = vec![0; INITIAL.len()];
760
+ /// f.read_exact_at(&mut buf, 0).unwrap();
761
+ /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef");
762
+ /// ```
763
+ #[ cfg( target_os = "freebsd" ) ]
764
+ pub fn fspacectl( fd: RawFd , range: SpacectlRange ) -> Result <SpacectlRange > {
765
+ let mut rqsr = libc:: spacectl_range{ r_offset: range. 0 , r_len: range. 1 } ;
766
+ let res = unsafe { libc:: fspacectl(
767
+ fd,
768
+ libc:: SPACECTL_DEALLOC , // Only one command is supported ATM
769
+ & rqsr,
770
+ 0 , // No flags are currently supported
771
+ & mut rqsr
772
+ ) } ;
773
+ Errno :: result( res) . map( |_| SpacectlRange ( rqsr. r_offset, rqsr. r_len) )
774
+ }
775
+
776
+ /// Like [`fspacectl`], but will never return incomplete.
777
+ ///
778
+ /// # Arguments
779
+ ///
780
+ /// - `fd` - File to operate on
781
+ /// - `offset` - File offset at which to begin deallocation
782
+ /// - `len` - Length of the region to deallocate
783
+ ///
784
+ /// # Returns
785
+ ///
786
+ /// Returns `()` on success. On failure, the region may or may not be partially
787
+ /// deallocated.
788
+ ///
789
+ /// # Example
790
+ ///
791
+ // no_run because it fails to link until FreeBSD 14.0
792
+ /// ```no_run
793
+ /// # use std::io::Write;
794
+ /// # use std::os::unix::fs::FileExt;
795
+ /// # use std::os::unix::io::AsRawFd;
796
+ /// # use nix::fcntl::*;
797
+ /// # use tempfile::tempfile;
798
+ /// const INITIAL: &[u8] = b"0123456789abcdef";
799
+ /// let mut f = tempfile().unwrap();
800
+ /// f.write_all(INITIAL).unwrap();
801
+ /// fspacectl_all(f.as_raw_fd(), 3, 6).unwrap();
802
+ /// let mut buf = vec![0; INITIAL.len()];
803
+ /// f.read_exact_at(&mut buf, 0).unwrap();
804
+ /// assert_eq!(buf, b"012\0\0\0\0\0\09abcdef");
805
+ /// ```
806
+ #[ cfg( target_os = "freebsd" ) ]
807
+ pub fn fspacectl_all( fd: RawFd , offset: libc:: off_t, len: libc:: off_t)
808
+ -> Result <( ) >
809
+ {
810
+ let mut rqsr = libc:: spacectl_range{ r_offset: offset, r_len: len} ;
811
+ while rqsr. r_len > 0 {
812
+ let res = unsafe { libc:: fspacectl(
813
+ fd,
814
+ libc:: SPACECTL_DEALLOC , // Only one command is supported ATM
815
+ & rqsr,
816
+ 0 , // No flags are currently supported
817
+ & mut rqsr
818
+ ) } ;
819
+ if let Err ( e) = Errno :: result( res) {
820
+ return Err ( e) ;
821
+ }
822
+ }
823
+ Ok ( ( ) )
824
+ }
700
825
701
826
#[ cfg( any(
702
827
target_os = "linux" ,
0 commit comments