Fix path traversal via metadata file_name in folder-based builders

Fix #8324

### Vulnerability

The folder-based builders (`imagefolder`, `audiofolder`, `videofolder`, `pdffolder`) resolve each metadata row's `file_name` by joining it to the metadata file's directory with no containment check. A malicious dataset can set `file_name` to a `../`-traversal path or an absolute path, causing the builder to open and read files outside the dataset directory when the dataset is loaded — arbitrary file read (CWE-22).

### Fix

`FolderBasedBuilder._generate_examples` now rejects, with a `ValueError` naming the offending `file_name`, any value that is absolute or uses `..` traversal to escape the directory containing the metadata file. The validation is performed on the relative reference so it applies uniformly to local dataset directories and to the fsspec URLs used when reading from downloaded archives; `os.path.realpath` / `os.path.commonpath` were deliberately not used on the joined path because those functions are not fsspec-aware (unlike the streaming-patched `os.path.join`) and would corrupt archive URLs such as `zip://...::...`. For genuine local paths, symlinks are additionally resolved and containment is verified with `os.path.commonpath`. The containment root is the metadata file's own directory, matching the existing resolution base and preserving all legitimate relative references into subdirectories.

### Tests

Added regression tests in `tests/packaged_modules/test_folder_based_builder.py`: `../` traversal rejected (three variants, including `subdir/../../` forms), absolute path rejected, and legitimate same-dir / `subdir/` / `./subdir/` references still load. These fail on the pre-fix code and pass with the fix. `test_folder_based_builder.py` (51 passed) and `test_imagefolder.py` (36 passed).

Follows the containment approach of #8303.

*AI assistance (Claude) was used in preparing this change; it was reviewed and verified locally.*



Thanks, both addressed.

**1. `dummy/../../../`:** this is actually already caught — `file_name` is run through `os.path.normpath` before the check, so `dummy/../../../etc/passwd` normalizes to `../../etc/passwd` and is rejected by the existing `..` guard. I added explicit regression tests (`dummy/../../../etc/passwd`, `subdir/../../../../outside/secret.txt`) so it stays that way.

**2. General containment check:** done as you suggested — I split both `downloaded_metadata_dir` and the joined reference on `::` and validate the first component, since a relative `file_name` only ever extends that part (the path inside the archive); the trailing container component(s) must stay identical, which also rejects tampering with the archive path. URL components are normalized with `posixpath` (os.path rewrites `/`→`\` and collapses `//` on Windows); genuine local paths still go through `realpath` + `commonpath` to resolve symlinks. This now runs for all four metadata-dir forms instead of being skipped for URLs:
- `/path/to/local/metadata_dir`
- `hf://path/to/remote/metadata_dir`
- `zip://metadata_dir::/path/to/local/archive.zip`
- `zip://metadata_dir::hf://path/to/remote/archive.zip`

Added a test covering all four (legit relative passes, sibling-dir escape and container tampering rejected), and the existing scheme-rejection and zip-archive loading tests still pass.

(Disclosure: I used AI assistance while preparing this change.)


Hi @lhoestq — I pushed the revision addressing both points: `file_name` values containing a scheme (`file://`, `local://`, etc.) are now rejected outright, and the containment check runs for every metadata-dir form (local, `hf://`, and the two `zip://…::…` chained variants) by splitting on `::` and comparing the relevant path component, with `dummy/../../../` covered by tests. The scheme-rejection, containment, and existing zip-archive tests all pass. Let me know if there's anything else you'd like adjusted.


@lhoestq gentle ping — I pushed the revised version that (1) forbids fsspec schemes in `file_name`, (2) keeps the `dummy/../../../` case covered, and (3) generalizes the containment check across the four metadata-dir forms by splitting on `::` (local, `hf://`, and both `zip://…::…` chained variants), with tests for each. Does that address your concerns, or is there anything else you'd like changed? Happy to iterate.