python / python/cpython

`zipfile`: file type issues

Ouverte
#133,324 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

stdlib type-bug
Langage dominant
Python
Étoiles
77.2k
Forks
35.9k
Métriques de merge des PR
Métriques de PR en attente

Description

Bug report

Bug description:

Hey.

I think there exist a number of issues (which may, depending on how code is used, in principle even be security relevant).

First, AFAIU, ZIP files may contain (at least) regular files, directories (as "standalone" items in the archive, like an empty directory) and symbolic links.

For example using the zip program:

$ mkdir empty
$ zip d.zip empty
  adding: empty/ (stored 0%)
$ ln -s /dev/null bar
$ zip --symlinks  s.zip bar 
  adding: bar (stored 0%)
$

When I open the one with the symlink in Python:

>>> import zipfile

>>> z = zipfile.ZipFile("s.zip", "r")
>>> z.namelist()
['bar']

>>> f = z.open("bar", "r")
>>> f.read()
b'/dev/null'

>>> i = z.getinfo("bar")
>>> i.is_dir()
False

>>> p = zipfile.Path(z, "bar")

>>> p.filename
PosixPath('s.zip/bar')

>>> p.is_dir()
False

>>> p.is_file()
True

>>> p.is_symlink()
True

>>>
  1. It's IMO debatable whether z.open("<symlink>", "r") should succeed or not. IMO zipfile.ZipFile.open() quite clearly is ZIP's open(), but that AFAIK, never opens symlinks but only follows them.
  2. Even if that behaviour is desired (i.e. like a os.readlink() for ZIPs), then it's still completely unexpected and the ZipFile object has no is_symlink()-method ... (only zipfile.Path has such, so one needs to create that first, which seems quite unhandy).
  3. Speaking of which zipfile.Path’s is_dir(), is_file() and is_symlink() functions seem either buggy or semantically inconsistent and/or badly documented.
    Usually, "file" means either any type of file (directory, symlink, device, etc.) or regular files (and sometimes also symlinks if they point to regular files).
    Here, the symlink points to nothing, so it cannot be the latter case. Also - see below - a directory wouldn't return True for is_file(), so the it's not the former either.
    The docs also don't meantion what "file" means.

Now the same with d.zip:

>>> import zipfile
>>> z = zipfile.ZipFile("d.zip", "r")
>>> z.namelist()
['empty/']

>>> f = z.open("empty/", "r")
>>> f.read()
b''

>>> i = archive_file.getinfo("empty/")
>>> i.is_dir()
True

>>> p = zipfile.Path(z,"empty/")
>>> p.filename
PosixPath('d.zip/empty')

>>> p.is_dir()
True

>>> p.is_file()
False

>>> p.is_symlink()
False

>>>
  1. IMO, that zipfile.ZipFile.open() succeeds on a directory (and gives an empty bytes) seems pretty strange at best. It does so even if the directory isn't empty but contains files.
  2. There's also that thing that sometimes that directory pathnames are suffixed by / and sometimes not. Maybe I've missed it but that doesn't seem to be documented, but may be crucial when e.g. matching filenames - and is IMO unexpected.
  3. As mentioned above, is_file() here is False, which would imply that the meaning of that function should be that a file is either a regular file or a regular file or a symbolic link pointing to such.

Cheers,
Chris.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par reproduire les exemples de Python 3.13 avec zipfile.ZipFile.open(), ZipInfo.is_dir() et zipfile.Path.is_dir(), is_file() et is_symlink(). Consultez la documentation et les tests associés de zipfile, puis établissez la sémantique attendue pour les répertoires, les fichiers ordinaires, les liens symboliques et les barres obliques finales avant de définir les critères d’achèvement.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
operating-systems
Type d'issue
Bug
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
À clarifier
Accessibilité débutants
25/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.