LEFT | RIGHT |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """The TAR file entry implementation.""" | 2 """The TAR file entry implementation.""" |
| 3 |
| 4 from __future__ import unicode_literals |
3 | 5 |
4 from dfdatetime import posix_time as dfdatetime_posix_time | 6 from dfdatetime import posix_time as dfdatetime_posix_time |
5 | 7 |
6 from dfvfs.lib import definitions | 8 from dfvfs.lib import definitions |
7 from dfvfs.lib import errors | 9 from dfvfs.lib import errors |
8 from dfvfs.lib import py2to3 | 10 from dfvfs.lib import py2to3 |
9 from dfvfs.path import tar_path_spec | 11 from dfvfs.path import tar_path_spec |
10 from dfvfs.vfs import file_entry | 12 from dfvfs.vfs import file_entry |
11 | 13 |
12 | 14 |
13 class TARDirectory(file_entry.Directory): | 15 class TARDirectory(file_entry.Directory): |
14 """File system directory that uses tarfile.""" | 16 """File system directory that uses tarfile.""" |
15 | 17 |
16 def _EntriesGenerator(self): | 18 def _EntriesGenerator(self): |
17 """Retrieves directory entries. | 19 """Retrieves directory entries. |
18 | 20 |
19 Since a directory can contain a vast number of entries using | 21 Since a directory can contain a vast number of entries using |
20 a generator is more memory efficient. | 22 a generator is more memory efficient. |
21 | 23 |
22 Yields: | 24 Yields: |
23 TARPathSpec: TAR path specification. | 25 TARPathSpec: TAR path specification. |
24 """ | 26 """ |
25 location = getattr(self.path_spec, u'location', None) | 27 location = getattr(self.path_spec, 'location', None) |
26 | 28 |
27 if (location is None or | 29 if (location is None or |
28 not location.startswith(self._file_system.PATH_SEPARATOR)): | 30 not location.startswith(self._file_system.PATH_SEPARATOR)): |
29 return | 31 return |
30 | 32 |
31 # The TAR info name does not have the leading path separator as | 33 # The TAR info name does not have the leading path separator as |
32 # the location string does. | 34 # the location string does. |
33 tar_path = location[1:] | 35 tar_path = location[1:] |
34 | 36 |
35 # Set of top level sub directories that have been yielded. | 37 # Set of top level sub directories that have been yielded. |
(...skipping 25 matching lines...) Expand all Loading... |
61 location, path_segment]) | 63 location, path_segment]) |
62 is_directory = True | 64 is_directory = True |
63 | 65 |
64 else: | 66 else: |
65 path_spec_location = self._file_system.JoinPath([path]) | 67 path_spec_location = self._file_system.JoinPath([path]) |
66 is_directory = tar_info.isdir() | 68 is_directory = tar_info.isdir() |
67 | 69 |
68 if is_directory: | 70 if is_directory: |
69 if path_spec_location in processed_directories: | 71 if path_spec_location in processed_directories: |
70 continue | 72 continue |
71 | |
72 processed_directories.add(path_spec_location) | 73 processed_directories.add(path_spec_location) |
73 | 74 |
74 yield tar_path_spec.TARPathSpec( | 75 yield tar_path_spec.TARPathSpec( |
75 location=path_spec_location, parent=self.path_spec.parent) | 76 location=path_spec_location, parent=self.path_spec.parent) |
76 | 77 |
77 | 78 |
78 class TARFileEntry(file_entry.FileEntry): | 79 class TARFileEntry(file_entry.FileEntry): |
79 """File system file entry that uses tarfile.""" | 80 """File system file entry that uses tarfile.""" |
80 | 81 |
81 TYPE_INDICATOR = definitions.TYPE_INDICATOR_TAR | 82 TYPE_INDICATOR = definitions.TYPE_INDICATOR_TAR |
(...skipping 12 matching lines...) Expand all Loading... |
94 is_virtual (Optional[bool]): True if the file entry is a virtual file | 95 is_virtual (Optional[bool]): True if the file entry is a virtual file |
95 entry emulated by the corresponding file system. | 96 entry emulated by the corresponding file system. |
96 tar_info (Optional[tarfile.TARInfo]): TAR info. | 97 tar_info (Optional[tarfile.TARInfo]): TAR info. |
97 | 98 |
98 Raises: | 99 Raises: |
99 BackEndError: when the TAR info is missing in a non-virtual file entry. | 100 BackEndError: when the TAR info is missing in a non-virtual file entry. |
100 """ | 101 """ |
101 if not is_virtual and tar_info is None: | 102 if not is_virtual and tar_info is None: |
102 tar_info = file_system.GetTARInfoByPathSpec(path_spec) | 103 tar_info = file_system.GetTARInfoByPathSpec(path_spec) |
103 if not is_virtual and tar_info is None: | 104 if not is_virtual and tar_info is None: |
104 raise errors.BackEndError(u'Missing TAR info in non-virtual file entry.') | 105 raise errors.BackEndError('Missing TAR info in non-virtual file entry.') |
105 | 106 |
106 super(TARFileEntry, self).__init__( | 107 super(TARFileEntry, self).__init__( |
107 resolver_context, file_system, path_spec, is_root=is_root, | 108 resolver_context, file_system, path_spec, is_root=is_root, |
108 is_virtual=is_virtual) | 109 is_virtual=is_virtual) |
109 self._tar_info = tar_info | 110 self._tar_info = tar_info |
110 | 111 |
111 if self._is_virtual or self._tar_info.isdir(): | 112 if self._is_virtual or self._tar_info.isdir(): |
112 self._type = definitions.FILE_ENTRY_TYPE_DIRECTORY | 113 self._type = definitions.FILE_ENTRY_TYPE_DIRECTORY |
113 elif self._tar_info.isfile(): | 114 elif self._tar_info.isfile(): |
114 self._type = definitions.FILE_ENTRY_TYPE_FILE | 115 self._type = definitions.FILE_ENTRY_TYPE_FILE |
(...skipping 27 matching lines...) Expand all Loading... |
142 | 143 |
143 def _GetStat(self): | 144 def _GetStat(self): |
144 """Retrieves the stat object. | 145 """Retrieves the stat object. |
145 | 146 |
146 Returns: | 147 Returns: |
147 VFSStat: stat object. | 148 VFSStat: stat object. |
148 """ | 149 """ |
149 stat_object = super(TARFileEntry, self)._GetStat() | 150 stat_object = super(TARFileEntry, self)._GetStat() |
150 | 151 |
151 # File data stat information. | 152 # File data stat information. |
152 stat_object.size = getattr(self._tar_info, u'size', None) | 153 stat_object.size = getattr(self._tar_info, 'size', None) |
153 | 154 |
154 # Ownership and permissions stat information. | 155 # Ownership and permissions stat information. |
155 stat_object.mode = getattr(self._tar_info, u'mode', None) | 156 stat_object.mode = getattr(self._tar_info, 'mode', None) |
156 stat_object.uid = getattr(self._tar_info, u'uid', None) | 157 stat_object.uid = getattr(self._tar_info, 'uid', None) |
157 stat_object.gid = getattr(self._tar_info, u'gid', None) | 158 stat_object.gid = getattr(self._tar_info, 'gid', None) |
158 | 159 |
159 # TODO: implement support for: | 160 # TODO: implement support for: |
160 # stat_object.uname = getattr(self._tar_info, u'uname', None) | 161 # stat_object.uname = getattr(self._tar_info, 'uname', None) |
161 # stat_object.gname = getattr(self._tar_info, u'gname', None) | 162 # stat_object.gname = getattr(self._tar_info, 'gname', None) |
162 | 163 |
163 # File entry type stat information. | 164 # File entry type stat information. |
164 | 165 |
165 # The root file entry is virtual and should have type directory. | 166 # The root file entry is virtual and should have type directory. |
166 | 167 |
167 # TODO: determine if this covers all the types: | 168 # TODO: determine if this covers all the types: |
168 # REGTYPE, AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, CONTTYPE, | 169 # REGTYPE, AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, CONTTYPE, |
169 # CHRTYPE, BLKTYPE, GNUTYPE_SPARSE | 170 # CHRTYPE, BLKTYPE, GNUTYPE_SPARSE |
170 | 171 |
171 # Other stat information. | 172 # Other stat information. |
172 # tar_info.pax_headers | 173 # tar_info.pax_headers |
173 | 174 |
174 return stat_object | 175 return stat_object |
175 | 176 |
176 @property | 177 @property |
177 def name(self): | 178 def name(self): |
178 """str: name of the file entry, which does not include the full path.""" | 179 """str: name of the file entry, which does not include the full path.""" |
179 path = getattr(self.path_spec, u'location', None) | 180 path = getattr(self.path_spec, 'location', None) |
180 if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): | 181 if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): |
181 try: | 182 try: |
182 path = path.decode(self._file_system.encoding) | 183 path = path.decode(self._file_system.encoding) |
183 except UnicodeDecodeError: | 184 except UnicodeDecodeError: |
184 path = None | 185 path = None |
185 return self._file_system.BasenamePath(path) | 186 return self._file_system.BasenamePath(path) |
186 | 187 |
187 @property | 188 @property |
188 def modification_time(self): | 189 def modification_time(self): |
189 """dfdatetime.DateTimeValues: modification time or None if not available.""" | 190 """dfdatetime.DateTimeValues: modification time or None if not available.""" |
190 timestamp = getattr(self._tar_info, u'mtime', None) | 191 timestamp = getattr(self._tar_info, 'mtime', None) |
191 if timestamp is not None: | 192 if timestamp is not None: |
192 return dfdatetime_posix_time.PosixTime(timestamp=timestamp) | 193 return dfdatetime_posix_time.PosixTime(timestamp=timestamp) |
193 | 194 |
194 @property | 195 @property |
195 def sub_file_entries(self): | 196 def sub_file_entries(self): |
196 """generator(TARFileEntry): sub file entries.""" | 197 """generator(TARFileEntry): sub file entries.""" |
197 tar_file = self._file_system.GetTARFile() | 198 tar_file = self._file_system.GetTARFile() |
198 | 199 |
199 if self._directory is None: | 200 if self._directory is None: |
200 self._directory = self._GetDirectory() | 201 self._directory = self._GetDirectory() |
201 | 202 |
202 if self._directory and tar_file: | 203 if self._directory and tar_file: |
203 for path_spec in self._directory.entries: | 204 for path_spec in self._directory.entries: |
204 location = getattr(path_spec, u'location', None) | 205 location = getattr(path_spec, 'location', None) |
205 if location is None: | 206 if location is None: |
206 continue | 207 continue |
207 | 208 |
208 kwargs = {} | 209 kwargs = {} |
209 try: | 210 try: |
210 kwargs[u'tar_info'] = tar_file.getmember(location[1:]) | 211 kwargs['tar_info'] = tar_file.getmember(location[1:]) |
211 except KeyError: | 212 except KeyError: |
212 kwargs[u'is_virtual'] = True | 213 kwargs['is_virtual'] = True |
213 | 214 |
214 yield TARFileEntry( | 215 yield TARFileEntry( |
215 self._resolver_context, self._file_system, path_spec, **kwargs) | 216 self._resolver_context, self._file_system, path_spec, **kwargs) |
216 | 217 |
217 def GetParentFileEntry(self): | 218 def GetParentFileEntry(self): |
218 """Retrieves the parent file entry. | 219 """Retrieves the parent file entry. |
219 | 220 |
220 Returns: | 221 Returns: |
221 TARFileEntry: parent file entry or None. | 222 TARFileEntry: parent file entry or None. |
222 """ | 223 """ |
223 location = getattr(self.path_spec, u'location', None) | 224 location = getattr(self.path_spec, 'location', None) |
224 if location is None: | 225 if location is None: |
225 return | 226 return |
226 | 227 |
227 parent_location = self._file_system.DirnamePath(location) | 228 parent_location = self._file_system.DirnamePath(location) |
228 if parent_location is None: | 229 if parent_location is None: |
229 return | 230 return |
230 | 231 |
231 if parent_location == u'': | 232 if parent_location == '': |
232 parent_location = self._file_system.PATH_SEPARATOR | 233 parent_location = self._file_system.PATH_SEPARATOR |
233 is_root = True | 234 is_root = True |
234 is_virtual = True | 235 is_virtual = True |
235 else: | 236 else: |
236 is_root = False | 237 is_root = False |
237 is_virtual = False | 238 is_virtual = False |
238 | 239 |
239 parent_path_spec = getattr(self.path_spec, u'parent', None) | 240 parent_path_spec = getattr(self.path_spec, 'parent', None) |
240 path_spec = tar_path_spec.TARPathSpec( | 241 path_spec = tar_path_spec.TARPathSpec( |
241 location=parent_location, parent=parent_path_spec) | 242 location=parent_location, parent=parent_path_spec) |
242 return TARFileEntry( | 243 return TARFileEntry( |
243 self._resolver_context, self._file_system, path_spec, is_root=is_root, | 244 self._resolver_context, self._file_system, path_spec, is_root=is_root, |
244 is_virtual=is_virtual) | 245 is_virtual=is_virtual) |
245 | 246 |
246 def GetTARInfo(self): | 247 def GetTARInfo(self): |
247 """Retrieves the TAR info. | 248 """Retrieves the TAR info. |
248 | 249 |
249 Returns: | 250 Returns: |
250 tarfile.TARInfo: TAR info or None if it does not exist. | 251 tarfile.TARInfo: TAR info or None if it does not exist. |
251 | 252 |
252 Raises: | 253 Raises: |
253 ValueError: if the path specification is incorrect. | 254 PathSpecError: if the path specification is incorrect. |
254 """ | 255 """ |
255 if not self._tar_info: | 256 if not self._tar_info: |
256 location = getattr(self.path_spec, u'location', None) | 257 location = getattr(self.path_spec, 'location', None) |
257 if location is None: | 258 if location is None: |
258 raise ValueError(u'Path specification missing location.') | 259 raise errors.PathSpecError('Path specification missing location.') |
259 | 260 |
260 if not location.startswith(self._file_system.LOCATION_ROOT): | 261 if not location.startswith(self._file_system.LOCATION_ROOT): |
261 raise ValueError(u'Invalid location in path specification.') | 262 raise errors.PathSpecError('Invalid location in path specification.') |
262 | 263 |
263 if len(location) == 1: | 264 if len(location) == 1: |
264 return | 265 return |
265 | 266 |
266 tar_file = self._file_system.GetTARFile() | 267 tar_file = self._file_system.GetTARFile() |
267 try: | 268 try: |
268 self._tar_info = tar_file.getmember(location[1:]) | 269 self._tar_info = tar_file.getmember(location[1:]) |
269 except KeyError: | 270 except KeyError: |
270 pass | 271 pass |
271 | 272 |
272 return self._tar_info | 273 return self._tar_info |
LEFT | RIGHT |