1#[cfg(all(feature = "fs", unix))]
55pub(crate) mod acl;
56#[cfg(feature = "app-dirs")]
57pub mod app_dirs;
58#[cfg(feature = "fs")]
59pub mod append;
60#[cfg(feature = "fs")]
61pub mod atomic;
62#[cfg(feature = "fs")]
63pub mod clone;
64#[cfg(feature = "fs")]
65pub mod confined_copy;
66pub mod contain;
67#[cfg(any(feature = "digest", feature = "blake3"))]
68pub mod digest;
69#[cfg(feature = "fs")]
70pub mod error;
71#[cfg(feature = "fs")]
72pub mod file_key;
73#[cfg(feature = "fs")]
74pub mod handle;
75#[cfg(feature = "fs")]
76pub mod identity;
77#[cfg(feature = "lock")]
78pub mod journal;
79#[cfg(feature = "fs")]
80pub mod lease;
81#[cfg(feature = "lock")]
82pub mod lock;
83#[cfg(feature = "fs")]
84pub mod malware_scan;
85#[cfg(feature = "fs")]
86pub mod migrate;
87pub mod names;
88#[cfg(feature = "fs")]
89pub mod netfs;
90#[cfg(feature = "fs")]
91pub mod owned_temp;
92pub mod plain;
93#[cfg(feature = "fs")]
94pub mod private;
95#[cfg(feature = "fs")]
96pub mod private_cached;
97#[cfg(feature = "app-dirs")]
98pub mod profile_home;
99#[cfg(feature = "fs")]
100pub mod publish_dir;
101#[cfg(feature = "fs")]
102pub mod rename_case;
103#[cfg(feature = "fs")]
104pub mod replaced;
105#[cfg(feature = "fs")]
106pub mod retention;
107#[cfg(feature = "fs")]
108pub mod secret_file;
109#[cfg(feature = "fs")]
110pub mod space;
111#[cfg(feature = "fs")]
112pub mod state;
113#[cfg(feature = "fs")]
114pub mod swap;
115#[cfg(feature = "toolchain-lease")]
116pub mod toolchain_lease;
117#[cfg(feature = "transaction")]
118pub mod transaction;
119#[cfg(feature = "fs")]
120pub mod transient;
121#[cfg(feature = "fs")]
122pub mod trash;
123#[cfg(feature = "fs")]
124pub mod tree;
125#[cfg(all(feature = "fs", any(feature = "digest", feature = "blake3")))]
126pub mod verified;
127#[cfg(all(feature = "fs", windows))]
128mod windows_temp_sweep;
129#[cfg(feature = "lock")]
130pub mod write_locks;
131pub mod zip;
132
133#[cfg(feature = "app-dirs")]
134pub use app_dirs::{
135 account_home, AppDirs, AppDirsError, AppId, Options as AppDirsOptions, Os as AppDirsOs,
136};
137#[cfg(feature = "fs")]
138pub use append::{append_record, open_private_append, AppendOptions};
139#[cfg(all(feature = "fs", feature = "digest"))]
140pub use atomic::atomic_write_with_digest;
141#[cfg(feature = "fs")]
142pub use atomic::{
143 atomic_write, atomic_write_private, atomic_write_reporting, atomic_write_with,
144 atomic_write_with_access_denied_retry, atomic_write_with_options, durable_sync,
145 durable_sync_with, publication_durability, publish_file, publish_file_first_free,
146 publish_file_with, publish_file_with_access_denied_retry, rename_exclusive,
147 rename_exclusive_reporting, sweep_stale_temps, sweep_stale_temps_report, try_sync_dir,
148 AccessDeniedRetry, AtomicOptions, AtomicWriteOptions, AtomicWriter, ExclusiveMethod, Privacy,
149 PublicationDurability, ReplaceMode, RetryPolicy, SweepReport, SyncLevel, SyncPolicy,
150 TempWriter, WriteReport,
151};
152#[cfg(feature = "fs")]
153pub use clone::{
154 clone_file_nofollow, clone_or_link_or_copy_nofollow, clone_or_link_or_copy_nofollow_with,
155 CloneError, CloneOptions, CloneOutcome,
156};
157#[cfg(feature = "fs")]
158pub use confined_copy::{copy_tree_confined, ConfinedCopy};
159pub use contain::{contain, contain_lenient, is_within, ContainError, Roots};
160#[cfg(feature = "fs")]
161pub use contain::{open_confined, ConfinedOptions};
162#[cfg(feature = "fs")]
163pub use error::{FsError, PostPublishStep, Result};
164#[cfg(feature = "fs")]
165pub use file_key::FileKey;
166#[cfg(feature = "fs")]
167pub use handle::{final_path, link_count, open_read_nofollow, ReadOptions};
168#[cfg(feature = "json")]
169pub use identity::IdentityStore;
170#[cfg(feature = "fs")]
171pub use identity::{Resolution, SearchLimits, StableId, Tracked};
172#[cfg(feature = "lock")]
173pub use journal::{JsonlJournal, OpenReport};
174#[cfg(feature = "fs")]
175pub use lease::{Acquire, Lease, LeaseInfo, LeaseOptions, Staleness};
176#[cfg(feature = "lock")]
177pub use lock::{probe_owner, with_lock, FileLock, LockKind, LockOptions, LockOwner};
178#[cfg(feature = "fs")]
179pub use malware_scan::{scan_file, ScanVerdict};
180#[cfg(feature = "fs")]
181pub use migrate::{migrate_dir, MigrateMethod, Migrated};
182#[cfg(feature = "fs")]
183pub use names::{create_download_file, create_unique_file};
184pub use names::{
185 is_windows_reserved_name, numbered_candidates, sanitize_file_name, sanitize_file_name_with,
186 NameOptions,
187};
188#[cfg(feature = "fs")]
189pub use netfs::is_network_filesystem;
190#[cfg(feature = "fs")]
191pub use owned_temp::{sweep_owned_temps, OwnedTemp};
192pub use plain::{canonicalize_plain, plain_path};
193#[cfg(feature = "fs")]
194pub use private::{
195 create_private_new, ensure_private_dir, restrict_owner_only, sweep_owner_only,
196 write_private_executable, write_private_file, write_private_text,
197};
198#[cfg(feature = "fs")]
199pub use publish_dir::{
200 pending_retained, publish_dir, publish_dir_retaining, publish_dir_with, DirPublishMethod,
201 DirPublishPolicy, PublishedDir, RetainedPublish,
202};
203#[cfg(feature = "fs")]
204pub use rename_case::rename_case_only;
205#[cfg(feature = "fs")]
206pub use replaced::{open_replaced, read_replaced, read_to_string_replaced};
207#[cfg(feature = "fs")]
208pub use retention::{quarantine, quarantine_hidden, Retention, RetentionReport};
209#[cfg(feature = "fs")]
210pub use secret_file::{read_secret_file, SecretFileError};
211#[cfg(feature = "fs")]
212pub use space::free_bytes;
213#[cfg(feature = "fs")]
214pub use state::{DirEntry, EntryKind, EntryStat, StateDir, StateOptions};
215#[cfg(feature = "fs")]
216pub use swap::{is_swap_unsupported, swap_paths};
217#[cfg(feature = "toolchain-lease")]
218pub use toolchain_lease::{
219 Enforcement, LeaseEvidence, RootEvidence, SealSpec, ToolchainLease, VerifyReport,
220};
221#[cfg(feature = "transaction")]
222pub use transaction::{
223 recover_transactions, recover_transactions_with, CommittedReport, ExpectedPrior,
224 FileTransaction, PreparedTransaction, Publication, RecoveredTransaction, RecoveryOutcome,
225 RecoveryReport, RecoveryRequiredReport, RetainedItem, RolledBackReport, TransactionEntry,
226 TransactionOptions, TransactionReport,
227};
228#[cfg(feature = "fs")]
229pub use trash::{move_to_trash, TrashEntry, TrashIdentity};
230#[cfg(feature = "fs")]
231pub use tree::{copy_tree, remove_tree, CopyOptions, RemoveOptions, RemoveReport};
232#[cfg(all(feature = "fs", feature = "digest"))]
233pub use verified::{copy_verified, copy_verified_with_progress, VerifiedCopy};
234#[cfg(all(feature = "fs", any(feature = "digest", feature = "blake3")))]
235pub use verified::{copy_verified_with_digest, DigestAlgorithm, VerifiedDigestCopy};
236#[cfg(feature = "lock")]
237pub use write_locks::{KeyedWriteLocks, LockedAtomicWriter, LockedDestination, WriteLockOptions};
238pub use zip::{crc32, stored_zip_bytes, StoredZipWriter};
239
240#[cfg(feature = "fs")]
245#[derive(Clone, Copy, Debug, PartialEq, Eq)]
246pub(crate) enum ProcessLiveness {
247 Alive,
248 Dead,
249 Unknown,
250}
251
252#[cfg(feature = "fs")]
254pub(crate) fn process_liveness(pid: u32) -> ProcessLiveness {
255 #[cfg(unix)]
256 {
257 if pid == 0 || pid > libc::pid_t::MAX as u32 {
258 return ProcessLiveness::Unknown;
259 }
260 let rc = unsafe { libc::kill(pid as libc::pid_t, 0) };
262 if rc == 0 {
263 ProcessLiveness::Alive
264 } else if std::io::Error::last_os_error().raw_os_error() == Some(libc::ESRCH) {
265 ProcessLiveness::Dead
266 } else {
267 ProcessLiveness::Unknown
268 }
269 }
270 #[cfg(windows)]
271 {
272 if pid == 0 {
273 return ProcessLiveness::Unknown;
274 }
275 const PROCESS_QUERY_LIMITED_INFORMATION: u32 = 0x1000;
276 const STILL_ACTIVE: u32 = 259;
277 unsafe {
279 let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
280 if handle.is_null() {
281 if std::io::Error::last_os_error().raw_os_error() == Some(ERROR_INVALID_PARAMETER) {
284 return snapshot_liveness(pid);
285 }
286 return ProcessLiveness::Unknown;
287 }
288 let mut code = 0u32;
289 let ok = GetExitCodeProcess(handle, &mut code);
290 CloseHandle(handle);
291 if ok == 0 {
292 ProcessLiveness::Unknown
293 } else if code == STILL_ACTIVE {
294 ProcessLiveness::Alive
295 } else {
296 ProcessLiveness::Dead
297 }
298 }
299 }
300 #[cfg(not(any(unix, windows)))]
301 {
302 let _ = pid;
303 ProcessLiveness::Unknown
304 }
305}
306
307#[cfg(all(feature = "fs", windows))]
308const ERROR_INVALID_PARAMETER: i32 = 87;
309#[cfg(all(feature = "fs", windows))]
310const ERROR_NO_MORE_FILES: i32 = 18;
311#[cfg(all(feature = "fs", windows))]
312const PROCESS_SNAPSHOT_LIMIT: usize = 4096;
313
314#[cfg(all(feature = "fs", windows))]
315#[repr(C)]
316struct ProcessEntry32W {
317 size: u32,
318 usage: u32,
319 process_id: u32,
320 default_heap_id: usize,
321 module_id: u32,
322 threads: u32,
323 parent_process_id: u32,
324 priority_class: i32,
325 flags: u32,
326 executable: [u16; 260],
327}
328
329#[cfg(all(feature = "fs", windows))]
331fn snapshot_liveness_from_pids(pid: u32, pids: &[u32], complete: bool) -> ProcessLiveness {
332 if complete && pids.len() < PROCESS_SNAPSHOT_LIMIT && !pids.contains(&pid) {
333 ProcessLiveness::Dead
334 } else {
335 ProcessLiveness::Unknown
336 }
337}
338
339#[cfg(all(feature = "fs", windows))]
341fn snapshot_liveness(pid: u32) -> ProcessLiveness {
342 const TH32CS_SNAPPROCESS: u32 = 0x0000_0002;
343 let snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
345 if snapshot as isize == -1 {
346 return ProcessLiveness::Unknown;
347 }
348 let mut pids = Vec::with_capacity(64);
349 let mut entry: ProcessEntry32W = unsafe { std::mem::zeroed() };
351 entry.size = std::mem::size_of::<ProcessEntry32W>() as u32;
352 if unsafe { Process32FirstW(snapshot, &mut entry) } == 0 {
354 unsafe { CloseHandle(snapshot) };
356 return ProcessLiveness::Unknown;
357 }
358 let complete = loop {
359 pids.push(entry.process_id);
360 if pids.len() >= PROCESS_SNAPSHOT_LIMIT {
361 break false;
362 }
363 entry.size = std::mem::size_of::<ProcessEntry32W>() as u32;
364 if unsafe { Process32NextW(snapshot, &mut entry) } == 0 {
366 break std::io::Error::last_os_error().raw_os_error() == Some(ERROR_NO_MORE_FILES);
367 }
368 };
369 unsafe { CloseHandle(snapshot) };
371 snapshot_liveness_from_pids(pid, &pids, complete)
372}
373
374#[cfg(all(feature = "fs", windows))]
375#[link(name = "kernel32")]
376unsafe extern "system" {
377 fn OpenProcess(access: u32, inherit: i32, pid: u32) -> *mut std::ffi::c_void;
378 fn GetExitCodeProcess(handle: *mut std::ffi::c_void, code: *mut u32) -> i32;
379 fn CloseHandle(handle: *mut std::ffi::c_void) -> i32;
380 fn CreateToolhelp32Snapshot(flags: u32, process_id: u32) -> *mut std::ffi::c_void;
381 fn Process32FirstW(snapshot: *mut std::ffi::c_void, entry: *mut ProcessEntry32W) -> i32;
382 fn Process32NextW(snapshot: *mut std::ffi::c_void, entry: *mut ProcessEntry32W) -> i32;
383}
384
385#[cfg(feature = "fs")]
390pub fn process_alive(pid: u32) -> bool {
391 !matches!(process_liveness(pid), ProcessLiveness::Dead)
392}