8687.15.18
by Karl Fogel
Add the copyright header block to files under lib/canonical/. |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
3 |
|
4 |
__metaclass__ = type |
|
10918.2.1
by Steve Kowalik
Merge in changes for plumbling for poppy-sftp |
5 |
__all__ = [ |
6 |
'UploadFileSystem', |
|
7 |
]
|
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
8 |
|
9 |
import datetime |
|
10 |
import os |
|
11 |
import stat |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
12 |
|
13 |
from zope.interface import implements |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
14 |
from zope.security.interfaces import Unauthorized |
15 |
from zope.server.interfaces.ftp import IFileSystem |
|
16 |
||
17 |
||
18 |
class UploadFileSystem: |
|
19 |
||
20 |
implements(IFileSystem) |
|
21 |
||
22 |
def __init__(self, rootpath): |
|
23 |
self.rootpath = rootpath |
|
24 |
||
25 |
def _full(self, path): |
|
26 |
"""Returns the full path name (i.e. rootpath + path)"""
|
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
27 |
full_path = os.path.join(self.rootpath, path) |
28 |
if not os.path.realpath(full_path).startswith(self.rootpath): |
|
29 |
raise OSError("Path not allowed:", path) |
|
30 |
return full_path |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
31 |
|
32 |
def _sanitize(self, path): |
|
33 |
if path.startswith('/'): |
|
34 |
path = path[1:] |
|
35 |
path = os.path.normpath(path) |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
36 |
return path |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
37 |
|
38 |
def type(self, path): |
|
39 |
"""Return the file type at path
|
|
40 |
||
41 |
The 'type' command returns 'f' for a file, 'd' for a directory and
|
|
42 |
None if there is no file.
|
|
43 |
"""
|
|
44 |
path = self._sanitize(path) |
|
45 |
full_path = self._full(path) |
|
46 |
if os.path.exists(full_path): |
|
47 |
if os.path.isdir(full_path): |
|
48 |
return 'd' |
|
49 |
elif os.path.isfile(full_path): |
|
50 |
return 'f' |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
51 |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
52 |
def names(self, path, filter=None): |
53 |
"""Return a sequence of the names in a directory
|
|
54 |
||
55 |
If the filter is not None, include only those names for which
|
|
56 |
the filter returns a true value.
|
|
57 |
"""
|
|
58 |
path = self._sanitize(path) |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
59 |
full_path = self._full(path) |
60 |
if not os.path.exists(full_path): |
|
61 |
raise OSError("Not exists:", path) |
|
3691.443.23
by Celso Providelo
applying review comments for ppa-poppy. |
62 |
filenames = os.listdir(os.path.join(self.rootpath, path)) |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
63 |
files = [] |
3691.443.23
by Celso Providelo
applying review comments for ppa-poppy. |
64 |
for filename in filenames: |
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
65 |
if not filter or filter(filename): |
3691.443.26
by Celso Providelo
moving poppyinterface file to its right place and also fixed filesystem.txt. |
66 |
files.append(filename) |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
67 |
return files |
68 |
||
69 |
def ls(self, path, filter=None): |
|
3691.443.23
by Celso Providelo
applying review comments for ppa-poppy. |
70 |
"""Return a sequence of information objects.
|
71 |
||
72 |
It considers the names in the given path (returned self.name())
|
|
73 |
and builds file information using self.lsinfo().
|
|
74 |
"""
|
|
3691.443.26
by Celso Providelo
moving poppyinterface file to its right place and also fixed filesystem.txt. |
75 |
return [self.lsinfo(name) for name in self.names(path, filter)] |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
76 |
|
77 |
def readfile(self, path, outstream, start=0, end=None): |
|
78 |
"""Outputs the file at path to a stream.
|
|
79 |
||
10918.2.1
by Steve Kowalik
Merge in changes for plumbling for poppy-sftp |
80 |
Not allowed - see filesystem.txt.
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
81 |
"""
|
82 |
raise Unauthorized |
|
83 |
||
84 |
def lsinfo(self, path): |
|
85 |
"""Return information for a unix-style ls listing for the path
|
|
86 |
||
87 |
See zope3's interfaces/ftp.py:IFileSystem for details of the
|
|
88 |
dictionary's content.
|
|
89 |
"""
|
|
90 |
path = self._sanitize(path) |
|
91 |
full_path = self._full(path) |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
92 |
if not os.path.exists(full_path): |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
93 |
raise OSError("Not exists:", path) |
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
94 |
|
95 |
info = {"owner_name": "upload", |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
96 |
"group_name": "upload", |
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
97 |
"name": path.split("/")[-1]} |
98 |
||
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
99 |
s = os.stat(full_path) |
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
100 |
|
3691.443.23
by Celso Providelo
applying review comments for ppa-poppy. |
101 |
info["owner_readable"] = bool(s.st_mode & stat.S_IRUSR) |
102 |
info["owner_writable"] = bool(s.st_mode & stat.S_IWUSR) |
|
103 |
info["owner_executable"] = bool(s.st_mode & stat.S_IXUSR) |
|
104 |
info["group_readable"] = bool(s.st_mode & stat.S_IRGRP) |
|
105 |
info["group_writable"] = bool(s.st_mode & stat.S_IWGRP) |
|
106 |
info["group_executable"] = bool(s.st_mode & stat.S_IXGRP) |
|
107 |
info["other_readable"] = bool(s.st_mode & stat.S_IROTH) |
|
108 |
info["other_writable"] = bool(s.st_mode & stat.S_IWOTH) |
|
109 |
info["other_executable"] = bool(s.st_mode & stat.S_IXOTH) |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
110 |
info["mtime"] = datetime.datetime.fromtimestamp(self.mtime(path)) |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
111 |
info["size"] = self.size(path) |
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
112 |
info["type"] = self.type(path) |
3691.443.23
by Celso Providelo
applying review comments for ppa-poppy. |
113 |
info["nlinks"] = s.st_nlink |
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
114 |
return info |
115 |
||
116 |
def mtime(self, path): |
|
117 |
"""Return the modification time for the file"""
|
|
118 |
path = self._sanitize(path) |
|
119 |
full_path = self._full(path) |
|
120 |
if os.path.exists(full_path): |
|
121 |
return os.path.getmtime(full_path) |
|
122 |
||
123 |
def size(self, path): |
|
124 |
"""Return the size of the file at path"""
|
|
125 |
path = self._sanitize(path) |
|
126 |
full_path = self._full(path) |
|
127 |
if os.path.exists(full_path): |
|
128 |
return os.path.getsize(full_path) |
|
129 |
||
130 |
def mkdir(self, path): |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
131 |
"""Create a directory."""
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
132 |
path = self._sanitize(path) |
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
133 |
full_path = self._full(path) |
134 |
if os.path.exists(full_path): |
|
135 |
if os.path.isfile(full_path): |
|
136 |
raise OSError("File already exists:", path) |
|
137 |
elif os.path.isdir(full_path): |
|
138 |
raise OSError("Directory already exists:", path) |
|
139 |
raise OSError("OOPS, can't create:", path) |
|
140 |
else: |
|
3691.312.83
by Celso Providelo
Fix poppy to correctly set permissions of PPA uploads according to the multi-user setup used in production (g+rw) |
141 |
old_mask = os.umask(0) |
142 |
try: |
|
143 |
os.makedirs(full_path, 0775) |
|
144 |
finally: |
|
145 |
os.umask(old_mask) |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
146 |
|
147 |
def remove(self, path): |
|
148 |
"""Remove a file."""
|
|
149 |
path = self._sanitize(path) |
|
150 |
full_path = self._full(path) |
|
151 |
if os.path.exists(full_path): |
|
152 |
if os.path.isfile(full_path): |
|
153 |
os.unlink(full_path) |
|
154 |
elif os.path.isdir(full_path): |
|
155 |
raise OSError("Is a directory:", path) |
|
156 |
else: |
|
157 |
raise OSError("Not exists:", path) |
|
158 |
||
159 |
def rmdir(self, path): |
|
160 |
"""Remove a directory.
|
|
161 |
||
3691.444.4
by Celso Providelo
Add a functional test for poppy features. |
162 |
Remove a target path recursively.
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
163 |
"""
|
164 |
path = self._sanitize(path) |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
165 |
full_path = self._full(path) |
166 |
if os.path.exists(full_path): |
|
3691.443.23
by Celso Providelo
applying review comments for ppa-poppy. |
167 |
os.rmdir(full_path) |
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
168 |
else: |
169 |
raise OSError("Not exists:", path) |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
170 |
|
171 |
def rename(self, old, new): |
|
172 |
"""Rename a file."""
|
|
173 |
old = self._sanitize(old) |
|
174 |
new = self._sanitize(new) |
|
175 |
full_old = self._full(old) |
|
176 |
full_new = self._full(new) |
|
177 |
||
178 |
if os.path.isdir(full_new): |
|
179 |
raise OSError("Is a directory:", new) |
|
180 |
||
181 |
if os.path.exists(full_old): |
|
182 |
if os.path.isfile(full_old): |
|
183 |
os.rename(full_old, full_new) |
|
184 |
elif os.path.isdir(full_old): |
|
185 |
raise OSError("Is a directory:", old) |
|
186 |
else: |
|
187 |
raise OSError("Not exists:", old) |
|
188 |
||
189 |
def writefile(self, path, instream, start=None, end=None, append=False): |
|
190 |
"""Write data to a file.
|
|
191 |
||
192 |
See zope3's interfaces/ftp.py:IFileSystem for details of the
|
|
193 |
handling of the various arguments.
|
|
194 |
"""
|
|
195 |
path = self._sanitize(path) |
|
196 |
full_path = self._full(path) |
|
197 |
if os.path.exists(full_path): |
|
198 |
if os.path.isdir(full_path): |
|
199 |
raise OSError("Is a directory:", path) |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
200 |
else: |
201 |
dirname = os.path.dirname(full_path) |
|
202 |
if dirname: |
|
203 |
if not os.path.exists(dirname): |
|
3691.312.83
by Celso Providelo
Fix poppy to correctly set permissions of PPA uploads according to the multi-user setup used in production (g+rw) |
204 |
old_mask = os.umask(0) |
205 |
try: |
|
206 |
os.makedirs(dirname, 0775) |
|
207 |
finally: |
|
208 |
os.umask(old_mask) |
|
3691.444.3
by Celso Providelo
Add directory supporting for poppy: recursive mkdir & rmdir, ls/lsinfo/type and protection for underneath directories. Add also support to automatically creation of directories 'CWD'ed in. Tested with dupload and dput |
209 |
|
1102
by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs |
210 |
if start and start < 0: |
211 |
raise ValueError("Negative start argument:", start) |
|
212 |
if end and end < 0: |
|
213 |
raise ValueError("Negative end argument:", end) |
|
214 |
if start and end and end <= start: |
|
215 |
return
|
|
216 |
if append: |
|
217 |
open_flag = 'a' |
|
218 |
elif start or end: |
|
219 |
open_flag = "r+" |
|
220 |
if not os.path.exists(full_path): |
|
221 |
open(full_path, 'w') |
|
222 |
||
223 |
else: |
|
224 |
open_flag = 'w' |
|
225 |
outstream = open(full_path, open_flag) |
|
226 |
if start: |
|
227 |
outstream.seek(start) |
|
228 |
chunk = instream.read() |
|
229 |
while chunk: |
|
230 |
outstream.write(chunk) |
|
231 |
chunk = instream.read() |
|
232 |
if not end: |
|
233 |
outstream.truncate() |
|
234 |
instream.close() |
|
235 |
outstream.close() |
|
236 |
||
237 |
def writable(self, path): |
|
238 |
"""Return boolean indicating whether a file at path is writable."""
|
|
239 |
path = self._sanitize(path) |
|
240 |
full_path = self._full(path) |
|
241 |
if os.path.exists(full_path): |
|
242 |
if os.path.isfile(full_path): |
|
243 |
return True |
|
244 |
elif os.path.isdir(full_path): |
|
245 |
return False |
|
246 |
else: |
|
247 |
return True |
|
248 |