On shared hosting, sometimes the webserver runs as a webserver user. If the webserver creates wiki pages in the directory of the real user without setting file permissions so that others can modify the files, then the real user ends up not being able to change the wiki page files in eir own directory.
Typically, a CGI script would create files using the user's "umask", and so the user may be able to control permissions by telling the webserver what umask to use, or by adding a command to set the umask at the beginning of the CGI script. However, Hatta uses mkstemp, which appears to always create files with no permissions for group or other, regardless of umask. Mercurial appears to leave the permissions as-is. So in this case, Hatta must explicitly change the permissions of each file created by mkstemp.
The following patch creates a module-level "constant", MY_FILE_PERMISSIONS, which determines the permissions of created files.
By default, the patch sets the permissions to 660 (u+rw g+rw).
--- hatta.py.orig Tue Dec 9 06:09:26 2008
+++ hatta.py Tue Dec 9 06:08:29 2008
@@ -52,6 +52,7 @@
import sys
import tempfile
import weakref
+import stat
import werkzeug
os.environ['HGENCODING'] = 'utf-8'
@@ -67,6 +68,7 @@
split_japanese = None
__version__ = '1.1.1-dev'
+MY_FILE_PERMISSIONS = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP
class WikiConfig(object):
# Please see the bottom of the script for modifying these values.
@@ -201,6 +203,11 @@
return (addr.startswith('http://') or addr.startswith('https://')
or addr.startswith('ftp://'))
+def mymkstemp(path):
+ tmpfd, file_name = tempfile.mkstemp(dir=path)
+ os.chmod(file_name, MY_FILE_PERMISSIONS)
+ return tmpfd, file_name
+
class WikiStorage(object):
def __init__(self, path):
self.path = path
@@ -262,7 +269,7 @@
def save_text(self, title, text, author=u'', comment=u''):
try:
- tmpfd, file_name = tempfile.mkstemp(dir=self.path)
+ tmpfd, file_name = mymkstemp(self.path)
f = os.fdopen(tmpfd, "w+b")
f.write(text)
f.close()
@@ -799,7 +806,7 @@
try:
self.load_titles()
self.titles.append(title)
- tmpfd, tmpname = tempfile.mkstemp(dir=self.path)
+ tmpfd, tmpname = mymkstemp(self.path)
f = os.fdopen(tmpfd, "w+b")
pickle.dump(self.titles, f, 2)
f.close()
@@ -1010,7 +1017,7 @@
def close(self, *args, **kw):
return self.f.close(*args, **kw)
- tmpfd, tmpname = tempfile.mkstemp(dir=self.tmppath)
+ tmpfd, tmpname = mymkstemp(self.tmppath)
self.tmpfiles.append(tmpname)
# We need to wrap the file object in order to add an attribute
tmpfile = FileWrapper(os.fdopen(tmpfd, "w+b"))
Thanks for reporting the issue, and great thanks for the patch. It's a good temporary solution, but in the long term I think I should just chmod the files according to umask after they have been renamed – I already have to use a custom rename function.
The great guys at #python have suggested a better approach: use mkdtemp instead of mkstemp and create the new file inside that temporary directory, using normal means that respect umask. – Radomir Dopieralski
The current development version uses mkdtemp instead of mkstemp and creates the files inside the temporary directory with traditional means, respecting the umask.