Traverse zip hierarchy (parents, children and symlinks) starting from this PathInfo. This is called from three places: - When a zip file member is added to ZipFile.filelist, this method populates the ZipPathInfo tree (using create=True). - When ReadableZip
(self, path=None, create=False, follow_symlinks=True)
| 161 | return False |
| 162 | |
| 163 | def resolve(self, path=None, create=False, follow_symlinks=True): |
| 164 | """ |
| 165 | Traverse zip hierarchy (parents, children and symlinks) starting |
| 166 | from this PathInfo. This is called from three places: |
| 167 | |
| 168 | - When a zip file member is added to ZipFile.filelist, this method |
| 169 | populates the ZipPathInfo tree (using create=True). |
| 170 | - When ReadableZipPath.info is accessed, this method is finds a |
| 171 | ZipPathInfo entry for the path without resolving any final symlink |
| 172 | (using follow_symlinks=False) |
| 173 | - When ZipPathInfo methods are called with follow_symlinks=True, this |
| 174 | method resolves any symlink in the final path position. |
| 175 | """ |
| 176 | link_count = 0 |
| 177 | stack = path.split('/')[::-1] if path else [] |
| 178 | info = self |
| 179 | while True: |
| 180 | if info.is_symlink() and (follow_symlinks or stack): |
| 181 | link_count += 1 |
| 182 | if link_count >= 40: |
| 183 | return missing_zip_path_info # Symlink loop! |
| 184 | path = info.zip_file.read(info.zip_info).decode() |
| 185 | stack += path.split('/')[::-1] if path else [] |
| 186 | info = info.parent |
| 187 | |
| 188 | if stack: |
| 189 | name = stack.pop() |
| 190 | else: |
| 191 | return info |
| 192 | |
| 193 | if name == '..': |
| 194 | info = info.parent |
| 195 | elif name and name != '.': |
| 196 | if name not in info.children: |
| 197 | if create: |
| 198 | info.children[name] = ZipPathInfo(info.zip_file, info) |
| 199 | else: |
| 200 | return missing_zip_path_info # No such child! |
| 201 | info = info.children[name] |
| 202 | |
| 203 | |
| 204 | class ZipFileList: |