def _add_item_internally_locked(self, arg): """ See _add_item_internally, this is just internal for locked operation. """ item, revmeta, revdata, revdata_target, itemmeta = arg item_id = make_uuid().hex item_name = item.name name2id = self._name2id try: results = name2id.insert().values(item_id=item_id, item_name=item_name).execute() except IntegrityError: raise ItemAlreadyExistsError("Item '%r' already exists!" % item_name) os.mkdir(self._make_path('meta', item_id)) if revdata is not None: filesys.rename(revdata, revdata_target) if revmeta is not None: rp = self._make_path('meta', item_id, '%d.rev' % 0) filesys.rename(revmeta, rp) if itemmeta: # only write item level metadata file if we have any mp = self._make_path('meta', item_id, 'item') f = open(mp, 'wb') pickle.dump(itemmeta, f, protocol=PICKLEPROTOCOL) f.close() item._fs_item_id = item_id
def move_file(request, pagename, new_pagename, attachment, new_attachment): _ = request.getText newpage = Page(request, new_pagename) if newpage.exists(includeDeleted=1) and request.user.may.write(new_pagename) and request.user.may.delete(pagename): new_attachment_path = os.path.join(getAttachDir(request, new_pagename, create=1), new_attachment).encode(config.charset) attachment_path = os.path.join(getAttachDir(request, pagename), attachment).encode(config.charset) if os.path.exists(new_attachment_path): upload_form(pagename, request, msg=_("Attachment '%(new_pagename)s/%(new_filename)s' already exists.") % { 'new_pagename': new_pagename, 'new_filename': new_attachment}) return if new_attachment_path != attachment_path: # move file filesys.rename(attachment_path, new_attachment_path) _addLogEntry(request, 'ATTDEL', pagename, attachment) _addLogEntry(request, 'ATTNEW', new_pagename, new_attachment) upload_form(pagename, request, msg=_("Attachment '%(pagename)s/%(filename)s' moved to '%(new_pagename)s/%(new_filename)s'.") % { 'pagename': pagename, 'filename': attachment, 'new_pagename': new_pagename, 'new_filename': new_attachment}) else: upload_form(pagename, request, msg=_("Nothing changed")) else: upload_form(pagename, request, msg=_("Page '%(new_pagename)s' does not exist or you don't have enough rights.") % { 'new_pagename': new_pagename})
def test_posix_rename_exists(self): self.makefile(self.src, "src") self.makefile(self.dst, "dst") # posix rename overwrites an existing destination # (on win32, we emulate this behaviour) filesys.rename(self.src, self.dst) dst_contents = open(self.dst).read() assert dst_contents == "src"
def _write_file(self, text, action='SAVE', comment=u'', extra=u''): """ Write the text to the page file (and make a backup of old page). @param text: text to save for this page @rtype: int @return: mtime_usec of new page """ _ = self._ #is_deprecated = self._get_pragmas(text).has_key("deprecated") was_deprecated = self._get_pragmas(self.get_raw_body()).has_key("deprecated") self.copypage() # Write always on the standard directory, never change the # underlay directory copy! pagedir = self.getPagePath(use_underlay=0, check_create=0) revdir = os.path.join(pagedir, 'revisions') cfn = os.path.join(pagedir,'current') clfn = os.path.join(pagedir,'current-locked') # !!! these log objects MUST be created outside the locked area !!! # The local log should be the standard edit log, not the # underlay copy log! pagelog = self.getPagePath('edit-log', use_underlay=0, isfile=1) llog = editlog.EditLog(self.request, filename=pagelog, uid_override=self.uid_override) # Open the global log glog = editlog.EditLog(self.request, uid_override=self.uid_override) if not os.path.exists(pagedir): # new page, create and init pagedir os.mkdir(pagedir) os.chmod(pagedir, 0777 & config.umask) if not os.path.exists(revdir): os.mkdir(revdir) os.chmod(revdir, 0777 & config.umask) f = open(cfn, 'w') f.write('%08d\n' % 0) f.close() os.chmod(cfn, 0666 & config.umask) got_lock= False retry = 0 while not got_lock and retry < 100: retry += 1 try: filesys.rename(cfn, clfn) got_lock = True except OSError, err: got_lock = False if err.errno == 2: # there was no 'current' file time.sleep(0.1) else: raise self.CouldNotLock, _("Page could not get locked. Unexpected error (errno=%d).") % err.errno
def move_file(request, pagename, new_pagename, attachment, new_attachment): _ = request.getText newpage = Page(request, new_pagename) if newpage.exists(includeDeleted=1) and request.user.may.write( new_pagename) and request.user.may.delete(pagename): new_attachment_path = os.path.join( getAttachDir(request, new_pagename, create=1), new_attachment).encode(config.charset) attachment_path = os.path.join(getAttachDir(request, pagename), attachment).encode(config.charset) if os.path.exists(new_attachment_path): upload_form( pagename, request, msg= _("Attachment '%(new_pagename)s/%(new_filename)s' already exists." ) % { 'new_pagename': new_pagename, 'new_filename': new_attachment }) return if new_attachment_path != attachment_path: filesize = os.path.getsize(attachment_path) filesys.rename(attachment_path, new_attachment_path) _addLogEntry(request, 'ATTDEL', pagename, attachment) event = FileRemovedEvent(request, pagename, attachment, filesize) send_event(event) _addLogEntry(request, 'ATTNEW', new_pagename, new_attachment) event = FileAttachedEvent(request, new_pagename, new_attachment, filesize) send_event(event) upload_form( pagename, request, msg= _("Attachment '%(pagename)s/%(filename)s' moved to '%(new_pagename)s/%(new_filename)s'." ) % { 'pagename': pagename, 'filename': attachment, 'new_pagename': new_pagename, 'new_filename': new_attachment }) else: upload_form(pagename, request, msg=_("Nothing changed")) else: upload_form( pagename, request, msg= _("Page '%(new_pagename)s' does not exist or you don't have enough rights." ) % {'new_pagename': new_pagename})
def close(self): """ close cache file (and release lock, if any) """ try: if self._fileobj: self._fileobj.close() self._fileobj = None if 'w' in self._mode: filesys.chmod(self._tmp_fname, 0666 & config.umask) # fix mode that mkstemp chose # this is either atomic or happening with real locks set: filesys.rename(self._tmp_fname, self._fname) finally: if self.locking: self.unlock()
def move_file(request, pagename, new_pagename, attachment, new_attachment): """ move a file attachment from pagename:attachment to new_pagename:new_attachment @param pagename: original pagename @param new_pagename: new pagename (may be same as original pagename) @param attachment: original attachment filename note: attachment filename must not contain a path, use wikiutil.taintfilename() before calling move_file @param new_attachment: new attachment filename (may be same as original filename) note: attachment filename must not contain a path, use wikiutil.taintfilename() before calling move_file """ _ = request.getText newpage = Page(request, new_pagename) if newpage.exists(includeDeleted=1) and request.user.may.write(new_pagename) and request.user.may.delete(pagename): new_attachment_path = os.path.join(getAttachDir(request, new_pagename, create=1), new_attachment).encode(config.charset) attachment_path = os.path.join(getAttachDir(request, pagename), attachment).encode(config.charset) if os.path.exists(new_attachment_path): upload_form(pagename, request, msg=_("Attachment '%(new_pagename)s/%(new_filename)s' already exists.") % { 'new_pagename': new_pagename, 'new_filename': new_attachment}) return if new_attachment_path != attachment_path: filesize = os.path.getsize(attachment_path) filesys.rename(attachment_path, new_attachment_path) _addLogEntry(request, 'ATTDEL', pagename, attachment) event = FileRemovedEvent(request, pagename, attachment, filesize) send_event(event) _addLogEntry(request, 'ATTNEW', new_pagename, new_attachment) event = FileAttachedEvent(request, new_pagename, new_attachment, filesize) send_event(event) upload_form(pagename, request, msg=_("Attachment '%(pagename)s/%(filename)s' moved to '%(new_pagename)s/%(new_filename)s'.") % { 'pagename': pagename, 'filename': attachment, 'new_pagename': new_pagename, 'new_filename': new_attachment}) else: upload_form(pagename, request, msg=_("Nothing changed")) else: upload_form(pagename, request, msg=_("Page '%(new_pagename)s' does not exist or you don't have enough rights.") % { 'new_pagename': new_pagename})
def close(self): """ close cache file (and release lock, if any) """ try: if self._fileobj: self._fileobj.close() self._fileobj = None if 'w' in self._mode: filesys.chmod( self._tmp_fname, 0666 & config.umask) # fix mode that mkstemp chose # this is either atomic or happening with real locks set: filesys.rename(self._tmp_fname, self._fname) finally: if self.locking: self.unlock()
def _destroy_item_locked(self, item): c = cdb.init(self._name_db) maker = cdb.cdbmake(self._name_db + '.ndb', self._name_db + '.tmp') r = c.each() while r: i, v = r if v != item._fs_item_id: maker.add(i, v) r = c.each() maker.finish() filesys.rename(self._name_db + '.ndb', self._name_db) path = os.path.join(self._path, item._fs_item_id) try: shutil.rmtree(path) except OSError, err: raise CouldNotDestroyError("Could not destroy item '%r' [errno: %d]" % ( item.name, err.errno))
def _rename_item_locked(self, arg): item, newname = arg nn = newname.encode('utf-8') npath = os.path.join(self._path, item._fs_item_id, 'name') c = cdb.init(self._name_db) maker = cdb.cdbmake(self._name_db + '.ndb', self._name_db + '.tmp') r = c.each() while r: i, v = r if i == nn: raise ItemAlreadyExistsError("Target item '%r' already exists!" % newname) elif v == item._fs_item_id: maker.add(nn, v) else: maker.add(i, v) r = c.each() maker.finish() filesys.rename(self._name_db + '.ndb', self._name_db) nf = open(npath, mode='wb') nf.write(nn) nf.close()
def update(self, content, encode=False): fname = self._filename() if encode: content = content.encode(config.charset) if self.wlock.acquire(1.0): try: try: # we do not write content to old inode, but to a new file # se we don't need to lock when we just want to read the file # (at least on POSIX, this works) tmp_handle, tmp_fname = tempfile.mkstemp('.tmp', self.key, self.arena_dir) os.write(tmp_handle, content) os.close(tmp_handle) # this is either atomic or happening with real locks set: filesys.rename(tmp_fname, fname) except OSError, err: self.request.log("can't update cache, probably not enough privs") self.request.log("%s" % str(err)) finally: self.wlock.release() else: self.request.log("Can't acquire write lock in %s" % self.lock_dir)
def test_posix_rename_notexists(self): self.makefile(self.src, "src") filesys.rename(self.src, self.dst) dst_contents = open(self.dst).read() assert dst_contents == "src"
# Oops. This item already exists! Clean up and error out. maker.finish() os.unlink(self._name_db + '.ndb') os.rmdir(ipath) if newrev is not None: os.unlink(newrev) raise ItemAlreadyExistsError("Item '%r' already exists!" % item.name) else: maker.add(i, v) r = c.each() maker.add(nn, itemid) maker.finish() if newrev is not None: rp = os.path.join(self._path, itemid, 'rev.0') filesys.rename(newrev, rp) if metadata: # only write metadata file if we have any meta = os.path.join(self._path, itemid, 'meta') f = open(meta, 'wb') pickle.dump(metadata, f, protocol=PICKLEPROTOCOL) f.close() # write 'name' file of item npath = os.path.join(ipath, 'name') nf = open(npath, mode='wb') nf.write(nn) nf.close() # make item retrievable (by putting the name-mapping in place)
pass elif not md: # metadata now empty, just rm the metadata file try: os.unlink(self._make_path('meta', item._fs_item_id, 'item')) except OSError, err: if err.errno != errno.ENOENT: raise # ignore, there might not have been metadata else: tmp = self._make_path('meta', item._fs_item_id, 'item.tmp') f = open(tmp, 'wb') pickle.dump(md, f, protocol=PICKLEPROTOCOL) f.close() filesys.rename(tmp, self._make_path('meta', item._fs_item_id, 'item')) item._fs_metadata_lock.release() del item._fs_metadata_lock def _get_item_metadata(self, item): if item._fs_item_id is not None: p = self._make_path('meta', item._fs_item_id, 'item') try: f = open(p, 'rb') metadata = pickle.load(f) f.close() except IOError, err: if err.errno != errno.ENOENT: raise # no such file means no metadata was stored metadata = {}
self.set_raw_body(text) # reset page object self.reset() # write the editlog entry # for now simply make 2 logs, better would be some multilog stuff maybe if self.do_revision_backup: # do not globally log edits with no revision backup (like /MoinEditorBackup pages) # if somebody edits a deprecated page, log it in global log, but not local log glog.add(self.request, mtime_usecs, rev, action, self.page_name, None, extra, comment) if not was_deprecated and self.do_revision_backup: # if we did not create a new revision number, do not locally log it llog.add(self.request, mtime_usecs, rev, action, self.page_name, None, extra, comment) filesys.rename(clfn, cfn) # add event log entry elog = eventlog.EventLog(self.request) elog.add(self.request, 'SAVEPAGE', {'pagename': self.page_name}, 1, mtime_usecs) return mtime_usecs, rev def saveText(self, newtext, rev, **kw): """ Save new text for a page. @param newtext: text to save for this page @param rev: revision of the page @keyword trivial: trivial edit (default: 0) @keyword extra: extra info field (e.g. for SAVE/REVERT with revno)
def save(self): """ Save user account data to user account file on disk. This saves all member variables, except "id" and "valid" and those starting with an underscore. """ if not self.id: return user_dir = self._cfg.user_dir if not os.path.exists(user_dir): os.makedirs(user_dir) self.last_saved = str(time.time()) # !!! should write to a temp file here to avoid race conditions, # or even better, use locking temp = file(os.path.join(user_dir, 'temp-' + uuid.uuid4().get_hex()), 'w') try: data = codecs.getwriter(config.charset)(temp) data.write("# Data saved '%s' for id '%s'\n" % ( time.strftime(self._cfg.datetime_fmt, time.localtime(time.time())), self.id)) attrs = self.persistent_items() attrs.sort() for key, value in attrs: # Encode list values if isinstance(value, list): key += '[]' value = encodeList(value) # Encode dict values elif isinstance(value, dict): key += '{}' value = encodeDict(value) line = u"%s=%s" % (key, unicode(value)) line = line.replace('\n', ' ').replace('\r', ' ') # no lineseps data.write(line + '\n') # atomically put it in place (except on windows) filesys.rename(temp.name, self.__filename()) except IOError as err: _ = self._request.getText # throw a nicer exception if err.errno == errno.ENOSPC: raise SaveError( _("Cannot save user %s, no storage space left.") % self.name) else: raise SaveError( _("An I/O error occurred while saving user %s (errno=%d)")\ % (self.name, err.errno)) finally: try: os.remove(temp.name) except: pass # we don't care for errors in the os.remove finally: temp.close() if not self.disabled: self.valid = 1 self.updateLookupCaches() if not self._stored: self._stored = True event = events.UserCreatedEvent(self._request, self) events.send_event(event) # update page subscriber's cache after saving user preferences self.updatePageSubCache()
def _write_file(self, text, action='SAVE', comment=u'', extra=u''): """ Write the text to the page file (and make a backup of old page). @param text: text to save for this page @rtype: int @return: mtime_usec of new page """ _ = self._ #is_deprecated = self._get_pragmas(text).has_key("deprecated") was_deprecated = self._get_pragmas(self.get_raw_body()).has_key("deprecated") self.copypage() # Write always on the standard directory, never change the # underlay directory copy! pagedir = self.getPagePath(use_underlay=0, check_create=0) revdir = os.path.join(pagedir, 'revisions') cfn = os.path.join(pagedir,'current') clfn = os.path.join(pagedir,'current-locked') # !!! these log objects MUST be created outside the locked area !!! # The local log should be the standard edit log, not the # underlay copy log! pagelog = self.getPagePath('edit-log', use_underlay=0, isfile=1) llog = editlog.EditLog(self.request, filename=pagelog, uid_override=self.uid_override) # Open the global log glog = editlog.EditLog(self.request, uid_override=self.uid_override) if not os.path.exists(pagedir): # new page, create and init pagedir os.mkdir(pagedir) os.chmod(pagedir, 0777 & config.umask) if not os.path.exists(revdir): os.mkdir(revdir) os.chmod(revdir, 0777 & config.umask) f = open(cfn, 'w') f.write('%08d\n' % 0) f.close() os.chmod(cfn, 0666 & config.umask) got_lock = False retry = 0 try: while not got_lock and retry < 100: retry += 1 try: filesys.rename(cfn, clfn) got_lock = True except OSError, err: got_lock = False if err.errno == 2: # there was no 'current' file time.sleep(0.1) else: raise self.CouldNotLock, _("Page could not get locked. Unexpected error (errno=%d).") % err.errno if not got_lock: raise self.CouldNotLock, _("Page could not get locked. Missing 'current' file?") # increment rev number of current(-locked) page f = open(clfn) revstr = f.read() f.close() rev = int(revstr) if not was_deprecated: if self.do_revision_backup or rev == 0: rev += 1 revstr = '%08d' % rev f = open(clfn, 'w') f.write(revstr+'\n') f.close() # save to page file pagefile = os.path.join(revdir, revstr) f = codecs.open(pagefile, 'wb', config.charset) # Write the file using text/* mime type f.write(self.encodeTextMimeType(text)) f.close() os.chmod(pagefile, 0666 & config.umask) mtime_usecs = wikiutil.timestamp2version(os.path.getmtime(pagefile)) # set in-memory content self.set_raw_body(text) # reset page object self.reset() # write the editlog entry # for now simply make 2 logs, better would be some multilog stuff maybe if self.do_revision_backup: # do not globally log edits with no revision backup (like /MoinEditorBackup pages) # if somebody edits a deprecated page, log it in global log, but not local log glog.add(self.request, mtime_usecs, rev, action, self.page_name, None, extra, comment) if not was_deprecated and self.do_revision_backup: # if we did not create a new revision number, do not locally log it llog.add(self.request, mtime_usecs, rev, action, self.page_name, None, extra, comment)