Repository: tauri-apps/tauri
File: core/tauri/src/api/file/extract.rs (Rust)

Code before:
      Self::Tar(mut entry) => {
        // determine if it's a file or a directory
        if entry.header().entry_type() == tar::EntryType::Directory {
          // this is a directory, lets create it
          match fs::create_dir_all(into_path) {
            Ok(_) => (),
            Err(e) => {
              if e.kind() != io::ErrorKind::AlreadyExists {
                return Err(e.into());
              }
            }
          }
        } else {
          // handle files, symlinks, hard links, etc. and set permissions
          entry.unpack(into_path)?;
        }
      }
      Self::Zip(entry) => {
        if entry.is_dir {
          // this is a directory, lets create it
          match fs::create_dir_all(into_path) {
            Ok(_) => (),
            Err(e) => {
              if e.kind() != io::ErrorKind::AlreadyExists {
                return Err(e.into());
              }
            }
          }
        } else {
          let mut out_file = fs::File::create(into_path)?;
          io::copy(&mut Cursor::new(entry.file_contents), &mut out_file)?;
        }
      }
    }

    Ok(())
  }
}

/// The extract manager to retrieve files from archives.
pub struct Extract<'a, R: Read + Seek> {
  reader: ArchiveReader<R>,
  archive_format: ArchiveFormat,
  tar_archive: Option<tar::Archive<&'a mut ArchiveReader<R>>>,
}

impl<'a, R: std::fmt::Debug + Read + Seek> std::fmt::Debug for Extract<'a, R> {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("Extract")
      .field("reader", &self.reader)
      .field("archive_format", &self.archive_format)

Review comment (suggestion):
Using [`Entry::unpack_in`](https://docs.rs/tar/latest/tar/struct.Entry.html#method.unpack_in) will help prevent unpacking a file outside the destination.
```suggestion
          entry.unpack_in(into_path)?;
```

Code after:
      Self::Tar(mut entry) => {
        // validate path
        let path = entry.path()?;
        if path.components().any(|c| matches!(c, Component::ParentDir)) {
          return Err(
            std::io::Error::new(
              std::io::ErrorKind::InvalidInput,
              "cannot extract path with parent dir component",
            )
            .into(),
          );
        }
        // determine if it's a file or a directory
        if entry.header().entry_type() == tar::EntryType::Directory {
          // this is a directory, lets create it
          match fs::create_dir_all(into_path) {
            Ok(_) => (),
            Err(e) => {
              if e.kind() != io::ErrorKind::AlreadyExists {
                return Err(e.into());
              }
            }
          }
        } else {
          // handle files, symlinks, hard links, etc. and set permissions
          entry.unpack(into_path)?;
        }
      }
      Self::Zip(entry) => {
        if entry.is_dir {
          // this is a directory, lets create it
          match fs::create_dir_all(into_path) {
            Ok(_) => (),
            Err(e) => {
              if e.kind() != io::ErrorKind::AlreadyExists {
                return Err(e.into());
              }
            }
          }
        } else {
          let mut out_file = fs::File::create(into_path)?;
          io::copy(&mut Cursor::new(entry.file_contents), &mut out_file)?;
        }
      }
    }

    Ok(())
  }
}

/// The extract manager to retrieve files from archives.