From 522bf08c55caf26e485378ddb7551229bd63b301 Mon Sep 17 00:00:00 2001 From: sylvestre Date: Sat, 13 May 2023 02:33:58 +0000 Subject: [PATCH] deploy: f0e8d44e6e64ee3354f95864c0a25b74cf1c1151 --- dev/src/uu_dd/dd.rs.html | 332 +++++++++++++++++++++++++++++++- dev/src/uu_dd/parseargs.rs.html | 4 +- dev/src/uu_dd/progress.rs.html | 24 ++- dev/uu_dd/fn.uu_app.html | 2 +- dev/uu_dd/fn.uumain.html | 2 +- dev/uu_dd/index.html | 2 +- 6 files changed, 351 insertions(+), 15 deletions(-) diff --git a/dev/src/uu_dd/dd.rs.html b/dev/src/uu_dd/dd.rs.html index 6ce6f4585..3a47a463d 100644 --- a/dev/src/uu_dd/dd.rs.html +++ b/dev/src/uu_dd/dd.rs.html @@ -1064,6 +1064,169 @@ 1064 1065 1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229
// This file is part of the uutils coreutils package.
 //
 // (c) Tyler Steele <tyler.steele@protonmail.com>
@@ -1071,7 +1234,7 @@
 // For the full copyright and license information, please view the LICENSE
 // file that was distributed with this source code.
 
-// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, iseek, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, oseek, outfile, parseargs, rlen, rmax, rremain, rsofar, rstat, sigusr, wlen, wstat seekable oconv canonicalized
+// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, iseek, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, oseek, outfile, parseargs, rlen, rmax, rremain, rsofar, rstat, sigusr, wlen, wstat seekable oconv canonicalized fadvise Fadvise FADV DONTNEED ESPIPE
 
 mod datastructures;
 use datastructures::*;
@@ -1108,9 +1271,16 @@
 
 use clap::{crate_version, Arg, Command};
 use gcd::Gcd;
+#[cfg(target_os = "linux")]
+use nix::{
+    errno::Errno,
+    fcntl::{posix_fadvise, PosixFadviseAdvice},
+};
 use uucore::display::Quotable;
 use uucore::error::{FromIo, UResult};
 use uucore::{format_usage, help_about, help_section, help_usage, show_error};
+#[cfg(target_os = "linux")]
+use uucore::{show, show_if_err};
 
 const ABOUT: &str = help_about!("dd.md");
 const AFTER_HELP: &str = help_section!("after help", "dd.md");
@@ -1197,6 +1367,16 @@
         Self::StdinFile(f)
     }
 
+    /// The length of the data source in number of bytes.
+    ///
+    /// If it cannot be determined, then this function returns 0.
+    fn len(&self) -> std::io::Result<i64> {
+        match self {
+            Self::File(f) => Ok(f.metadata()?.len().try_into().unwrap_or(i64::MAX)),
+            _ => Ok(0),
+        }
+    }
+
     fn skip(&mut self, n: u64) -> io::Result<u64> {
         match self {
             #[cfg(not(unix))]
@@ -1222,6 +1402,23 @@
             Self::Fifo(f) => io::copy(&mut f.take(n), &mut io::sink()),
         }
     }
+
+    /// Discard the system file cache for the given portion of the data source.
+    ///
+    /// `offset` and `len` specify a contiguous portion of the data
+    /// source. This function informs the kernel that the specified
+    /// portion of the source is no longer needed. If not possible,
+    /// then this function returns an error.
+    #[cfg(target_os = "linux")]
+    fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> nix::Result<()> {
+        match self {
+            Self::File(f) => {
+                let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
+                posix_fadvise(f.as_raw_fd(), offset, len, advice)
+            }
+            _ => Err(Errno::ESPIPE), // "Illegal seek"
+        }
+    }
 }
 
 impl Read for Source {
@@ -1362,6 +1559,29 @@
 }
 
 impl<'a> Input<'a> {
+    /// Discard the system file cache for the given portion of the input.
+    ///
+    /// `offset` and `len` specify a contiguous portion of the input.
+    /// This function informs the kernel that the specified portion of
+    /// the input file is no longer needed. If not possible, then this
+    /// function prints an error message to stderr and sets the exit
+    /// status code to 1.
+    #[allow(unused_variables)]
+    fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
+        #[cfg(target_os = "linux")]
+        {
+            show_if_err!(self
+                .src
+                .discard_cache(offset, len)
+                .map_err_context(|| "failed to discard cache for: 'standard input'".to_string()));
+        }
+        #[cfg(not(target_os = "linux"))]
+        {
+            // TODO Is there a way to discard filesystem cache on
+            // these other operating systems?
+        }
+    }
+
     /// Fills a given buffer.
     /// Reads in increments of 'self.ibs'.
     /// The start of each ibs-sized read follows the previous one.
@@ -1383,13 +1603,13 @@
                 _ => break,
             }
         }
-
         buf.truncate(bytes_total);
         Ok(ReadStat {
             reads_complete,
             reads_partial,
             // Records are not truncated when filling.
             records_truncated: 0,
+            bytes_total: bytes_total.try_into().unwrap(),
         })
     }
 
@@ -1400,6 +1620,7 @@
         let mut reads_complete = 0;
         let mut reads_partial = 0;
         let mut base_idx = 0;
+        let mut bytes_total = 0;
 
         while base_idx < buf.len() {
             let next_blk = cmp::min(base_idx + self.settings.ibs, buf.len());
@@ -1408,11 +1629,13 @@
             match self.read(&mut buf[base_idx..next_blk])? {
                 0 => break,
                 rlen if rlen < target_len => {
+                    bytes_total += rlen;
                     reads_partial += 1;
                     let padding = vec![pad; target_len - rlen];
                     buf.splice(base_idx + rlen..next_blk, padding.into_iter());
                 }
-                _ => {
+                rlen => {
+                    bytes_total += rlen;
                     reads_complete += 1;
                 }
             }
@@ -1425,6 +1648,7 @@
             reads_complete,
             reads_partial,
             records_truncated: 0,
+            bytes_total: bytes_total.try_into().unwrap(),
         })
     }
 }
@@ -1513,6 +1737,33 @@
             _ => Ok(()),
         }
     }
+
+    /// Discard the system file cache for the given portion of the destination.
+    ///
+    /// `offset` and `len` specify a contiguous portion of the
+    /// destination. This function informs the kernel that the
+    /// specified portion of the destination is no longer needed. If
+    /// not possible, then this function returns an error.
+    #[cfg(target_os = "linux")]
+    fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> nix::Result<()> {
+        match self {
+            Self::File(f, _) => {
+                let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
+                posix_fadvise(f.as_raw_fd(), offset, len, advice)
+            }
+            _ => Err(Errno::ESPIPE), // "Illegal seek"
+        }
+    }
+
+    /// The length of the data destination in number of bytes.
+    ///
+    /// If it cannot be determined, then this function returns 0.
+    fn len(&self) -> std::io::Result<i64> {
+        match self {
+            Self::File(f, _) => Ok(f.metadata()?.len().try_into().unwrap_or(i64::MAX)),
+            _ => Ok(0),
+        }
+    }
 }
 
 /// Decide whether the given buffer is all zeros.
@@ -1646,6 +1897,29 @@
         Ok(Self { dst, settings })
     }
 
+    /// Discard the system file cache for the given portion of the output.
+    ///
+    /// `offset` and `len` specify a contiguous portion of the output.
+    /// This function informs the kernel that the specified portion of
+    /// the output file is no longer needed. If not possible, then
+    /// this function prints an error message to stderr and sets the
+    /// exit status code to 1.
+    #[allow(unused_variables)]
+    fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) {
+        #[cfg(target_os = "linux")]
+        {
+            show_if_err!(self
+                .dst
+                .discard_cache(offset, len)
+                .map_err_context(|| "failed to discard cache for: 'standard output'".to_string()));
+        }
+        #[cfg(target_os = "linux")]
+        {
+            // TODO Is there a way to discard filesystem cache on
+            // these other operating systems?
+        }
+    }
+
     /// Write the given bytes one block at a time.
     ///
     /// This may write partial blocks (for example, if the underlying
@@ -1740,6 +2014,27 @@
     // Optimization: if no blocks are to be written, then don't
     // bother allocating any buffers.
     if let Some(Num::Blocks(0) | Num::Bytes(0)) = i.settings.count {
+        // Even though we are not reading anything from the input
+        // file, we still need to honor the `nocache` flag, which
+        // requests that we inform the system that we no longer
+        // need the contents of the input file in a system cache.
+        //
+        // TODO Better error handling for overflowing `len`.
+        if i.settings.iflags.nocache {
+            let offset = 0;
+            #[allow(clippy::useless_conversion)]
+            let len = i.src.len()?.try_into().unwrap();
+            i.discard_cache(offset, len);
+        }
+        // Similarly, discard the system cache for the output file.
+        //
+        // TODO Better error handling for overflowing `len`.
+        if i.settings.oflags.nocache {
+            let offset = 0;
+            #[allow(clippy::useless_conversion)]
+            let len = o.dst.len()?.try_into().unwrap();
+            o.discard_cache(offset, len);
+        }
         return finalize(&mut o, rstat, wstat, start, &prog_tx, output_thread);
     };
 
@@ -1747,6 +2042,13 @@
     // This is the max size needed.
     let mut buf = vec![BUF_INIT_BYTE; bsize];
 
+    // Index in the input file where we are reading bytes and in
+    // the output file where we are writing bytes.
+    //
+    // These are updated on each iteration of the main loop.
+    let mut read_offset = 0;
+    let mut write_offset = 0;
+
     // The main read/write loop.
     //
     // Each iteration reads blocks from the input and writes
@@ -1766,6 +2068,30 @@
         }
         let wstat_update = o.write_blocks(&buf)?;
 
+        // Discard the system file cache for the read portion of
+        // the input file.
+        //
+        // TODO Better error handling for overflowing `offset` and `len`.
+        let read_len = rstat_update.bytes_total;
+        if i.settings.iflags.nocache {
+            let offset = read_offset.try_into().unwrap();
+            let len = read_len.try_into().unwrap();
+            i.discard_cache(offset, len);
+        }
+        read_offset += read_len;
+
+        // Discard the system file cache for the written portion
+        // of the output file.
+        //
+        // TODO Better error handling for overflowing `offset` and `len`.
+        let write_len = wstat_update.bytes_total;
+        if o.settings.oflags.nocache {
+            let offset = write_offset.try_into().unwrap();
+            let len = write_len.try_into().unwrap();
+            o.discard_cache(offset, len);
+        }
+        write_offset += write_len;
+
         // Update the read/write stats and inform the progress thread once per second.
         //
         // If the receiver is disconnected, `send()` returns an
diff --git a/dev/src/uu_dd/parseargs.rs.html b/dev/src/uu_dd/parseargs.rs.html
index be5fb4603..372809528 100644
--- a/dev/src/uu_dd/parseargs.rs.html
+++ b/dev/src/uu_dd/parseargs.rs.html
@@ -951,7 +951,7 @@
                 "directory" => linux_only!(f, i.directory = true),
                 "dsync" => linux_only!(f, i.dsync = true),
                 "sync" => linux_only!(f, i.sync = true),
-                "nocache" => return Err(ParseError::Unimplemented(f.to_string())),
+                "nocache" => linux_only!(f, i.nocache = true),
                 "nonblock" => linux_only!(f, i.nonblock = true),
                 "noatime" => linux_only!(f, i.noatime = true),
                 "noctty" => linux_only!(f, i.noctty = true),
@@ -983,7 +983,7 @@
                 "directory" => linux_only!(f, o.directory = true),
                 "dsync" => linux_only!(f, o.dsync = true),
                 "sync" => linux_only!(f, o.sync = true),
-                "nocache" => return Err(ParseError::Unimplemented(f.to_string())),
+                "nocache" => linux_only!(f, o.nocache = true),
                 "nonblock" => linux_only!(f, o.nonblock = true),
                 "noatime" => linux_only!(f, o.noatime = true),
                 "noctty" => linux_only!(f, o.noctty = true),
diff --git a/dev/src/uu_dd/progress.rs.html b/dev/src/uu_dd/progress.rs.html
index b01118506..0e5a5c471 100644
--- a/dev/src/uu_dd/progress.rs.html
+++ b/dev/src/uu_dd/progress.rs.html
@@ -656,6 +656,11 @@
 656
 657
 658
+659
+660
+661
+662
+663
 
//  * This file is part of the uutils coreutils package.
 //  *
 //  * For the full copyright and license information, please view the LICENSE
@@ -737,9 +742,9 @@
     /// ```rust,ignore
     /// use std::io::Cursor;
     /// use std::time::Duration;
-    /// use crate::progress::{ProgUpdate, ReadState, WriteStat};
+    /// use crate::progress::{ProgUpdate, ReadStat, WriteStat};
     ///
-    /// let read_stat = ReadStat::new(1, 2, 3);
+    /// let read_stat = ReadStat::new(1, 2, 3, 999);
     /// let write_stat = WriteStat::new(4, 5, 6);
     /// let duration = Duration::new(789, 0);
     /// let prog_update = ProgUpdate {
@@ -779,7 +784,7 @@
     /// ```rust,ignore
     /// use std::io::Cursor;
     /// use std::time::Duration;
-    /// use crate::progress::{ProgUpdate, ReadState, WriteStat};
+    /// use crate::progress::ProgUpdate;
     ///
     /// let prog_update = ProgUpdate {
     ///     read_stat: Default::default(),
@@ -849,7 +854,7 @@
     /// ```rust,ignore
     /// use std::io::Cursor;
     /// use std::time::Duration;
-    /// use crate::progress::{ProgUpdate, ReadState, WriteStat};
+    /// use crate::progress::ProgUpdate;
     ///
     /// let prog_update = ProgUpdate {
     ///     read_stat: Default::default(),
@@ -934,16 +939,20 @@
     ///
     /// A truncated record can only occur in `conv=block` mode.
     pub(crate) records_truncated: u32,
+
+    /// The total number of bytes read.
+    pub(crate) bytes_total: u64,
 }
 
 impl ReadStat {
     /// Create a new instance.
     #[allow(dead_code)]
-    fn new(complete: u64, partial: u64, truncated: u32) -> Self {
+    fn new(complete: u64, partial: u64, truncated: u32, bytes_total: u64) -> Self {
         Self {
             reads_complete: complete,
             reads_partial: partial,
             records_truncated: truncated,
+            bytes_total,
         }
     }
 
@@ -973,6 +982,7 @@
             reads_complete: self.reads_complete + other.reads_complete,
             reads_partial: self.reads_partial + other.reads_partial,
             records_truncated: self.records_truncated + other.records_truncated,
+            bytes_total: self.bytes_total + other.bytes_total,
         }
     }
 }
@@ -1172,7 +1182,7 @@
 
     #[test]
     fn test_read_stat_report() {
-        let read_stat = ReadStat::new(1, 2, 3);
+        let read_stat = ReadStat::new(1, 2, 3, 4);
         let mut cursor = Cursor::new(vec![]);
         read_stat.report(&mut cursor).unwrap();
         assert_eq!(cursor.get_ref(), b"1+2 records in\n");
@@ -1188,7 +1198,7 @@
 
     #[test]
     fn test_prog_update_write_io_lines() {
-        let read_stat = ReadStat::new(1, 2, 3);
+        let read_stat = ReadStat::new(1, 2, 3, 4);
         let write_stat = WriteStat::new(4, 5, 6);
         let duration = Duration::new(789, 0);
         let complete = false;
diff --git a/dev/uu_dd/fn.uu_app.html b/dev/uu_dd/fn.uu_app.html
index 643c002a1..3132c1f7f 100644
--- a/dev/uu_dd/fn.uu_app.html
+++ b/dev/uu_dd/fn.uu_app.html
@@ -1 +1 @@
-uu_app in uu_dd - Rust

Function uu_dd::uu_app

source ·
pub fn uu_app() -> Command
\ No newline at end of file +uu_app in uu_dd - Rust

Function uu_dd::uu_app

source ·
pub fn uu_app() -> Command
\ No newline at end of file diff --git a/dev/uu_dd/fn.uumain.html b/dev/uu_dd/fn.uumain.html index 329765aff..07e7890ad 100644 --- a/dev/uu_dd/fn.uumain.html +++ b/dev/uu_dd/fn.uumain.html @@ -1 +1 @@ -uumain in uu_dd - Rust

Function uu_dd::uumain

source ·
pub fn uumain(args: impl Args) -> i32
\ No newline at end of file +uumain in uu_dd - Rust

Function uu_dd::uumain

source ·
pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/dev/uu_dd/index.html b/dev/uu_dd/index.html index 411417b86..60c74c97b 100644 --- a/dev/uu_dd/index.html +++ b/dev/uu_dd/index.html @@ -1 +1 @@ -uu_dd - Rust
\ No newline at end of file +uu_dd - Rust
\ No newline at end of file