예제 #1
0
 def has_permission(self, access):
     # From draft23 9.1.2:
     # "For delegation stateids the access mode is based on the type of
     #  delegation"
     if access == OPEN4_SHARE_ACCESS_WRITE and \
             self.deleg_type == OPEN_DELEGATE_READ:
         raise NFS4Error(NFS4ERR_OPENMODE) # Is this the correct error???
예제 #2
0
    def find_conflicts(self, key_template, range):
        """See if range conflicts with any lock not matching template

        Raises error containing info on a conlicting lock if any found.
        """
        def match(template, key):
            for i,j in zip(template, key):
                if i==j or i is None:
                    return True
            return False
        for e in self._tree.itervalues():
            if match(key_template, e.key):
                # Ignore locks in subtree indicated by key
                continue
            for lock in e.locks:
                if range.conflicts(lock):
                    if lock.expired:
                        # STUB - expired always returns False
                        pass
                    # Set up the exception
                    if lock.end == 0xffffffffffffffff:
                        dlength = 0xffffffffffffffff
                    else:
                        dlength = lock.end + 1 - lock.start
                    owner = lock_owner4(e.key[0].clientid, e.key[-1])
                    lock_denied = LOCK4denied(lock.start, dlength,
                                              lock.type, owner)
                    raise NFS4Error(NFS4ERR_DENIED, lock_denied=lock_denied)
예제 #3
0
 def close(self, key): # key = (client, open_owner)
     # client.config.allow_close_with_locks
     if self.types[BYTE].has_locks(key):
         if not client.config.allow_close_with_locks:
             raise NFS4Error(NFS4ERR_LOCKS_HELD)
         self.types[BYTE].remove_locks(key)
     self.types[SHARE].close(key)
     if self.has_no_state():
         # BUG - ignores file locking
         if self.file.fattr4_numlinks == 0:
             self.file.destroy()
예제 #4
0
 def grant_layout(self, state, layoutargs):
     # FIXME
     #if self.waiting > 0 or self.outstanding > 0:
     ## Don't grant layouts while anyone is waiting for a recall
     #   return None
     if self.file.layout_options() == layoutargs.loga_layout_type:
         entry = self.grab_entry(state.key[:1], LayoutEntry)
         layout = self.file.get_layout(layoutargs)
         entry.populate(layout)
         log.debug("GRANTING layout: %s" % layout)
         return layout, entry
     raise NFS4Error(NFS4ERR_LAYOUTUNAVAILABLE)
예제 #5
0
    def overlaps(self, start, end, exact=False):
        """Returns True if given range overlaps that of lock.

        If exact==True, an overlap that does not match the lock range
        exactly raises an error.
        """
        out = start <= self.start <= end or \
              self.start <= start <= self.end
        if out and exact:
            if self.start != start or self.end != end:
                raise NFS4Error(NFS4ERR_LOCK_RANGE)
        return out
예제 #6
0
 def remove_lock(self, type, start, end):
     """Try to remove a lock for the lockowner implicit in self.key."""
     old_lock = ByteLock(type, start, end)
     # Note type is ignored per draft22 18.12.3:
     # "Any legal value for locktype has no effect on the success or
     # failure of the LOCKU operation."
     if POSIXLOCK:
         self.remove_posix_lock(old_lock)
     else:
         try:
             self.locks.remove(old_lock)
         except ValueError:
             raise NFS4Error(NFS4ERR_LOCK_RANGE)
예제 #7
0
    def test_share(self, access, deny=OPEN4_SHARE_DENY_NONE,
                   error=NFS4ERR_SHARE_DENIED, client=None):
        """Check (access, deny) against all current shares.

        Raises error if there is a conflict.
        """
        if access & 3 == 0:
            raise NFS4Error(NFS4ERR_INVAL)
        anon = 0
        if self.anon0.read_count:
            anon |= OPEN4_SHARE_ACCESS_READ
        if self.anon0.write_count:
            anon |= OPEN4_SHARE_ACCESS_WRITE
        self.types[SHARE]._test_share(access, deny, error, anon)
예제 #8
0
 def recall_conflicting_delegations(self, dispatcher, client, access, deny):
     # NOTE OK to have extra access/deny flags
     if not self.conflicts(client, access, deny):
         return
     # Recall everything
     for e in self._tree.itervalues():
         if e.status == NORMAL:
             e.status = CB_INIT
             t = threading.Thread(target=e.initiate_recall,
                                  args=(dispatcher,))
             t.setDaemon(True)
             t.start()
     # We need to release the lock so that delegations can be recalled,
     # which can involve operations like WRITE, LOCK, OPEN, etc,
     # that would otherwise block.  The easiest way to do this is to
     # initiate shut down of this thread.
     raise NFS4Error(NFS4ERR_DELAY)
예제 #9
0
    def _test_share(self, access, deny, error, anon):
        """Check (access, deny) against all current shares.

        Raises error if there is a conflict.
        """
        # OK to use full access/deny
        if self.cache_valid:
            current_access, current_deny = self.cached_access, self.cached_deny
        else:
            # See draft22 9.7
            current_access = current_deny = 0
            for entry in self.itervalues():
                current_access |= entry.share_access
                current_deny |= entry.share_deny
            self.cached_access, self.cached_deny = current_access, current_deny
            self.cache_valid = True
        current_access |= anon
        if access & current_deny or deny & current_access:
            raise NFS4Error(error)
예제 #10
0
 def has_permission(self, access):
     """Verify access against current share"""
     if (not self.share_access) or \
             (access == OPEN4_SHARE_ACCESS_WRITE and
              not (self.share_access & OPEN4_SHARE_ACCESS_WRITE)):
         raise NFS4Error(NFS4ERR_OPENMODE)
예제 #11
0
def find_state(env, stateid, allow_0=True, allow_bypass=False):
    """Find the matching StateTableEntry, and manage its lock."""
    anon = False
    if env.is_ds:
        # STUB - have dataservers ignore stateid (but still do needed locking
        stateid = stateid4(0, DS_MAGIC * 12)
        state = env.cfh.state.types[ANON][(DS_MAGIC, )]
        # Could meddle with state.other here if needed
        anon = True
    # First we convert special stateids, see draft22 8.2.3
    if stateid.other == "\0" * 12:
        if allow_0 and stateid.seqid == 0:
            state = env.cfh.state.anon0
            anon = True
        elif stateid.seqid == 1:
            stateid = env.cid
            # Special stateids must be passed in explicitly
            if stateid in [None, nfs4lib.state00, nfs4lib.state11]:
                raise NFS4Error(NFS4ERR_BAD_STATEID,
                                tag="Current stateid not useable")
        else:
            raise NFS4Error(NFS4ERR_BAD_STATEID)
    elif stateid.other == "\xff" * 12:
        if allow_0 and stateid.seqid == 0xffffffff:
            stateid = nfs4lib.state00 # Needed to pass seqid checks below
            state = (env.cfh.state.anon1 if allow_bypass else env.cfh.state.anon0)
            anon = True
        else:
            raise NFS4Error(NFS4ERR_BAD_STATEID)
    if not anon:
        # Now map stateid to find state
        state = env.session.client.state.get(stateid.other, None)
        if state is None:
            raise NFS4Error(NFS4ERR_BAD_STATEID, tag="stateid not known")
        if state.file != env.cfh:
            raise NFS4Error(NFS4ERR_BAD_STATEID,
                            tag="cfh %r does not match stateid %r" % 
                            (state.file.fh, env.cfh.fh))
    state.lock.acquire()
    # It is possible that while waiting to get the lock, the state has been
    # removed.  In that case, the removal sets the invalid flag.
    if state.invalid:
        state.release()
        raise NFS4Error(NFS4ERR_BAD_STATEID, tag="stateid not known (race)")
    if state.type != LAYOUT:
        # See draft22 8.2.2
        if stateid.seqid != 0 and stateid.seqid != state.seqid:
            old = (stateid.seqid < state.seqid)
            state.lock.release()
            if old:
                raise NFS4Error(NFS4ERR_OLD_STATEID, tag="bad stateid.seqid")
            else:
                raise NFS4Error(NFS4ERR_BAD_STATEID, tag="bad stateid.seqid")
    else:
        # See draft22 12.5.3
        if stateid.seqid == 0:
            state.lock.release()
            raise NFS4Error(NFS4ERR_BAD_STATEID, tag="layout stateid.seqid==0")
    try:
        yield state
    finally:
        state.lock.release()