Example #1
0
def get_thread_name():
    """
  <Purpose>
    Returns a string identifier for the currently executing thread.
    This identifier is unique to this thread.

  <Arguments>
    None.

  <Exceptions>
    None.

  <Side Effects>
    None.

  <Returns>
    A string identifier.
  """

    # Check if this is allows
    restrictions.assertisallowed('get_thread_name')

    # Get the thread object
    tobj = threading.currentThread()

    # Return the name
    return tobj.getName()
Example #2
0
def get_thread_name():
  """
  <Purpose>
    Returns a string identifier for the currently executing thread.
    This identifier is unique to this thread.

  <Arguments>
    None.

  <Exceptions>
    None.

  <Side Effects>
    None.

  <Returns>
    A string identifier.
  """

  # Check if this is allows
  restrictions.assertisallowed('get_thread_name')

  # Get the thread object
  tobj = threading.currentThread()

  # Return the name
  return tobj.getName()
Example #3
0
    def flush(self):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.flush")

        if "w" in self.mode:
            return fileinfo[myfilehandle]["fobj"].flush()
        else:
            return None
Example #4
0
  def write(self, writeitem):
    restrictions.assertisallowed('log.write', writeitem)
    # block if already over
    nanny.tattle_quantity('lograte', 0)

    # do the actual write
    loggingrepy_core.flush_logger_core.write(self, writeitem)

    # block if over after log write
    writeamt = len(str(writeitem))
    nanny.tattle_quantity('lograte', writeamt)
Example #5
0
    def next(self):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.next")

        if "w" in self.mode:
            raise IOError("file.next() is invalid for write-enabled files.")

        # wait if it's already over used
        nanny.tattle_quantity("fileread", 0)

        readdata = fileinfo[myfilehandle]["fobj"].next()

        nanny.tattle_quantity("fileread", len(readdata))

        return readdata
Example #6
0
    def readline(self, *args):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.readline", *args)

        # wait if it's already over used
        nanny.tattle_quantity("fileread", 0)

        try:
            readdata = fileinfo[myfilehandle]["fobj"].readline(*args)
        except KeyError:
            raise ValueError("Invalid file object (probably closed).")

        nanny.tattle_quantity("fileread", len(readdata))

        return readdata
Example #7
0
def settimer(waittime, function, args):
    """
   <Purpose>
      Allow the current event to set an event to be performed in the future.
      This does not guarantee the event will be triggered at that time, only
      that it will be triggered after that time.

   <Arguments>
      waittime:
         The minimum amount of time to wait before delivering the event
      function:
         The function to call
      args:
         The arguments to pass to the function.   This should be a tuple or 
         list

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      A timer handle, for use with canceltimer
  """
    restrictions.assertisallowed('settimer', waittime)

    eventhandle = generate_eventhandle()

    nanny.tattle_add_item('events', eventhandle)

    tobj = threading.Timer(waittime, functionwrapper,
                           [function] + [eventhandle] + [args])

    # Set the name of the thread
    tobj.setName(idhelper.get_new_thread_name(EVENT_PREFIX))

    timerinfo[eventhandle] = {'timer': tobj}

    # Check if we get an exception trying to create a new thread
    try:
        # start the timer
        tobj.start()
    except thread.error, exp:
        # Set exit code 56, which stands for a Threading Error
        # The Node manager will detect this and handle it
        harshexit.harshexit(56)
Example #8
0
def settimer(waittime, function, args):
  """
   <Purpose>
      Allow the current event to set an event to be performed in the future.
      This does not guarantee the event will be triggered at that time, only
      that it will be triggered after that time.

   <Arguments>
      waittime:
         The minimum amount of time to wait before delivering the event
      function:
         The function to call
      args:
         The arguments to pass to the function.   This should be a tuple or 
         list

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      A timer handle, for use with canceltimer
  """
  restrictions.assertisallowed('settimer',waittime)
  
  eventhandle = generate_eventhandle()

  nanny.tattle_add_item('events',eventhandle)

  tobj = threading.Timer(waittime,functionwrapper,[function] + [eventhandle] + [args])

  # Set the name of the thread
  tobj.setName(idhelper.get_new_thread_name(EVENT_PREFIX))

  timerinfo[eventhandle] = {'timer':tobj}
  
  # Check if we get an exception trying to create a new thread
  try:
    # start the timer
    tobj.start()
  except thread.error, exp:
    # Set exit code 56, which stands for a Threading Error
    # The Node manager will detect this and handle it
    harshexit.harshexit(56)
Example #9
0
def randomfloat():
  """
   <Purpose>
     Return a random number in the range [0.0, 1.0) using sources 
     provided by the operating system (such as /dev/urandom on Unix or
     CryptGenRandom on Windows).

   <Arguments>
     None

   <Exceptions>
     None

   <Side Effects>
     This function is metered because it may involve using a hardware
     source of randomness.
     
     If os.urandom raises a NotImplementedError then we will log the
     exception as interalerror and a harshexit will occur. A machine
     that raised this exception has not been observed but it is best
     that the problemed be logged. os.urandom will raise the exception
     if a source of OS-specific random numbers is not found.

   <Returns>
     The number (a float)

  """

  restrictions.assertisallowed('randomfloat')
  nanny.tattle_quantity('random',1)
  
  # If an OS-specific source of randomness is not a found
  # a NotImplementedError would be raised. 
  # Anthony - a NotImplementedError will be logged as an internal
  # error so that we will hopefully be able to identify the system,
  # the exception is not passed on because the problem was not
  # caused by the user. The exit code 217 was chosen to be
  # unique from all other exit calls in repy.
  # Get 56 bits of random data
  try:
    randombytes = os.urandom(7)
  except NotImplementedError, e:
    tracebackrepy.handle_internalerror("os.urandom is not implemented " + \
        "(Exception was: %s)" % e.message, 217)
Example #10
0
def randomfloat():
    """
   <Purpose>
     Return a random number in the range [0.0, 1.0) using sources 
     provided by the operating system (such as /dev/urandom on Unix or
     CryptGenRandom on Windows).

   <Arguments>
     None

   <Exceptions>
     None

   <Side Effects>
     This function is metered because it may involve using a hardware
     source of randomness.
     
     If os.urandom raises a NotImplementedError then we will log the
     exception as interalerror and a harshexit will occur. A machine
     that raised this exception has not been observed but it is best
     that the problemed be logged. os.urandom will raise the exception
     if a source of OS-specific random numbers is not found.

   <Returns>
     The number (a float)

  """

    restrictions.assertisallowed('randomfloat')
    nanny.tattle_quantity('random', 1)

    # If an OS-specific source of randomness is not a found
    # a NotImplementedError would be raised.
    # Anthony - a NotImplementedError will be logged as an internal
    # error so that we will hopefully be able to identify the system,
    # the exception is not passed on because the problem was not
    # caused by the user. The exit code 217 was chosen to be
    # unique from all other exit calls in repy.
    # Get 56 bits of random data
    try:
        randombytes = os.urandom(7)
    except NotImplementedError, e:
        tracebackrepy.handle_internalerror("os.urandom is not implemented " + \
            "(Exception was: %s)" % e.message, 217)
Example #11
0
def canceltimer(timerhandle):
  """
   <Purpose>
      Cancels a timer.

   <Arguments>
      timerhandle:
         The handle of the timer that should be stopped.   Handles are 
         returned by settimer

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      If False is returned, the timer already fired or was cancelled 
      previously.   If True is returned, the timer was cancelled
  """

  restrictions.assertisallowed('canceltimer')

  # Armon: Check that the given handle is valid
  if not is_valid_eventhandle(timerhandle):
    raise Exception("Invalid timer handle specified!")

  try:
    timerinfo[timerhandle]['timer'].cancel()
  except KeyError:
    # The timer already fired (or was cancelled)
    return False

  try:
    del timerinfo[timerhandle]
  except KeyError:
    # The timer just fired (or was cancelled)
    return False
  else:
    # I was able to delete the entry, the function will abort.   I can remove
    # the event
    nanny.tattle_remove_item('events',timerhandle)
    return True
Example #12
0
def canceltimer(timerhandle):
    """
   <Purpose>
      Cancels a timer.

   <Arguments>
      timerhandle:
         The handle of the timer that should be stopped.   Handles are 
         returned by settimer

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      If False is returned, the timer already fired or was cancelled 
      previously.   If True is returned, the timer was cancelled
  """

    restrictions.assertisallowed('canceltimer')

    # Armon: Check that the given handle is valid
    if not is_valid_eventhandle(timerhandle):
        raise Exception("Invalid timer handle specified!")

    try:
        timerinfo[timerhandle]['timer'].cancel()
    except KeyError:
        # The timer already fired (or was cancelled)
        return False

    try:
        del timerinfo[timerhandle]
    except KeyError:
        # The timer just fired (or was cancelled)
        return False
    else:
        # I was able to delete the entry, the function will abort.   I can remove
        # the event
        nanny.tattle_remove_item('events', timerhandle)
        return True
Example #13
0
    def write(self, writeitem):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.write", writeitem)

        # wait if it's already over used
        nanny.tattle_quantity("filewrite", 0)

        if "w" in self.mode:
            try:
                retval = fileinfo[myfilehandle]["fobj"].write(writeitem)
            except KeyError:
                raise ValueError("Invalid file object (probably closed).")
        else:
            raise ValueError("write() isn't allowed on read-only file objects!")

        writeamt = len(str(writeitem))
        nanny.tattle_quantity("filewrite", writeamt)

        return retval
Example #14
0
    def writelines(self, writelist):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.writelines", writelist)

        # wait if it's already over used
        nanny.tattle_quantity("filewrite", 0)

        if "w" not in self.mode:
            raise ValueError("writelines() isn't allowed on read-only file objects!")

        try:
            fh = fileinfo[myfilehandle]["fobj"]
        except KeyError:
            raise ValueError("Invalid file object (probably closed).")

        for writeitem in writelist:
            strtowrite = str(writeitem)
            fileinfo[myfilehandle]["fobj"].write(strtowrite)
            nanny.tattle_quantity("filewrite", len(strtowrite))

        return None  # python documentation states there is no return value
Example #15
0
    def close(self):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.close")

        # Ignore multiple closes (as file does)
        if myfilehandle not in fileinfo:
            return

        nanny.tattle_remove_item("filesopened", myfilehandle)

        fileinfolock.acquire()
        try:
            returnvalue = fileinfo[myfilehandle]["fobj"].close()

            # delete the filehandle
            del fileinfo[myfilehandle]

        finally:
            fileinfolock.release()

        return returnvalue
Example #16
0
def listdir():
    """
   <Purpose>
      Allows the user program to get a list of files in their area.

   <Arguments>
      None

   <Exceptions>
      This probably shouldn't raise any errors / exceptions so long as the
      node manager isn't buggy.

   <Side Effects>
      None

   <Returns>
      A list of strings (file names)
  """

    restrictions.assertisallowed("listdir")

    return os.listdir(".")
Example #17
0
def removefile(filename):
    """
   <Purpose>
      Allows the user program to remove a file in their area.

   <Arguments>
      filename: the name of the file to remove.   It must not contain 
      characters other than 'a-zA-Z0-9.-_' and cannot be '.' or '..'

   <Exceptions>
      An exception is raised if the file does not exist

   <Side Effects>
      None

   <Returns>
      None
  """

    restrictions.assertisallowed("removefile")

    _assert_is_allowed_filename(filename)

    # Problem notification thanks to Andrei Borac
    # Handle the case where the file is open via an exception to prevent the user
    # from removing a file to circumvent resource accounting

    fileinfolock.acquire()
    try:
        for filehandle in fileinfo:
            if filename == fileinfo[filehandle]["filename"]:
                raise Exception, 'File "' + filename + '" is open with handle "' + filehandle + '"'

        result = os.remove(filename)
    finally:
        fileinfolock.release()

    return result
Example #18
0
    def read(self, *args):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.read", *args)

        # basic sanity checking of input
        if len(args) > 1:
            raise TypeError("read() takes at most 1 argument")

        if len(args) == 1 and type(args[0]) != int:
            raise TypeError("file.read() expects an integer argument")

        # wait if it's already over used
        nanny.tattle_quantity("fileread", 0)

        try:
            readdata = fileinfo[myfilehandle]["fobj"].read(*args)
        except KeyError:
            raise ValueError("Invalid file object (probably closed).")

        nanny.tattle_quantity("fileread", len(readdata))

        return readdata
Example #19
0
def getlock():
    """
   <Purpose>
      Returns a lock object to the user program.    A lock object supports
      two functions: acquire and release.   See threading.Lock() for details

   <Arguments>
      None.

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      The lock object.
  """

    restrictions.assertisallowed('getlock')

    # I'm a little worried about this, but it should be safe.
    return threading.Lock()
Example #20
0
def getlock():
  """
   <Purpose>
      Returns a lock object to the user program.    A lock object supports
      two functions: acquire and release.   See threading.Lock() for details

   <Arguments>
      None.

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      The lock object.
  """

  restrictions.assertisallowed('getlock')

  # I'm a little worried about this, but it should be safe.
  return threading.Lock()
Example #21
0
def getruntime():
  """
   <Purpose>
      Return the amount of time the program has been running.   This is in
      wall clock time.   This function is not guaranteed to always return
      increasing values due to NTP, etc.

   <Arguments>
      None

   <Exceptions>
      None.

   <Side Effects>
      None

   <Remarks>
      Accurate granularity not guaranteed past 1 second.

   <Returns>
      The elapsed time as float
  """
  restrictions.assertisallowed('getruntime')
  return nonportable.getruntime()
Example #22
0
def getruntime():
    """
   <Purpose>
      Return the amount of time the program has been running.   This is in
      wall clock time.   This function is not guaranteed to always return
      increasing values due to NTP, etc.

   <Arguments>
      None

   <Exceptions>
      None.

   <Side Effects>
      None

   <Remarks>
      Accurate granularity not guaranteed past 1 second.

   <Returns>
      The elapsed time as float
  """
    restrictions.assertisallowed('getruntime')
    return nonportable.getruntime()
Example #23
0
def sleep(seconds):
  """
   <Purpose>
      Allow the current event to pause execution (similar to time.sleep()).
      This function will not return early for any reason

   <Arguments>
      seconds:
         The number of seconds to sleep.   This can be a floating point value

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      None.
  """

  restrictions.assertisallowed('sleep',seconds)
  
  # Use the do_sleep implementation in misc
  misc.do_sleep(seconds)
Example #24
0
def sleep(seconds):
    """
   <Purpose>
      Allow the current event to pause execution (similar to time.sleep()).
      This function will not return early for any reason

   <Arguments>
      seconds:
         The number of seconds to sleep.   This can be a floating point value

   <Exceptions>
      None.

   <Side Effects>
      None.

   <Returns>
      None.
  """

    restrictions.assertisallowed('sleep', seconds)

    # Use the do_sleep implementation in misc
    misc.do_sleep(seconds)
Example #25
0
def exitall():
    """
   <Purpose>
      Allows the user program to stop execution of the program without
      passing an exit event to the main program. 

   <Arguments>
      None.

   <Exceptions>
      None.

   <Side Effects>
      Interactions with timers and connection / message receiving functions 
      are undefined.   These functions may be called after exit and may 
      have undefined state.

   <Returns>
      None.   The current thread does not resume after exit
  """

    restrictions.assertisallowed('exitall')

    harshexit.harshexit(200)
Example #26
0
def exitall():
  """
   <Purpose>
      Allows the user program to stop execution of the program without
      passing an exit event to the main program. 

   <Arguments>
      None.

   <Exceptions>
      None.

   <Side Effects>
      Interactions with timers and connection / message receiving functions 
      are undefined.   These functions may be called after exit and may 
      have undefined state.

   <Returns>
      None.   The current thread does not resume after exit
  """

  restrictions.assertisallowed('exitall')

  harshexit.harshexit(200)
Example #27
0
    def __init__(self, filename, mode="r", create=False):
        """
     <Purpose>
        Allows the user program to open a file safely.   This function is not
        meant to resemble the builtin "open".

     <Arguments>
        filename:
           The file that should be operated on
        mode:
           The mode:
              "r":  Open the file for reading.
              "rw": Open the file for reading and writing.

              These are the only valid modes accepted by this version of
              open(). Note: files are always opened in "binary" mode.
        create:
           If True, create the file if it doesn't exist already.

     <Exceptions>
        As with open, this may raise a number of errors. Additionally:

        ValueError is raised if this is passed an invalid mode.

     <Side Effects>
        Opens a file on disk, using a file descriptor.

     <Returns>
        A file-like object 
    """

        # Only allow 'r' and 'rw'.

        actual_mode = None
        if mode == "r":
            actual_mode = "rb"
        elif mode == "rw":
            actual_mode = "r+b"

        if actual_mode is None:
            raise ValueError("Valid modes for opening a file in repy are 'r' and 'rw'.")

        restrictions.assertisallowed("file.__init__", filename, actual_mode)

        # Here we are checking that we only open a given file once in 'write' mode
        # so that file access is more uniform across platforms. (On Microsoft
        # Windows, for example, writing to the same file from two different file-
        # handles throws an error because of the way Windows (by default) locks
        # files opened for writing.)
        fileinfolock.acquire()

        try:
            # Check the entire fileinfo dictionary for the same file already being
            # open.
            for fileinfokey in fileinfo.keys():

                # If the filename matches this one, raise an exception.
                if os.path.abspath(fileinfo[fileinfokey]["filename"]) == os.path.abspath(filename):
                    raise ValueError("A file is only allowed to have one open filehandle.")

            _assert_is_allowed_filename(filename)

            # If the file doesn't exist and the create flag was passed, create the
            # file first.
            if create and not os.path.exists(filename):
                # Create a file by opening it in write mode and then closing it.
                restrictions.assertisallowed("file.__init__", filename, "wb")

                # Allocate a resource.
                try:
                    nanny.tattle_add_item("filesopened", self.filehandle)
                except Exception:
                    # Ok, maybe we can free up a file by garbage collecting.
                    gc.collect()
                    nanny.tattle_add_item("filesopened", self.filehandle)

                # Create the file, and then free up the resource.
                created_file = myfile(filename, "wb")
                created_file.close()
                nanny.tattle_remove_item("filesopened", self.filehandle)

            self.filehandle = idhelper.getuniqueid()

            # Here is where we try to allocate a "file" resource from the
            # nanny system. If that fails, we garbage collect and try again
            # (this forces __del__() methods to be called on objects with
            # no references, which is how we automatically free up
            # file resources).
            try:
                nanny.tattle_add_item("filesopened", self.filehandle)
            except Exception:
                # Ok, maybe we can free up a file by garbage collecting.
                gc.collect()
                nanny.tattle_add_item("filesopened", self.filehandle)

            fileinfo[self.filehandle] = {
                "filename": filename,
                "mode": actual_mode,
                "fobj": myfile(filename, actual_mode),
            }
            self.name = filename
            self.mode = mode

        finally:
            fileinfolock.release()
Example #28
0
def get_VirtualNamespace(code, name="<string>"):
    # Check if this is allows
    restrictions.assertisallowed('VirtualNamespace')

    return VirtualNamespace(code, name)
Example #29
0
def get_VirtualNamespace(code, name="<string>"):
  # Check if this is allows
  restrictions.assertisallowed('VirtualNamespace')

  return VirtualNamespace(code,name)
Example #30
0
def emulated_open(filename, mode="rb"):
  """
   <Purpose>
      Allows the user program to open a file safely. This function is meant
      to resemble the builtin "open".

   <Arguments>
      filename:
         The file that should be operated on.
      mode:
         The mode (see open).

   <Exceptions>
      As with open, this may raise a number of errors. Additionally:

      TypeError if the mode is not a string.
      ValueError if the modestring is invalid.

   <Side Effects>
      Opens a file on disk, using a file descriptor. When opened with "w"
      it will truncate the existing file.

   <Returns>
      A file-like object.
  """

  if type(mode) is not str:
    raise TypeError("Attempted to open file with invalid mode (must be a string).")

  restrictions.assertisallowed('open', filename, mode)

  # We just filter out 'b' / 't' in modestrings because emulated_file opens
  # everything in binary mode for us.

  originalmode = mode

  if 'b' in mode:
    mode = mode.replace('b','')

  if 't' in mode:
    mode = mode.replace('t','')

  # Now we use our very safe, cross-platform open-like function and other
  # file-object methods to emulate ANSI file modes.

  file_object = None
  if mode == "r":
    file_object = emulated_file(filename, "r")

  elif mode == "r+":
    file_object = emulated_file(filename, "rw")

  elif mode == "w" or mode == "w+":
    file_object = emulated_file(filename, "rw", create=True)
    fileinfo[file_object.filehandle]['fobj'].truncate()

  elif mode == "a" or mode == "a+":
    file_object = emulated_file(filename, "rw", create=True)
    file_object.seek(0, os.SEEK_END)


  if file_object is None:
    raise ValueError("Invalid or unsupported mode ('%s') passed to open()." % originalmode)

  return file_object
Example #31
0
def emulated_open(filename, mode="rb"):
    """
   <Purpose>
      Allows the user program to open a file safely. This function is meant
      to resemble the builtin "open".

   <Arguments>
      filename:
         The file that should be operated on.
      mode:
         The mode (see open).

   <Exceptions>
      As with open, this may raise a number of errors. Additionally:

      TypeError if the mode is not a string.
      ValueError if the modestring is invalid.

   <Side Effects>
      Opens a file on disk, using a file descriptor. When opened with "w"
      it will truncate the existing file.

   <Returns>
      A file-like object.
  """

    if type(mode) is not str:
        raise TypeError("Attempted to open file with invalid mode (must be a string).")

    restrictions.assertisallowed("open", filename, mode)

    # We just filter out 'b' / 't' in modestrings because emulated_file opens
    # everything in binary mode for us.

    originalmode = mode

    if "b" in mode:
        mode = mode.replace("b", "")

    if "t" in mode:
        mode = mode.replace("t", "")

    # Now we use our very safe, cross-platform open-like function and other
    # file-object methods to emulate ANSI file modes.

    file_object = None
    if mode == "r":
        file_object = emulated_file(filename, "r")

    elif mode == "r+":
        file_object = emulated_file(filename, "rw")

    elif mode == "w" or mode == "w+":
        file_object = emulated_file(filename, "rw", create=True)
        fileinfo[file_object.filehandle]["fobj"].truncate()

    elif mode == "a" or mode == "a+":
        file_object = emulated_file(filename, "rw", create=True)
        file_object.seek(0, os.SEEK_END)

    if file_object is None:
        raise ValueError("Invalid or unsupported mode ('%s') passed to open()." % originalmode)

    return file_object
Example #32
0
  def __init__(self, filename, mode="r", create=False):
    """
     <Purpose>
        Allows the user program to open a file safely.   This function is not
        meant to resemble the builtin "open".

     <Arguments>
        filename:
           The file that should be operated on
        mode:
           The mode:
              "r":  Open the file for reading.
              "rw": Open the file for reading and writing.

              These are the only valid modes accepted by this version of
              open(). Note: files are always opened in "binary" mode.
        create:
           If True, create the file if it doesn't exist already.

     <Exceptions>
        As with open, this may raise a number of errors. Additionally:

        ValueError is raised if this is passed an invalid mode.

     <Side Effects>
        Opens a file on disk, using a file descriptor.

     <Returns>
        A file-like object 
    """

    # Only allow 'r' and 'rw'.

    actual_mode = None
    if mode == "r":
      actual_mode = "rb"
    elif mode == "rw":
      actual_mode = "r+b"

    if actual_mode is None:
      raise ValueError("Valid modes for opening a file in repy are 'r' and 'rw'.")
     
    restrictions.assertisallowed('file.__init__', filename, actual_mode)

    # Here we are checking that we only open a given file once in 'write' mode
    # so that file access is more uniform across platforms. (On Microsoft
    # Windows, for example, writing to the same file from two different file-
    # handles throws an error because of the way Windows (by default) locks
    # files opened for writing.)
    fileinfolock.acquire()

    try:
      # Check the entire fileinfo dictionary for the same file already being
      # open.
      for fileinfokey in fileinfo.keys():

        # If the filename matches this one, raise an exception.
        if os.path.abspath(fileinfo[fileinfokey]['filename']) == \
            os.path.abspath(filename):
          raise ValueError(\
              "A file is only allowed to have one open filehandle.")

      _assert_is_allowed_filename(filename)

      # If the file doesn't exist and the create flag was passed, create the
      # file first.
      if create and not os.path.exists(filename):
        # Create a file by opening it in write mode and then closing it.
        restrictions.assertisallowed('file.__init__', filename, 'wb')

        # Allocate a resource.
        try:
          nanny.tattle_add_item('filesopened', self.filehandle)
        except Exception:
          # Ok, maybe we can free up a file by garbage collecting.
          gc.collect()
          nanny.tattle_add_item('filesopened', self.filehandle)

        # Create the file, and then free up the resource.
        created_file = myfile(filename, 'wb')
        created_file.close()
        nanny.tattle_remove_item('filesopened', self.filehandle)

      self.filehandle = idhelper.getuniqueid()

      # Here is where we try to allocate a "file" resource from the
      # nanny system. If that fails, we garbage collect and try again
      # (this forces __del__() methods to be called on objects with
      # no references, which is how we automatically free up
      # file resources).
      try:
        nanny.tattle_add_item('filesopened', self.filehandle)
      except Exception:
        # Ok, maybe we can free up a file by garbage collecting.
        gc.collect()
        nanny.tattle_add_item('filesopened', self.filehandle)

      fileinfo[self.filehandle] = {'filename':filename, \
          'mode':actual_mode, 'fobj':myfile(filename, actual_mode)}
      self.name = filename
      self.mode = mode

    finally:
      fileinfolock.release()
Example #33
0
    def seek(self, *args):
        # prevent TOCTOU race with client changing my filehandle
        myfilehandle = self.filehandle
        restrictions.assertisallowed("file.seek", *args)

        return fileinfo[myfilehandle]["fobj"].seek(*args)