1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! # path-lib
//!
//! CROSS-PLATFORM PATHS FOR RUST
//!
//! Where should an application keep its data, config, cache, and logs?
//! The answer differs on every operating system, differs again for a
//! per-user tool versus a machine-wide service, and gets subtly wrong the
//! moment a folder is redirected or an environment variable is missing.
//! `path-lib` answers it once, correctly, with no dependencies.
//!
//! # Application directories
//!
//! ```
//! use path_lib::App;
//!
//! let app = App::new("HiveDB")?; // this user
//! let svc = App::global("HiveDB")?; // the whole machine
//!
//! let data = app.data(); // &Path, resolved once
//! let db = app.data_at("db/main")?; // hardened sub-path
//! # let _ = (svc, data, db);
//! # Ok::<(), path_lib::Error>(())
//! ```
//!
//! | Kind | Linux (user) | macOS (user) | Windows (user) |
//! |-----------|-------------------------------|-----------------------------------------|--------------------------------|
//! | data | `~/.local/share/<app>` | `~/Library/Application Support/<app>` | `%LOCALAPPDATA%\<app>` |
//! | config | `~/.config/<app>` | `~/Library/Preferences/<app>` | `%APPDATA%\<app>` |
//! | cache | `~/.cache/<app>` | `~/Library/Caches/<app>` | `%LOCALAPPDATA%\<app>\cache` |
//! | logs | `~/.local/state/<app>/logs` | `~/Library/Logs/<app>` | `%LOCALAPPDATA%\<app>\logs` |
//! | state | `~/.local/state/<app>` | `.../Application Support/<app>/state` | `%LOCALAPPDATA%\<app>\state` |
//! | runtime | `$XDG_RUNTIME_DIR/<app>` | `.../Application Support/<app>/run` | `%LOCALAPPDATA%\<app>\run` |
//! | temp | `~/.cache/<app>/tmp` | `$TMPDIR/<app>` | `%TEMP%\<app>` |
//! | documents | `~/Documents/<app>` | `~/Documents/<app>` | `Documents\<app>` |
//!
//! | Kind | Linux (global) | macOS (global) | Windows (global) |
//! |-----------|-------------------------|---------------------------------------|--------------------------------|
//! | data | `/var/lib/<app>` | `/Library/Application Support/<app>` | `%ProgramData%\<app>` |
//! | config | `/etc/<app>` | `/Library/Preferences/<app>` | `%ProgramData%\<app>\config` |
//! | cache | `/var/cache/<app>` | `/Library/Caches/<app>` | `%ProgramData%\<app>\cache` |
//! | logs | `/var/log/<app>` | `/Library/Logs/<app>` | `%ProgramData%\<app>\logs` |
//! | state | `/var/lib/<app>/state` | `.../Application Support/<app>/state` | `%ProgramData%\<app>\state` |
//! | runtime | `/run/<app>` | `/var/run/<app>` | `%ProgramData%\<app>\run` |
//! | temp | `/var/tmp/<app>` | `/var/tmp/<app>` | `%ProgramData%\<app>\temp` |
//! | documents | `/srv/<app>` | `/Users/Shared/<app>` | `%PUBLIC%\Documents\<app>` |
//!
//! XDG variables (`XDG_DATA_HOME`, `XDG_CONFIG_HOME`, ...) and
//! `user-dirs.dirs` are honoured on Linux and the BSDs. Windows folders
//! come from the Known Folder API, so OneDrive-redirected Documents
//! resolve correctly. [`App::portable`] puts everything under one folder
//! of your choosing instead.
//!
//! # Hardened sub-paths
//!
//! Every `*_at` accessor, and the free function [`join`], accepts a
//! relative path in either slash style and rejects, before building
//! anything, input that could escape the base directory or that means
//! different things on different systems: `..`, drive letters, control
//! characters, Windows-reserved characters and their Unicode look-alikes,
//! bidirectional overrides, device names such as `CON`, and trailing dots
//! or spaces. For names typed by end users, [`sanitize`] repairs instead
//! of rejecting.
//!
//! ```
//! # let app = path_lib::App::portable("Demo", std::env::temp_dir())?;
//! assert!(app.data_at("/big\\sloppy//floppy/").is_ok());
//! assert!(app.data_at("../../etc/passwd").is_err());
//!
//! let name = path_lib::sanitize("Q3: final?.pdf"); // "Q3_ final_.pdf"
//! assert!(app.documents_at(&name).is_ok());
//! # Ok::<(), path_lib::Error>(())
//! ```
//!
//! # OS folders
//!
//! [`home`], [`documents`], [`desktop`], [`downloads`], [`pictures`],
//! [`music`], [`videos`], [`root`], [`temp`], [`exe`], and [`exe_dir`]
//! return cached `&'static Path` values. [`os()`] is a compile-time
//! constant: the operating system never needs detecting at runtime.
//!
//! # Filesystem operations
//!
//! [`make_dir`], [`make_file`], [`exists`], [`list`], [`remove`],
//! [`copy`], [`move_to`], and [`find`] never overwrite, never follow
//! symbolic links while walking a tree, and refuse to remove or move
//! roots, the home directory, and the user's standard folders. [`App`]
//! exposes the common ones scoped to its directories.
//!
//! # Platform support
//!
//! Linux, macOS, and Windows are tested in CI. FreeBSD and the other
//! BSDs use the Linux (XDG) rules with `/var/run` for global runtime
//! files. Other targets fail to compile with an explanatory message
//! rather than resolving paths that would be wrong.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;