Exemplo n.º 1
0
// remove a directory, if it is empty
int fs_entry_rmdir( struct fs_core* core, char const* path, uint64_t user, uint64_t volume ) {

   if( core->gateway == GATEWAY_ANON ) {
      errorf("%s", "Removing directories is forbidden for anonymous gateways\n");
      return -EPERM;
   }
   
   // get some info about this directory first
   int rc = 0;
   
   char* fpath = strdup( path );
   md_sanitize_path( fpath );
   
   // revalidate this path
   rc = fs_entry_revalidate_path( core, volume, fpath );
   if( rc != 0 && rc != -ENOENT ) {
      // consistency cannot be guaranteed
      errorf("fs_entry_revalidate_path(%s) rc = %d\n", fpath, rc );
      free( fpath );
      return rc;
   }
   
   free( fpath );

   int err = 0;
   struct fs_entry* dent = fs_entry_resolve_path( core, path, user, volume, false, &err );
   if( !dent || err ) {
      return err;
   }

   if( dent->ftype != FTYPE_DIR ) {
      fs_entry_unlock( dent );
      return -ENOTDIR;
   }

   char* path_dirname = md_dirname( path, NULL );

   struct fs_entry* parent = fs_entry_resolve_path( core, path_dirname, user, volume, true, &err );

   free( path_dirname );

   if( !parent || err ) {
      fs_entry_unlock( dent );

      return err;
   }

   // IS THE PARENT EMPTY?
   if( fs_entry_set_count( dent->children ) > 2 ) {
      // nope
      fs_entry_unlock( dent );
      fs_entry_unlock( parent );

      return -ENOTEMPTY;
   }


   struct md_entry ent;
   fs_entry_to_md_entry( core, &ent, dent, parent->file_id, parent->name );

   // tell the MS that this directory should go away
   rc = ms_client_delete( core->ms, &ent );
   md_entry_free( &ent );

   if( rc != 0 ) {
      errorf( "ms_client_delete(%s) rc = %d\n", path, rc );
      rc = -EREMOTEIO;

      fs_entry_unlock( dent );
      fs_entry_unlock( parent );
   }
   else {

      fs_entry_unlock( dent );

      // detach from the filesystem 
      rc = fs_entry_detach_lowlevel( core, parent, dent );
      if( rc != 0 ) {
         errorf("fs_entry_detach_lowlevel(%s) rc = %d\n", path, rc );
      }
      
      fs_entry_unlock( parent );
   }
   
   return rc;
}
Exemplo n.º 2
0
// lowlevel unlink operation--given an fs_entry and the name of an entry
// parent must be write-locked!
// child must NOT be locked!
int fs_entry_detach_lowlevel( struct fs_core* core, struct fs_entry* parent, struct fs_entry* child ) {

   if( parent == child ) {
      // tried to detach .
      return -ENOTEMPTY;
   }

   if( child == NULL ) {
      // no entry found
      return -ENOENT;
   }

   fs_entry_wlock( child );

   if( child->link_count == 0 ) {
      // child is invalid
      fs_entry_unlock( child );
      return -ENOENT;
   }

   // if the child is a directory, and it's not empty, then don't proceed
   if( child->ftype == FTYPE_DIR && fs_entry_set_count( child->children ) > 2 ) {
      // not empty
      fs_entry_unlock( child );
      return -ENOTEMPTY;
   }

   // unlink
   fs_entry_set_remove( parent->children, child->name );
   
   struct timespec ts;
   clock_gettime( CLOCK_REALTIME, &ts );
   parent->mtime_sec = ts.tv_sec;
   parent->mtime_nsec = ts.tv_nsec;


   int rc = 0;

   if( child->open_count == 0 ) {
      
      // evict blocks, if there is a file to begin with
      if( child->ftype == FTYPE_FILE && child->file_id != 0 ) {
         rc = md_cache_evict_file( core->cache, child->file_id, child->version );
         if( rc == -ENOENT ) {
            // not a problem
            rc = 0;
         }
      }
      
      if( rc == 0 ) {
         fs_entry_destroy( child, false );
         free( child );
         child = NULL;
      }
      else {
         fs_entry_unlock( child );
      }
   }
   else {
      fs_entry_unlock( child );
   }

   if( rc == 0 && child ) {
      child->link_count = 0;
   }

   return rc;
}