file.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! Types and functions related to file operations.
  5. #[cfg(feature = "fs-extract-api")]
  6. mod extract;
  7. mod file_move;
  8. use std::{
  9. fs,
  10. path::{Display, Path},
  11. };
  12. #[cfg(feature = "fs-extract-api")]
  13. pub use extract::*;
  14. pub use file_move::*;
  15. use serde::{de::Error as DeError, Deserialize, Deserializer};
  16. #[derive(Clone, Debug)]
  17. pub(crate) struct SafePathBuf(std::path::PathBuf);
  18. impl SafePathBuf {
  19. pub fn new(path: std::path::PathBuf) -> Result<Self, &'static str> {
  20. if path
  21. .components()
  22. .any(|x| matches!(x, std::path::Component::ParentDir))
  23. {
  24. Err("cannot traverse directory, rewrite the path without the use of `../`")
  25. } else {
  26. Ok(Self(path))
  27. }
  28. }
  29. #[allow(dead_code)]
  30. pub unsafe fn new_unchecked(path: std::path::PathBuf) -> Self {
  31. Self(path)
  32. }
  33. #[allow(dead_code)]
  34. pub fn display(&self) -> Display<'_> {
  35. self.0.display()
  36. }
  37. }
  38. impl AsRef<Path> for SafePathBuf {
  39. fn as_ref(&self) -> &Path {
  40. self.0.as_ref()
  41. }
  42. }
  43. impl<'de> Deserialize<'de> for SafePathBuf {
  44. fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  45. where
  46. D: Deserializer<'de>,
  47. {
  48. let path = std::path::PathBuf::deserialize(deserializer)?;
  49. SafePathBuf::new(path).map_err(DeError::custom)
  50. }
  51. }
  52. /// Reads the entire contents of a file into a string.
  53. pub fn read_string<P: AsRef<Path>>(file: P) -> crate::api::Result<String> {
  54. fs::read_to_string(file).map_err(Into::into)
  55. }
  56. /// Reads the entire contents of a file into a bytes vector.
  57. pub fn read_binary<P: AsRef<Path>>(file: P) -> crate::api::Result<Vec<u8>> {
  58. fs::read(file).map_err(Into::into)
  59. }
  60. #[cfg(test)]
  61. mod test {
  62. use super::*;
  63. use crate::api::Error;
  64. use quickcheck::{Arbitrary, Gen};
  65. use std::path::PathBuf;
  66. impl Arbitrary for super::SafePathBuf {
  67. fn arbitrary(g: &mut Gen) -> Self {
  68. Self(PathBuf::arbitrary(g))
  69. }
  70. fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
  71. Box::new(self.0.shrink().map(SafePathBuf))
  72. }
  73. }
  74. #[test]
  75. fn check_read_string() {
  76. let file = String::from("test/api/test.txt");
  77. let res = read_string(file);
  78. assert!(res.is_ok());
  79. if let Ok(s) = res {
  80. assert_eq!(s, "This is a test doc!".to_string());
  81. }
  82. }
  83. #[test]
  84. fn check_read_string_fail() {
  85. let file = String::from("test/api/");
  86. let res = read_string(file);
  87. assert!(res.is_err());
  88. #[cfg(not(windows))]
  89. if let Error::Io(e) = res.unwrap_err() {
  90. #[cfg(not(windows))]
  91. assert_eq!(e.to_string(), "Is a directory (os error 21)".to_string());
  92. }
  93. }
  94. #[test]
  95. fn check_read_binary() {
  96. let file = String::from("test/api/test_binary");
  97. let expected_vec = vec![
  98. 71, 73, 70, 56, 57, 97, 1, 0, 1, 0, 128, 0, 0, 255, 255, 255, 0, 0, 0, 33, 249, 4, 1, 0, 0,
  99. 0, 0, 44, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 2, 68, 1, 0, 59,
  100. ];
  101. let res = read_binary(file);
  102. assert!(res.is_ok());
  103. if let Ok(vec) = res {
  104. assert_eq!(vec, expected_vec);
  105. }
  106. }
  107. #[test]
  108. fn check_read_binary_fail() {
  109. let file = String::from("test/api/");
  110. let res = read_binary(file);
  111. assert!(res.is_err());
  112. #[cfg(not(windows))]
  113. if let Error::Io(e) = res.unwrap_err() {
  114. #[cfg(not(windows))]
  115. assert_eq!(e.to_string(), "Is a directory (os error 21)".to_string());
  116. }
  117. }
  118. }