Beispiel #1
0
    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
Beispiel #2
0
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"
Beispiel #4
0
 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
Beispiel #6
0
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})
Beispiel #7
0
 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()
Beispiel #8
0
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})
Beispiel #9
0
 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()
Beispiel #10
0
    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))
Beispiel #11
0
    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()
Beispiel #12
0
    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)
Beispiel #13
0
 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"
Beispiel #14
0
                # 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)
Beispiel #15
0
                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)
Beispiel #17
0
    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()
Beispiel #18
0
    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)
 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"