| 232 | } |
| 233 | |
| 234 | cbm_ws_verdict_t cbm_workspace_classify_root(const char *canonical_path, const char *home_dir, |
| 235 | const char *cache_dir) { |
| 236 | if (!canonical_path || !canonical_path[0] || ws_volume_prefix_len(canonical_path) == 0) { |
| 237 | /* A relative or empty path is not a usable root; refuse it the same way |
| 238 | * as a volume root rather than letting it fall through as allowed. */ |
| 239 | return CBM_WS_DENY_ABSOLUTE; |
| 240 | } |
| 241 | |
| 242 | bool windows_style = ws_is_windows_style(canonical_path); |
| 243 | int depth = cbm_workspace_path_depth(canonical_path); |
| 244 | |
| 245 | /* A volume, drive or share root, whatever the platform. */ |
| 246 | if (depth == 0) { |
| 247 | return CBM_WS_DENY_ABSOLUTE; |
| 248 | } |
| 249 | |
| 250 | /* Order matters below, and not for cosmetic reasons. |
| 251 | * |
| 252 | * The home directory normally CONTAINS the cache directory, so testing the |
| 253 | * cache first would report every $HOME as "holds the cache" — and, worse, |
| 254 | * would make it absolutely denied when the design says a person may override |
| 255 | * it. Home is therefore classified first. |
| 256 | * |
| 257 | * Depth comes before the cache test for the same kind of reason: "/Users" is |
| 258 | * both too broad and an ancestor of the cache, and "too broad, name a |
| 259 | * project directory below it" is the reason that actually helps the reader. */ |
| 260 | if (home_dir && home_dir[0] && ws_paths_equal(canonical_path, home_dir)) { |
| 261 | return CBM_WS_DENY_SENSITIVE; |
| 262 | } |
| 263 | |
| 264 | /* Below a drive or a UNC share the first component is already user space |
| 265 | * ("D:/repos", "//srv/share/proj"), so one component is enough there. Below a |
| 266 | * POSIX root it is a system tree, so require two. */ |
| 267 | int min_depth = |
| 268 | (windows_style || ws_is_unc(canonical_path)) ? WS_MIN_DEPTH_WINDOWS : WS_MIN_DEPTH_POSIX; |
| 269 | if (depth < min_depth) { |
| 270 | return CBM_WS_DENY_TOO_SHALLOW; |
| 271 | } |
| 272 | |
| 273 | /* No rule here for "this root contains the cache directory". |
| 274 | * |
| 275 | * An earlier draft refused such roots outright, on the theory that indexing |
| 276 | * them would absorb every other project's graph database. Two things make |
| 277 | * that wrong. The indexer only parses recognised source files, and a graph |
| 278 | * database is binary SQLite it would never extract; and refusing an entire |
| 279 | * root is the wrong remedy even where the concern holds — the right one is to |
| 280 | * not walk the cache. Excluding the cache from discovery is tracked |
| 281 | * separately; classifying the root is not the place for it. |
| 282 | * |
| 283 | * cache_dir stays in the signature because the exclusion work will need it |
| 284 | * and because callers already have it to hand. */ |
| 285 | (void)cache_dir; |
| 286 | |
| 287 | if (ws_any_component_matches(canonical_path, WS_CREDENTIAL_NAMES, |
| 288 | sizeof(WS_CREDENTIAL_NAMES) / sizeof(WS_CREDENTIAL_NAMES[0]), |
| 289 | windows_style)) { |
| 290 | return CBM_WS_DENY_SENSITIVE; |
| 291 | } |
no test coverage detected