Esempio n. 1
0
 def open(self):
     # read boot block
     self.boot = BootBlock(self.blkdev)
     self.boot.read()
     # valid root block?
     if self.boot.valid:
         # get fs flags
         dos_type = self.boot.dos_type
         self.is_ffs = DosType.is_ffs(dos_type)
         self.is_intl = DosType.is_intl(dos_type)
         self.is_dircache = DosType.is_dircache(dos_type)
         # read root
         self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
         self.root.read()
         if self.root.valid:
             self.name = FSString(self.root.name)
             # build meta info
             self.meta_info = RootMetaInfo(self.root.create_ts,
                                           self.root.disk_ts,
                                           self.root.mod_ts)
             # create root dir
             self.root_dir = ADFSVolDir(self, self.root)
             self.root_dir.read()
             # create bitmap
             self.bitmap = ADFSBitmap(self.root)
             self.bitmap.read()
             self.valid = True
         else:
             raise FSError(INVALID_ROOT_BLOCK, block=self.root)
     else:
         raise FSError(INVALID_BOOT_BLOCK, block=self.boot)
Esempio n. 2
0
 def create(self,
            name,
            meta_info=None,
            dos_type=None,
            boot_code=None,
            is_ffs=False,
            is_intl=False,
            is_dircache=False):
     # determine dos_type
     if dos_type == None:
         dos_type = DosType.DOS0
         if is_ffs:
             dos_type |= DosType.DOS_MASK_FFS
         if is_dircache:
             dos_type |= DosType.DOS_MASK_DIRCACHE
         elif is_intl:
             dos_type |= DosType.DOS_MASK_INTL
     # update flags
     self.is_ffs = DosType.is_ffs(dos_type)
     self.is_intl = DosType.is_intl(dos_type)
     self.is_dircache = DosType.is_dircache(dos_type)
     # convert and check volume name
     if not isinstance(name, FSString):
         raise ValueError("create's name must be a FSString")
     fn = FileName(name, is_intl=self.is_intl)
     if not fn.is_valid():
         raise FSError(INVALID_VOLUME_NAME, file_name=name, node=self)
     # create a boot block
     self.boot = BootBlock(self.blkdev)
     self.boot.create(dos_type=dos_type, boot_code=boot_code)
     self.boot.write()
     # create a root block
     self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
     if meta_info == None:
         meta_info = RootMetaInfo()
         meta_info.set_current_as_create_time()
         meta_info.set_current_as_mod_time()
         meta_info.set_current_as_disk_time()
     create_ts = meta_info.get_create_ts()
     disk_ts = meta_info.get_disk_ts()
     mod_ts = meta_info.get_mod_ts()
     self.meta_info = meta_info
     self.root.create(name.get_ami_str(), create_ts, disk_ts, mod_ts)
     self.name = name
     # create bitmap
     self.bitmap = ADFSBitmap(self.root)
     self.bitmap.create()
     self.bitmap.write()  # writes root block, too
     # create empty root dir
     self.root_dir = ADFSVolDir(self, self.root)
     self.root_dir.read()
     # all ok
     self.valid = True
Esempio n. 3
0
 def open(self):
   # read boot block
   self.boot = BootBlock(self.blkdev)
   self.boot.read()
   # valid root block?
   if self.boot.valid:
     # get fs flags
     dos_type = self.boot.dos_type
     self.is_ffs = DosType.is_ffs(dos_type)
     self.is_intl = DosType.is_intl(dos_type)
     self.is_dircache = DosType.is_dircache(dos_type)
     # read root 
     self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
     self.root.read()
     if self.root.valid:
       self.name = self.root.name
       # build meta info
       self.meta_info = RootMetaInfo( self.root.create_ts, self.root.disk_ts, self.root.mod_ts )
       # create root dir
       self.root_dir = ADFSVolDir(self, self.root)
       self.root_dir.read()
       # create bitmap
       self.bitmap = ADFSBitmap(self.root)
       self.bitmap.read()
       self.valid = True
     else:
       raise FSError(INVALID_ROOT_BLOCK, block=self.root)
   else:
     raise FSError(INVALID_BOOT_BLOCK, block=self.boot)
Esempio n. 4
0
 def create(self,
            name,
            create_time=None,
            dos_type=BootBlock.DOS0,
            boot_code=None):
     # create a boot block
     self.boot = BootBlock(self.blkdev)
     self.boot.create()
     self.boot.write()
     # create a root block
     self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
     self.root.create(name, create_time)
     self.name = name
     # create bitmap
     self.bitmap = ADFSBitmap(self.root)
     self.bitmap.create()
     self.bitmap.write()  # writes root block, too
     # create empty root dir
     self.root_dir = ADFSVolDir(self, self.root)
     self.root_dir.read()
     # all ok
     self.valid = True
Esempio n. 5
0
 def open(self):
     # read boot block
     self.boot = BootBlock(self.blkdev)
     self.boot.read()
     # valid root block?
     if self.boot.valid:
         self.is_ffs = self.boot.dos_type > BootBlock.DOS0
         # read root
         self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
         self.root.read()
         if self.root.valid:
             self.name = self.root.name
             # create root dir
             self.root_dir = ADFSVolDir(self, self.root)
             self.root_dir.read()
             # create bitmap
             self.bitmap = ADFSBitmap(self.root)
             self.bitmap.read()
             self.valid = True
         else:
             raise FSError(INVALID_ROOT_BLOCK, block=self.root)
     else:
         raise FSError(INVALID_BOOT_BLOCK, block=self.boot)
Esempio n. 6
0
 def create(self, name, meta_info=None, dos_type=None, boot_code=None, is_ffs=False, is_intl=False, is_dircache=False, is_longname=False):
   # determine dos_type
   if dos_type == None:
     dos_type = DosType.DOS0
     if is_longname:
       dos_type = DosType.DOS6
     elif is_dircache:
       dos_type |= DosType.DOS_MASK_DIRCACHE
     elif is_intl:
       dos_type |= DosType.DOS_MASK_INTL
     if is_ffs:
       dos_type |= DosType.DOS_MASK_FFS
   # update flags
   self.is_ffs = DosType.is_ffs(dos_type)
   self.is_intl = DosType.is_intl(dos_type)
   self.is_dircache = DosType.is_dircache(dos_type)
   self.is_longname = DosType.is_longname(dos_type)
   # convert and check volume name
   if not isinstance(name, FSString):
     raise ValueError("create's name must be a FSString")
   fn = FileName(name, is_intl=self.is_intl, is_longname=False) # Volumes don't support long names
   if not fn.is_valid():
     raise FSError(INVALID_VOLUME_NAME, file_name=name, node=self)
   # create a boot block
   self.boot = BootBlock(self.blkdev)
   self.boot.create(dos_type=dos_type, boot_code=boot_code)
   self.boot.write()
   # create a root block
   self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
   if meta_info == None:
     meta_info = RootMetaInfo()
     meta_info.set_current_as_create_time()
     meta_info.set_current_as_mod_time()
     meta_info.set_current_as_disk_time()
   create_ts = meta_info.get_create_ts()
   disk_ts = meta_info.get_disk_ts()
   mod_ts = meta_info.get_mod_ts()
   self.meta_info = meta_info
   self.root.create(name.get_ami_str(), create_ts, disk_ts, mod_ts, fstype=dos_type)
   self.name = name
   # create bitmap
   self.bitmap = ADFSBitmap(self.root)
   self.bitmap.create()
   self.bitmap.write() # writes root block, too
   # create empty root dir
   self.root_dir = ADFSVolDir(self, self.root)
   self.root_dir.read()
   # all ok
   self.valid = True
Esempio n. 7
0
 def create(self, name, create_time=None, dos_type=BootBlock.DOS0, boot_code=None):
   # create a boot block
   self.boot = BootBlock(self.blkdev)
   self.boot.create()
   self.boot.write()
   # create a root block
   self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
   self.root.create(name, create_time)
   self.name = name
   # create bitmap
   self.bitmap = ADFSBitmap(self.root)
   self.bitmap.create()
   self.bitmap.write() # writes root block, too
   # create empty root dir
   self.root_dir = ADFSVolDir(self, self.root)
   self.root_dir.read()
   # all ok
   self.valid = True
Esempio n. 8
0
 def create(self, name, meta_info=None, dos_type=None, boot_code=None, is_ffs=False, is_intl=False, is_dircache=False):
   # determine dos_type
   if dos_type == None:
     dos_type = DosType.DOS0
     if is_ffs:
       dos_type |= DosType.DOS_MASK_FFS
     if is_dircache:
       dos_type |= DosType.DOS_MASK_DIRCACHE
     elif is_intl:
       dos_type |= DosType.DOS_MASK_INTL
   # create a boot block
   self.boot = BootBlock(self.blkdev, )
   self.boot.create(dos_type=dos_type, boot_code=boot_code)
   self.is_ffs = DosType.is_ffs(dos_type)
   self.is_intl = DosType.is_intl(dos_type)
   self.is_dircache = DosType.is_dircache(dos_type)
   self.boot.write()
   # create a root block
   self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
   if meta_info == None:
     meta_info = RootMetaInfo()
     meta_info.set_current_as_create_time()
     meta_info.set_current_as_mod_time()
     meta_info.set_current_as_disk_time()
   create_ts = meta_info.get_create_ts()
   disk_ts = meta_info.get_disk_ts()
   mod_ts = meta_info.get_mod_ts()
   self.meta_info = meta_info
   self.root.create(name, create_ts, disk_ts, mod_ts)
   self.name = name
   # create bitmap
   self.bitmap = ADFSBitmap(self.root)
   self.bitmap.create()
   self.bitmap.write() # writes root block, too
   # create empty root dir
   self.root_dir = ADFSVolDir(self, self.root)
   self.root_dir.read()
   # all ok
   self.valid = True
Esempio n. 9
0
 def open(self):
   # read boot block
   self.boot = BootBlock(self.blkdev)
   self.boot.read()
   # valid root block?
   if self.boot.valid:
     self.is_ffs = self.boot.dos_type > BootBlock.DOS0
     # read root 
     self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
     self.root.read()
     if self.root.valid:
       self.name = self.root.name
       # create root dir
       self.root_dir = ADFSVolDir(self, self.root)
       self.root_dir.read()
       # create bitmap
       self.bitmap = ADFSBitmap(self.root)
       self.bitmap.read()
       self.valid = True
     else:
       raise FSError(INVALID_ROOT_BLOCK, block=self.root)
   else:
     raise FSError(INVALID_BOOT_BLOCK, block=self.boot)
Esempio n. 10
0
class ADFSVolume:
  root_path_aliases = ("", "/", ":")
  
  def __init__(self, blkdev):
    self.blkdev = blkdev
    
    self.boot = None
    self.root = None
    self.root_dir = None
    self.bitmap = None
    
    self.valid = False
    self.is_ffs = None
    self.is_intl = None
    self.is_dircache = None
    self.name = None
    self.meta_info = None
    
  def open(self):
    # read boot block
    self.boot = BootBlock(self.blkdev)
    self.boot.read()
    # valid root block?
    if self.boot.valid:
      # get fs flags
      dos_type = self.boot.dos_type
      self.is_ffs = DosType.is_ffs(dos_type)
      self.is_intl = DosType.is_intl(dos_type)
      self.is_dircache = DosType.is_dircache(dos_type)
      # read root 
      self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
      self.root.read()
      if self.root.valid:
        self.name = self.root.name
        # build meta info
        self.meta_info = RootMetaInfo( self.root.create_ts, self.root.disk_ts, self.root.mod_ts )
        # create root dir
        self.root_dir = ADFSVolDir(self, self.root)
        self.root_dir.read()
        # create bitmap
        self.bitmap = ADFSBitmap(self.root)
        self.bitmap.read()
        self.valid = True
      else:
        raise FSError(INVALID_ROOT_BLOCK, block=self.root)
    else:
      raise FSError(INVALID_BOOT_BLOCK, block=self.boot)
  
  def create(self, name, meta_info=None, dos_type=None, boot_code=None, is_ffs=False, is_intl=False, is_dircache=False):
    # determine dos_type
    if dos_type == None:
      dos_type = DosType.DOS0
      if is_ffs:
        dos_type |= DosType.DOS_MASK_FFS
      if is_dircache:
        dos_type |= DosType.DOS_MASK_DIRCACHE
      elif is_intl:
        dos_type |= DosType.DOS_MASK_INTL
    # create a boot block
    self.boot = BootBlock(self.blkdev, )
    self.boot.create(dos_type=dos_type, boot_code=boot_code)
    self.is_ffs = DosType.is_ffs(dos_type)
    self.is_intl = DosType.is_intl(dos_type)
    self.is_dircache = DosType.is_dircache(dos_type)
    self.boot.write()
    # create a root block
    self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
    if meta_info == None:
      meta_info = RootMetaInfo()
      meta_info.set_current_as_create_time()
      meta_info.set_current_as_mod_time()
      meta_info.set_current_as_disk_time()
    create_ts = meta_info.get_create_ts()
    disk_ts = meta_info.get_disk_ts()
    mod_ts = meta_info.get_mod_ts()
    self.meta_info = meta_info
    self.root.create(name, create_ts, disk_ts, mod_ts)
    self.name = name
    # create bitmap
    self.bitmap = ADFSBitmap(self.root)
    self.bitmap.create()
    self.bitmap.write() # writes root block, too
    # create empty root dir
    self.root_dir = ADFSVolDir(self, self.root)
    self.root_dir.read()
    # all ok
    self.valid = True
  
  def close(self):
    pass

  def get_info(self):
    """return an array of strings with information on the volume"""
    res = []
    total = self.get_total_blocks()
    free  = self.get_free_blocks()
    used  = total - free
    bb = self.blkdev.block_bytes
    btotal = total * bb
    bfree  = free * bb
    bused  = used * bb
    prc_free = 10000 * free / total
    prc_used = 10000 - prc_free
    res.append("total:  %10d  %s  %12d" % (total, ByteSize.to_byte_size_str(btotal), btotal))
    res.append("used:   %10d  %s  %12d  %5.2f%%" % (used, ByteSize.to_byte_size_str(bused), bused, prc_used / 100.0))
    res.append("free:   %10d  %s  %12d  %5.2f%%" % (free, ByteSize.to_byte_size_str(bfree), bfree, prc_free / 100.0))
    return res

  def get_path_name(self, path_name, allow_file=True, allow_dir=True):
    if path_name in self.root_path_aliases:
      return self.root_dir
    pc = path_name.split("/")
    fn = []
    for path in pc:
      fn.append(FileName(path))
    return self.root_dir.get_path(fn, allow_file, allow_dir)

  def get_dir_path_name(self, path_name):
    return self.get_path_name(path_name, allow_file=False)
  
  def get_file_path_name(self, path_name):
    return self.get_path_name(path_name, allow_dir=False)
  
  def get_create_path_name(self, path_name, suggest_name=None):
    """get a parent node and path name for creation
       return: parent_node_or_none, file_name_or_none
    """
    if path_name in self.root_path_aliases:
      return self.root_dir, suggest_name
    else:
      # try to get path_name as a directory
      node = self.get_dir_path_name(path_name)
      if node != None:
        return node, suggest_name
      # is a file name appended?
      pos = path_name.rfind('/')
      if pos != -1:
        dir_name = path_name[0:pos]
        file_name = path_name[pos+1:]
        if len(file_name) == 0:
          file_name = suggest_name
        node = self.get_dir_path_name(dir_name)
        return node, file_name
      else:
        # its a file name
        return self.root_dir, path_name
  
  # ----- convenience API -----
  
  def get_volume_name(self):
    return self.name
  
  def get_root_dir(self):
    return self.root_dir
  
  def get_dos_type(self):
    return self.boot.dos_type
    
  def get_boot_code(self):
    return self.boot.boot_code
  
  def get_free_blocks(self):
    return self.bitmap.get_num_free()
    
  def get_used_blocks(self):
    free = self.bitmap.get_num_free()
    total = self.blkdev.num_blocks
    return total - free
    
  def get_total_blocks(self):
    return self.blkdev.num_blocks
  
  def get_meta_info(self):
    return self.meta_info

  def update_disk_time(self):
    mi = RootMetaInfo()
    mi.set_current_as_disk_time()
    self.change_meta_info(mi)
    
  def change_meta_info(self, meta_info):
    if self.root != None and self.root.valid:
      dirty = False
      # update create_ts
      create_ts = meta_info.get_create_ts()
      if create_ts != None:
        self.root.create_ts = meta_info.get_create_ts()
        dirty = True
      # update disk_ts
      disk_ts = meta_info.get_disk_ts()
      if disk_ts != None:
        self.root.disk_ts = disk_ts
        dirty = True
      # update mod_ts
      mod_ts = meta_info.get_mod_ts()
      if mod_ts != None:
        self.root.mod_ts = mod_ts
        dirty = True
      # update if something changed
      if dirty:
        self.root.write()
        self.meta_info = RootMetaInfo( self.root.create_ts, self.root.disk_ts, self.root.mod_ts )
      return True
    else:
      return False
      
  def change_create_ts(self, create_ts):
    return self.change_meta_info(RootMetaInfo(create_ts=create_ts))
    
  def change_disk_ts(self, disk_ts):
    return self.change_meta_info(RootMetaInfo(disk_ts=disk_ts))
    
  def change_mod_ts(self, mod_ts):
    return self.change_meta_info(RootMetaInfo(mod_ts=mod_ts))
  
  def change_create_ts_by_string(self, create_ts_str):
    t = TimeStamp()
    t.parse(create_ts_str)
    return self.change_meta_info(RootMetaInfo(create_ts=t))

  def change_disk_ts_by_string(self, disk_ts_str):
    t = TimeStamp()
    t.parse(disk_ts_str)
    return self.change_meta_info(RootMetaInfo(disk_ts=t))
    
  def change_mod_ts_by_string(self, mod_ts_str):
    t = TimeStamp()
    t.parse(mod_ts_str)
    return self.change_meta_info(RootMetaInfo(mod_ts=t))    

  def relabel(self, new_name):
    fn = FileName(new_name, is_intl=self.is_intl)
    if not fn.is_valid():
      raise FSError(INVALID_VOLUME_NAME, file_name=name, node=self)
    self.root.name = new_name
    self.root.write()
    self.name = new_name
    self.root_dir.name = new_name

  def create_dir(self, ami_path):
    pc = ami_path.split("/")
    # no directory given
    if len(pc) == 0:
      raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
    # no parent dir found
    node = self.get_dir_path_name("/".join(pc[:-1]))
    if node == None:
      raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
    node.create_dir(pc[-1])
    
  def write_file(self, data, ami_path=None, file_name=None, cache=False):
    parent_node, file_name = self.get_create_path_name(ami_path, file_name)
    if parent_node == None:
      raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
    if file_name == None:
      raise FSError(INVALID_FILE_NAME, file_name=file_name)
    # create file
    node = parent_node.create_file(file_name, data)
    if not cache:
      node.flush()
  
  def read_file(self, ami_path, cache=False):
    node = self.get_file_path_name(ami_path)
    if node == None:
      raise FSError(FILE_NOT_FOUND, file_name=ami_path)
    data = node.get_file_data()
    if not cache:
      node.flush()
    return data
  
  def delete(self, ami_path, wipe=False, all=False):
    node = self.get_path_name(ami_path)
    if node == None:
      raise FSError(FILE_NOT_FOUND, file_name=ami_path)
    node.delete(wipe=wipe, all=all)
Esempio n. 11
0
class ADFSVolume:
  
  def __init__(self, blkdev):
    self.blkdev = blkdev
    
    self.boot = None
    self.root = None
    self.root_dir = None
    self.bitmap = None
    
    self.valid = False
    self.is_ffs = None
    self.is_intl = None
    self.is_dircache = None
    self.name = None
    self.meta_info = None
    
  def open(self):
    # read boot block
    self.boot = BootBlock(self.blkdev)
    self.boot.read()
    # valid root block?
    if self.boot.valid:
      # get fs flags
      dos_type = self.boot.dos_type
      self.is_ffs = DosType.is_ffs(dos_type)
      self.is_intl = DosType.is_intl(dos_type)
      self.is_dircache = DosType.is_dircache(dos_type)
      # read root 
      self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
      self.root.read()
      if self.root.valid:
        self.name = FSString(self.root.name)
        # build meta info
        self.meta_info = RootMetaInfo( self.root.create_ts, self.root.disk_ts, self.root.mod_ts )
        # create root dir
        self.root_dir = ADFSVolDir(self, self.root)
        self.root_dir.read()
        # create bitmap
        self.bitmap = ADFSBitmap(self.root)
        self.bitmap.read()
        self.valid = True
      else:
        raise FSError(INVALID_ROOT_BLOCK, block=self.root)
    else:
      raise FSError(INVALID_BOOT_BLOCK, block=self.boot)
  
  def create(self, name, meta_info=None, dos_type=None, boot_code=None, is_ffs=False, is_intl=False, is_dircache=False):
    # determine dos_type
    if dos_type == None:
      dos_type = DosType.DOS0
      if is_ffs:
        dos_type |= DosType.DOS_MASK_FFS
      if is_dircache:
        dos_type |= DosType.DOS_MASK_DIRCACHE
      elif is_intl:
        dos_type |= DosType.DOS_MASK_INTL
    # update flags
    self.is_ffs = DosType.is_ffs(dos_type)
    self.is_intl = DosType.is_intl(dos_type)
    self.is_dircache = DosType.is_dircache(dos_type)
    # convert and check volume name
    if not isinstance(name, FSString):
      raise ValueError("create's name must be a FSString")
    fn = FileName(name, is_intl=self.is_intl)
    if not fn.is_valid():
      raise FSError(INVALID_VOLUME_NAME, file_name=name, node=self)
    # create a boot block
    self.boot = BootBlock(self.blkdev)
    self.boot.create(dos_type=dos_type, boot_code=boot_code)
    self.boot.write()
    # create a root block
    self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
    if meta_info == None:
      meta_info = RootMetaInfo()
      meta_info.set_current_as_create_time()
      meta_info.set_current_as_mod_time()
      meta_info.set_current_as_disk_time()
    create_ts = meta_info.get_create_ts()
    disk_ts = meta_info.get_disk_ts()
    mod_ts = meta_info.get_mod_ts()
    self.meta_info = meta_info
    self.root.create(name.get_ami_str(), create_ts, disk_ts, mod_ts)
    self.name = name
    # create bitmap
    self.bitmap = ADFSBitmap(self.root)
    self.bitmap.create()
    self.bitmap.write() # writes root block, too
    # create empty root dir
    self.root_dir = ADFSVolDir(self, self.root)
    self.root_dir.read()
    # all ok
    self.valid = True
  
  def close(self):
    pass

  def get_info(self):
    """return an array of strings with information on the volume"""
    res = []
    total = self.get_total_blocks()
    free  = self.get_free_blocks()
    used  = total - free
    bb = self.blkdev.block_bytes
    btotal = total * bb
    bfree  = free * bb
    bused  = used * bb
    prc_free = 10000 * free / total
    prc_used = 10000 - prc_free
    res.append("total:  %10d  %s  %12d" % (total, ByteSize.to_byte_size_str(btotal), btotal))
    res.append("used:   %10d  %s  %12d  %5.2f%%" % (used, ByteSize.to_byte_size_str(bused), bused, prc_used / 100.0))
    res.append("free:   %10d  %s  %12d  %5.2f%%" % (free, ByteSize.to_byte_size_str(bfree), bfree, prc_free / 100.0))
    return res

  # ----- Path Queries -----

  def get_path_name(self, path_name, allow_file=True, allow_dir=True):
    """get node for given path"""
    # make sure path name is a FSString
    if not isinstance(path_name, FSString):
      raise ValueError("get_path_name's path must be a FSString")
    # create and check file name
    fn = FileName(path_name, is_intl=self.is_intl)
    if not fn.is_valid():
      raise FSError(INVALID_FILE_NAME, file_name=path_name, node=self)      
    # find node
    if fn.is_root_path_alias():
      # its the root node
      return self.root_dir
    else:
      # find a sub node
      path = fn.split_path()
      return self.root_dir.get_path(path, allow_file, allow_dir)

  def get_dir_path_name(self, path_name):
    """get node for given path and ensure its a directory"""
    return self.get_path_name(path_name, allow_file=False)
  
  def get_file_path_name(self, path_name):
    """get node for given path and ensure its a file"""
    return self.get_path_name(path_name, allow_dir=False)
  
  def get_create_path_name(self, path_name, suggest_name=None):
    """get a parent node and path name for creation
       return: parent_node_or_none, file_name_or_none
    """
    # make sure input is correct
    if not isinstance(path_name, FSString):
      raise ValueError("get_create_path_name's path_name must be a FSString")
    if suggest_name != None and not isinstance(suggest_name, FSString):
      raise ValueError("get_create_path_name's suggest_name must be a FSString")
    # is root path?
    fn = FileName(path_name, is_intl=self.is_intl)
    if not fn.is_valid():
      raise FSError(INVALID_FILE_NAME, file_name=path_name, node=self)      
    # find node
    if fn.is_root_path_alias():
      return self.root_dir, suggest_name
    else:
      # try to get path_name as a directory
      node = self.get_dir_path_name(path_name)
      if node != None:
        return node, suggest_name
      else:
        # split into dir and file name
        dn, fn = fn.get_dir_and_base_name()
        if dn != None:
          # has a directory -> try to fetch it
          node = self.get_dir_path_name(dn)
        else:
          # no dir -> assume root dir
          node = self.root_dir
        if fn != None:
          # take given name
          return node, fn
        else:
          # use suggested name
          return node, suggest_name
    
  # ----- convenience API -----
  
  def get_volume_name(self):
    return self.name
  
  def get_root_dir(self):
    return self.root_dir
  
  def get_dos_type(self):
    return self.boot.dos_type
    
  def get_boot_code(self):
    return self.boot.boot_code
  
  def get_free_blocks(self):
    return self.bitmap.get_num_free()
    
  def get_used_blocks(self):
    free = self.bitmap.get_num_free()
    total = self.blkdev.num_blocks
    return total - free
    
  def get_total_blocks(self):
    return self.blkdev.num_blocks
  
  def get_meta_info(self):
    return self.meta_info

  def update_disk_time(self):
    mi = RootMetaInfo()
    mi.set_current_as_disk_time()
    self.change_meta_info(mi)
    
  def change_meta_info(self, meta_info):
    if self.root != None and self.root.valid:
      dirty = False
      # update create_ts
      create_ts = meta_info.get_create_ts()
      if create_ts != None:
        self.root.create_ts = meta_info.get_create_ts()
        dirty = True
      # update disk_ts
      disk_ts = meta_info.get_disk_ts()
      if disk_ts != None:
        self.root.disk_ts = disk_ts
        dirty = True
      # update mod_ts
      mod_ts = meta_info.get_mod_ts()
      if mod_ts != None:
        self.root.mod_ts = mod_ts
        dirty = True
      # update if something changed
      if dirty:
        self.root.write()
        self.meta_info = RootMetaInfo( self.root.create_ts, self.root.disk_ts, self.root.mod_ts )
      return True
    else:
      return False
      
  def change_create_ts(self, create_ts):
    return self.change_meta_info(RootMetaInfo(create_ts=create_ts))
    
  def change_disk_ts(self, disk_ts):
    return self.change_meta_info(RootMetaInfo(disk_ts=disk_ts))
    
  def change_mod_ts(self, mod_ts):
    return self.change_meta_info(RootMetaInfo(mod_ts=mod_ts))
  
  def change_create_ts_by_string(self, create_ts_str):
    t = TimeStamp()
    t.parse(create_ts_str)
    return self.change_meta_info(RootMetaInfo(create_ts=t))

  def change_disk_ts_by_string(self, disk_ts_str):
    t = TimeStamp()
    t.parse(disk_ts_str)
    return self.change_meta_info(RootMetaInfo(disk_ts=t))
    
  def change_mod_ts_by_string(self, mod_ts_str):
    t = TimeStamp()
    t.parse(mod_ts_str)
    return self.change_meta_info(RootMetaInfo(mod_ts=t))    

  def relabel(self, name):
    """Relabel the volume"""
    # make sure its a FSString
    if not isinstance(name, FSString):
      raise ValueError("relabel's name must be a FSString")
    # validate file name
    fn = FileName(name, is_intl=self.is_intl)
    if not fn.is_valid():
      raise FSError(INVALID_VOLUME_NAME, file_name=name, node=self)
    # update root block
    ami_name = name.get_ami_str()
    self.root.name = ami_name
    self.root.write()
    # store internally
    self.name = name
    self.root_dir.name = name

  def create_dir(self, ami_path):
    """Create a new directory"""
    # make sure its a FSString
    if not isinstance(ami_path, FSString):
      raise ValueError("create_dir's ami_path must be a FSString")
    # check file path
    fn = FileName(ami_path, is_intl=self.is_intl)
    if not fn.is_valid():
      raise FSError(INVALID_FILE_NAME, file_name=ami_path)
    # split into dir and base name
    dir_name, base_name = fn.get_dir_and_base_name()
    if base_name == None:
      raise FSError(INVALID_FILE_NAME, file_name=ami_path)
    # find parent of dir
    if dir_name == None:
      node = self.root_dir
    else:
      # no parent dir found
      node = self.get_dir_path_name(dir_name)
      if node == None:
        raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path, extra="not found: "+dir_name)
    node.create_dir(base_name)
    
  def write_file(self, data, ami_path, suggest_name=None, cache=False):
    """Write given data as a file"""
    # get parent node and file_name
    parent_node, file_name = self.get_create_path_name(ami_path, suggest_name)
    if parent_node == None:
      raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
    if file_name == None:
      raise FSError(INVALID_FILE_NAME, file_name=file_name)
    # create file
    node = parent_node.create_file(file_name, data)
    if not cache:
      node.flush()
  
  def read_file(self, ami_path, cache=False):
    """Read a file and return data"""
    # get node of file
    node = self.get_file_path_name(ami_path)
    if node == None:
      raise FSError(FILE_NOT_FOUND, file_name=ami_path)
    data = node.get_file_data()
    if not cache:
      node.flush()
    return data
  
  def delete(self, ami_path, wipe=False, all=False):
    """Delete a file or directory at given path"""
    node = self.get_path_name(ami_path)
    if node == None:
      raise FSError(FILE_NOT_FOUND, file_name=ami_path)
    node.delete(wipe=wipe, all=all)
Esempio n. 12
0
class ADFSVolume:
    def __init__(self, blkdev):
        self.blkdev = blkdev

        self.boot = None
        self.root = None
        self.root_dir = None
        self.bitmap = None

        self.valid = False
        self.is_ffs = None
        self.is_intl = None
        self.is_dircache = None
        self.name = None
        self.meta_info = None

    def open(self):
        # read boot block
        self.boot = BootBlock(self.blkdev)
        self.boot.read()
        # valid root block?
        if self.boot.valid:
            # get fs flags
            dos_type = self.boot.dos_type
            self.is_ffs = DosType.is_ffs(dos_type)
            self.is_intl = DosType.is_intl(dos_type)
            self.is_dircache = DosType.is_dircache(dos_type)
            # read root
            self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
            self.root.read()
            if self.root.valid:
                self.name = FSString(self.root.name)
                # build meta info
                self.meta_info = RootMetaInfo(self.root.create_ts,
                                              self.root.disk_ts,
                                              self.root.mod_ts)
                # create root dir
                self.root_dir = ADFSVolDir(self, self.root)
                self.root_dir.read()
                # create bitmap
                self.bitmap = ADFSBitmap(self.root)
                self.bitmap.read()
                self.valid = True
            else:
                raise FSError(INVALID_ROOT_BLOCK, block=self.root)
        else:
            raise FSError(INVALID_BOOT_BLOCK, block=self.boot)

    def create(self,
               name,
               meta_info=None,
               dos_type=None,
               boot_code=None,
               is_ffs=False,
               is_intl=False,
               is_dircache=False):
        # determine dos_type
        if dos_type == None:
            dos_type = DosType.DOS0
            if is_ffs:
                dos_type |= DosType.DOS_MASK_FFS
            if is_dircache:
                dos_type |= DosType.DOS_MASK_DIRCACHE
            elif is_intl:
                dos_type |= DosType.DOS_MASK_INTL
        # update flags
        self.is_ffs = DosType.is_ffs(dos_type)
        self.is_intl = DosType.is_intl(dos_type)
        self.is_dircache = DosType.is_dircache(dos_type)
        # convert and check volume name
        if not isinstance(name, FSString):
            raise ValueError("create's name must be a FSString")
        fn = FileName(name, is_intl=self.is_intl)
        if not fn.is_valid():
            raise FSError(INVALID_VOLUME_NAME, file_name=name, node=self)
        # create a boot block
        self.boot = BootBlock(self.blkdev)
        self.boot.create(dos_type=dos_type, boot_code=boot_code)
        self.boot.write()
        # create a root block
        self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
        if meta_info == None:
            meta_info = RootMetaInfo()
            meta_info.set_current_as_create_time()
            meta_info.set_current_as_mod_time()
            meta_info.set_current_as_disk_time()
        create_ts = meta_info.get_create_ts()
        disk_ts = meta_info.get_disk_ts()
        mod_ts = meta_info.get_mod_ts()
        self.meta_info = meta_info
        self.root.create(name.get_ami_str(), create_ts, disk_ts, mod_ts)
        self.name = name
        # create bitmap
        self.bitmap = ADFSBitmap(self.root)
        self.bitmap.create()
        self.bitmap.write()  # writes root block, too
        # create empty root dir
        self.root_dir = ADFSVolDir(self, self.root)
        self.root_dir.read()
        # all ok
        self.valid = True

    def close(self):
        pass

    def get_info(self):
        """return an array of strings with information on the volume"""
        res = []
        total = self.get_total_blocks()
        free = self.get_free_blocks()
        used = total - free
        bb = self.blkdev.block_bytes
        btotal = total * bb
        bfree = free * bb
        bused = used * bb
        prc_free = 10000 * free / total
        prc_used = 10000 - prc_free
        res.append("total:  %10d  %s  %12d" %
                   (total, ByteSize.to_byte_size_str(btotal), btotal))
        res.append(
            "used:   %10d  %s  %12d  %5.2f%%" %
            (used, ByteSize.to_byte_size_str(bused), bused, prc_used / 100.0))
        res.append(
            "free:   %10d  %s  %12d  %5.2f%%" %
            (free, ByteSize.to_byte_size_str(bfree), bfree, prc_free / 100.0))
        return res

    # ----- Path Queries -----

    def get_path_name(self, path_name, allow_file=True, allow_dir=True):
        """get node for given path"""
        # make sure path name is a FSString
        if not isinstance(path_name, FSString):
            raise ValueError("get_path_name's path must be a FSString")
        # create and check file name
        fn = FileName(path_name, is_intl=self.is_intl)
        if not fn.is_valid():
            raise FSError(INVALID_FILE_NAME, file_name=path_name, node=self)
        # find node
        if fn.is_root_path_alias():
            # its the root node
            return self.root_dir
        else:
            # find a sub node
            path = fn.split_path()
            return self.root_dir.get_path(path, allow_file, allow_dir)

    def get_dir_path_name(self, path_name):
        """get node for given path and ensure its a directory"""
        return self.get_path_name(path_name, allow_file=False)

    def get_file_path_name(self, path_name):
        """get node for given path and ensure its a file"""
        return self.get_path_name(path_name, allow_dir=False)

    def get_create_path_name(self, path_name, suggest_name=None):
        """get a parent node and path name for creation
       return: parent_node_or_none, file_name_or_none
    """
        # make sure input is correct
        if not isinstance(path_name, FSString):
            raise ValueError(
                "get_create_path_name's path_name must be a FSString")
        if suggest_name != None and not isinstance(suggest_name, FSString):
            raise ValueError(
                "get_create_path_name's suggest_name must be a FSString")
        # is root path?
        fn = FileName(path_name, is_intl=self.is_intl)
        if not fn.is_valid():
            raise FSError(INVALID_FILE_NAME, file_name=path_name, node=self)
        # find node
        if fn.is_root_path_alias():
            return self.root_dir, suggest_name
        else:
            # try to get path_name as a directory
            node = self.get_dir_path_name(path_name)
            if node != None:
                return node, suggest_name
            else:
                # split into dir and file name
                dn, fn = fn.get_dir_and_base_name()
                if dn != None:
                    # has a directory -> try to fetch it
                    node = self.get_dir_path_name(dn)
                else:
                    # no dir -> assume root dir
                    node = self.root_dir
                if fn != None:
                    # take given name
                    return node, fn
                else:
                    # use suggested name
                    return node, suggest_name

    # ----- convenience API -----

    def get_volume_name(self):
        return self.name

    def get_root_dir(self):
        return self.root_dir

    def get_dos_type(self):
        return self.boot.dos_type

    def get_boot_code(self):
        return self.boot.boot_code

    def get_free_blocks(self):
        return self.bitmap.get_num_free()

    def get_used_blocks(self):
        free = self.bitmap.get_num_free()
        total = self.blkdev.num_blocks
        return total - free

    def get_total_blocks(self):
        return self.blkdev.num_blocks

    def get_meta_info(self):
        return self.meta_info

    def update_disk_time(self):
        mi = RootMetaInfo()
        mi.set_current_as_disk_time()
        self.change_meta_info(mi)

    def change_meta_info(self, meta_info):
        if self.root != None and self.root.valid:
            dirty = False
            # update create_ts
            create_ts = meta_info.get_create_ts()
            if create_ts != None:
                self.root.create_ts = meta_info.get_create_ts()
                dirty = True
            # update disk_ts
            disk_ts = meta_info.get_disk_ts()
            if disk_ts != None:
                self.root.disk_ts = disk_ts
                dirty = True
            # update mod_ts
            mod_ts = meta_info.get_mod_ts()
            if mod_ts != None:
                self.root.mod_ts = mod_ts
                dirty = True
            # update if something changed
            if dirty:
                self.root.write()
                self.meta_info = RootMetaInfo(self.root.create_ts,
                                              self.root.disk_ts,
                                              self.root.mod_ts)
            return True
        else:
            return False

    def change_create_ts(self, create_ts):
        return self.change_meta_info(RootMetaInfo(create_ts=create_ts))

    def change_disk_ts(self, disk_ts):
        return self.change_meta_info(RootMetaInfo(disk_ts=disk_ts))

    def change_mod_ts(self, mod_ts):
        return self.change_meta_info(RootMetaInfo(mod_ts=mod_ts))

    def change_create_ts_by_string(self, create_ts_str):
        t = TimeStamp()
        t.parse(create_ts_str)
        return self.change_meta_info(RootMetaInfo(create_ts=t))

    def change_disk_ts_by_string(self, disk_ts_str):
        t = TimeStamp()
        t.parse(disk_ts_str)
        return self.change_meta_info(RootMetaInfo(disk_ts=t))

    def change_mod_ts_by_string(self, mod_ts_str):
        t = TimeStamp()
        t.parse(mod_ts_str)
        return self.change_meta_info(RootMetaInfo(mod_ts=t))

    def relabel(self, name):
        """Relabel the volume"""
        # make sure its a FSString
        if not isinstance(name, FSString):
            raise ValueError("relabel's name must be a FSString")
        # validate file name
        fn = FileName(name, is_intl=self.is_intl)
        if not fn.is_valid():
            raise FSError(INVALID_VOLUME_NAME, file_name=name, node=self)
        # update root block
        ami_name = name.get_ami_str()
        self.root.name = ami_name
        self.root.write()
        # store internally
        self.name = name
        self.root_dir.name = name

    def create_dir(self, ami_path):
        """Create a new directory"""
        # make sure its a FSString
        if not isinstance(ami_path, FSString):
            raise ValueError("create_dir's ami_path must be a FSString")
        # check file path
        fn = FileName(ami_path, is_intl=self.is_intl)
        if not fn.is_valid():
            raise FSError(INVALID_FILE_NAME, file_name=ami_path)
        # split into dir and base name
        dir_name, base_name = fn.get_dir_and_base_name()
        if base_name == None:
            raise FSError(INVALID_FILE_NAME, file_name=ami_path)
        # find parent of dir
        if dir_name == None:
            node = self.root_dir
        else:
            # no parent dir found
            node = self.get_dir_path_name(dir_name)
            if node == None:
                raise FSError(INVALID_PARENT_DIRECTORY,
                              file_name=ami_path,
                              extra="not found: " + dir_name)
        node.create_dir(base_name)

    def write_file(self, data, ami_path, suggest_name=None, cache=False):
        """Write given data as a file"""
        # get parent node and file_name
        parent_node, file_name = self.get_create_path_name(
            ami_path, suggest_name)
        if parent_node == None:
            raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
        if file_name == None:
            raise FSError(INVALID_FILE_NAME, file_name=file_name)
        # create file
        node = parent_node.create_file(file_name, data)
        if not cache:
            node.flush()

    def read_file(self, ami_path, cache=False):
        """Read a file and return data"""
        # get node of file
        node = self.get_file_path_name(ami_path)
        if node == None:
            raise FSError(FILE_NOT_FOUND, file_name=ami_path)
        data = node.get_file_data()
        if not cache:
            node.flush()
        return data

    def delete(self, ami_path, wipe=False, all=False):
        """Delete a file or directory at given path"""
        node = self.get_path_name(ami_path)
        if node == None:
            raise FSError(FILE_NOT_FOUND, file_name=ami_path)
        node.delete(wipe=wipe, all=all)
Esempio n. 13
0
class ADFSVolume:
  def __init__(self, blkdev):
    self.blkdev = blkdev
    
    self.boot = None
    self.root = None
    self.root_dir = None
    self.bitmap = None
    
    self.valid = False
    self.is_ffs = None
    self.name = None
    
  def open(self):
    # read boot block
    self.boot = BootBlock(self.blkdev)
    self.boot.read()
    # valid root block?
    if self.boot.valid:
      self.is_ffs = self.boot.dos_type > BootBlock.DOS0
      # read root 
      self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
      self.root.read()
      if self.root.valid:
        self.name = self.root.name
        # create root dir
        self.root_dir = ADFSVolDir(self, self.root)
        self.root_dir.read()
        # create bitmap
        self.bitmap = ADFSBitmap(self.root)
        self.bitmap.read()
        self.valid = True
      else:
        raise FSError(INVALID_ROOT_BLOCK, block=self.root)
    else:
      raise FSError(INVALID_BOOT_BLOCK, block=self.boot)
  
  def create(self, name, create_time=None, dos_type=BootBlock.DOS0, boot_code=None):
    # create a boot block
    self.boot = BootBlock(self.blkdev)
    self.boot.create()
    self.boot.write()
    # create a root block
    self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
    self.root.create(name, create_time)
    self.name = name
    # create bitmap
    self.bitmap = ADFSBitmap(self.root)
    self.bitmap.create()
    self.bitmap.write() # writes root block, too
    # create empty root dir
    self.root_dir = ADFSVolDir(self, self.root)
    self.root_dir.read()
    # all ok
    self.valid = True
  
  def close(self):
    pass

  def get_path_name(self, path_name, allow_file=True, allow_dir=True):
    if path_name == "" or path_name == "/":
      return self.root_dir
    pc = path_name.split("/")
    fn = []
    for path in pc:
      fn.append(FileName(path))
    return self.root_dir.get_path(fn, allow_file, allow_dir)

  def get_dir_path_name(self, path_name):
    return self.get_path_name(path_name, allow_file=False)
  
  def get_file_path_name(self, path_name):
    return self.get_path_name(path_name, allow_dir=False)
  
  def get_create_path_name(self, path_name, suggest_name=None):
    """get a parent node and path name for creation
       return: parent_node_or_none, file_name_or_none
    """
    if path_name == None or path_name == "":
      return self.root_dir, suggest_name
    else:
      # try to get path_name as a directory
      node = self.get_dir_path_name(path_name)
      if node != None:
        return node, suggest_name
      # is a file name appended?
      pos = path_name.rfind('/')
      if pos != -1:
        dir_name = path_name[0:pos]
        file_name = path_name[pos+1:]
        if len(file_name) == 0:
          file_name = suggest_name
        node = self.get_dir_path_name(dir_name)
        return node, file_name
      else:
        # its a file name
        return self.root_dir, path_name
  
  # ----- convenience API -----
  
  def create_dir(self, ami_path):
    pc = ami_path.split("/")
    # no directory given
    if len(pc) == 0:
      raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
    # no parent dir found
    node = self.get_dir_path_name("/".join(pc[:-1]))
    if node == None:
      raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
    node.create_dir(pc[-1])
    
  def write_file(self, data, ami_path=None, file_name=None, cache=False):
    parent_node, file_name = self.get_create_path_name(ami_path, file_name)
    if parent_node == None:
      raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
    if file_name == None:
      raise FSError(INVALID_FILE_NAME, file_name=file_name)
    # create file
    node = parent_node.create_file(file_name, data)
    if not cache:
      node.flush()
  
  def read_file(self, ami_path, cache=False):
    node = self.get_file_path_name(ami_path)
    if node == None:
      raise FSError(FILE_NOT_FOUND, file_name=ami_path)
    data = node.get_file_data()
    if not cache:
      node.flush()
    return data
  
  def delete(self, ami_path, wipe=False, all=False):
    node = self.get_path_name(ami_path)
    if node == None:
      raise FSError(INVALID_FILE_NAME, file_name=ami_path)
    node.delete(wipe=wipe, all=all)
Esempio n. 14
0
class ADFSVolume:
    def __init__(self, blkdev):
        self.blkdev = blkdev

        self.boot = None
        self.root = None
        self.root_dir = None
        self.bitmap = None

        self.valid = False
        self.is_ffs = None
        self.name = None

    def open(self):
        # read boot block
        self.boot = BootBlock(self.blkdev)
        self.boot.read()
        # valid root block?
        if self.boot.valid:
            self.is_ffs = self.boot.dos_type > BootBlock.DOS0
            # read root
            self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
            self.root.read()
            if self.root.valid:
                self.name = self.root.name
                # create root dir
                self.root_dir = ADFSVolDir(self, self.root)
                self.root_dir.read()
                # create bitmap
                self.bitmap = ADFSBitmap(self.root)
                self.bitmap.read()
                self.valid = True
            else:
                raise FSError(INVALID_ROOT_BLOCK, block=self.root)
        else:
            raise FSError(INVALID_BOOT_BLOCK, block=self.boot)

    def create(self,
               name,
               create_time=None,
               dos_type=BootBlock.DOS0,
               boot_code=None):
        # create a boot block
        self.boot = BootBlock(self.blkdev)
        self.boot.create()
        self.boot.write()
        # create a root block
        self.root = RootBlock(self.blkdev, self.boot.calc_root_blk)
        self.root.create(name, create_time)
        self.name = name
        # create bitmap
        self.bitmap = ADFSBitmap(self.root)
        self.bitmap.create()
        self.bitmap.write()  # writes root block, too
        # create empty root dir
        self.root_dir = ADFSVolDir(self, self.root)
        self.root_dir.read()
        # all ok
        self.valid = True

    def close(self):
        pass

    def get_path_name(self, path_name, allow_file=True, allow_dir=True):
        if path_name == "" or path_name == "/":
            return self.root_dir
        pc = path_name.split("/")
        fn = []
        for path in pc:
            fn.append(FileName(path))
        return self.root_dir.get_path(fn, allow_file, allow_dir)

    def get_dir_path_name(self, path_name):
        return self.get_path_name(path_name, allow_file=False)

    def get_file_path_name(self, path_name):
        return self.get_path_name(path_name, allow_dir=False)

    def get_create_path_name(self, path_name, suggest_name=None):
        """get a parent node and path name for creation
       return: parent_node_or_none, file_name_or_none
    """
        if path_name == None or path_name == "":
            return self.root_dir, suggest_name
        else:
            # try to get path_name as a directory
            node = self.get_dir_path_name(path_name)
            if node != None:
                return node, suggest_name
            # is a file name appended?
            pos = path_name.rfind('/')
            if pos != -1:
                dir_name = path_name[0:pos]
                file_name = path_name[pos + 1:]
                if len(file_name) == 0:
                    file_name = suggest_name
                node = self.get_dir_path_name(dir_name)
                return node, file_name
            else:
                # its a file name
                return self.root_dir, path_name

    # ----- convenience API -----

    def create_dir(self, ami_path):
        pc = ami_path.split("/")
        # no directory given
        if len(pc) == 0:
            raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
        # no parent dir found
        node = self.get_dir_path_name("/".join(pc[:-1]))
        if node == None:
            raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
        node.create_dir(pc[-1])

    def write_file(self, data, ami_path=None, file_name=None, cache=False):
        parent_node, file_name = self.get_create_path_name(ami_path, file_name)
        if parent_node == None:
            raise FSError(INVALID_PARENT_DIRECTORY, file_name=ami_path)
        if file_name == None:
            raise FSError(INVALID_FILE_NAME, file_name=file_name)
        # create file
        node = parent_node.create_file(file_name, data)
        if not cache:
            node.flush()

    def read_file(self, ami_path, cache=False):
        node = self.get_file_path_name(ami_path)
        if node == None:
            raise FSError(FILE_NOT_FOUND, file_name=ami_path)
        data = node.get_file_data()
        if not cache:
            node.flush()
        return data

    def delete(self, ami_path, wipe=False, all=False):
        node = self.get_path_name(ami_path)
        if node == None:
            raise FSError(INVALID_FILE_NAME, file_name=ami_path)
        node.delete(wipe=wipe, all=all)