Example #1
0
// open a directory, but fail-fast if we can't get path metadata
struct fs_dir_handle* fs_entry_opendir( struct fs_core* core, char const* fs_path, uint64_t user, uint64_t vol, int* err ) {

   // ensure path ends in /
   char path[PATH_MAX];
   strcpy( path, fs_path );

   md_sanitize_path( path );
   
   int rc = fs_entry_revalidate_path( core, path );
   if( rc != 0 ) {
      SG_error("fs_entry_revalidate_path(%s) rc = %d\n", path, rc );
      return NULL;
   }

   uint64_t parent_id = 0;
   char* parent_name = NULL;

   struct fs_entry* dir = fs_entry_resolve_path_and_parent_info( core, path, user, vol, true, err, &parent_id, &parent_name );
   if( dir == NULL ) {
      return NULL;
   }
   // make sure it's a directory
   if( dir->ftype != FTYPE_DIR ) {
      *err = -ENOTDIR;
      fs_entry_unlock( dir );
      return NULL;
   }

   // open this directory
   dir->open_count++;
   struct fs_dir_handle* dirh = fs_dir_handle_create( dir, path, parent_id, parent_name );
   rc = fs_dir_handle_open( dirh );
   if( rc != 0 ) {
      fs_dir_handle_destroy( dirh );
      free( dirh );
      dirh = NULL;
      *err = rc;
   }

   // release the directory
   fs_entry_unlock( dir );
   free( parent_name );
   
   return dirh;
}
Example #2
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;
}
Example #3
0
// Try to open a file, but fail-fast on error.  It behaves as close to POSIX-open as possible, with the following differences:
// * return -EREMOTEIO if the UG could not contact the MS, or if it could not obtain a fresh manifest.
// * return -EUCLEAN if the UG was unable to merge metadata from the MS into its metadata hierarchy (usually indicates a bug)
// * return a driver-specific, non-zero error code given by the driver's create_file() method
// Side-effects:
// * re-downloads and updates metadata for all entries along the path that are stale.
// * re-downloads the manifest for the i-node if it is stale.
struct fs_file_handle* fs_entry_open( struct fs_core* core, char const* _path, uint64_t user, uint64_t vol, int flags, mode_t mode, int* err ) {

    // sanity check
    if( (flags & O_RDONLY) == 0 && (flags & O_RDWR) != 0 && (flags & O_WRONLY) != 0 ) {
        *err = -EINVAL;
        return NULL;
    }

    if( (flags & O_RDONLY) != 0 && (flags & O_WRONLY) != 0 ) {
        *err = -EINVAL;
        return NULL;
    }

    // sanity check: check open mode vs whether or not we're a client and/or have read-only caps
    if( core->gateway == SG_GATEWAY_ANON ) {
        // no authentication; we're read-only
        if( flags & (O_CREAT | O_RDWR | O_WRONLY | O_TRUNC | O_EXCL) ) {
            SG_error("%s", "Opening to create, write, or truncate is forbidden for anonymous gateways\n");
            *err = -EPERM;
            return NULL;
        }
    }

    int rc = 0;
    char* parent_name = NULL;
    uint64_t parent_id = 0;
    struct fs_entry* child = NULL;
    struct fs_entry* parent = NULL;
    char const* reval_method = NULL;
    struct fs_file_handle* ret = NULL;

    // make sure path is sane
    char* path = strdup(_path);
    md_sanitize_path( path );

    // revalidate metadata
    if( flags & O_CREAT ) {

        reval_method = "fs_entry_create_revalidate";
        rc = fs_entry_create_revalidate( core, path, user, vol );
    }
    else {

        reval_method = "fs_entry_open_revalidate";
        rc = fs_entry_open_revalidate( core, path, user, vol );
    }

    if( rc != 0 ) {

        SG_error("%s(%s) rc = %d\n", reval_method, path, rc );

        *err = rc;
        free( path );
        return NULL;
    }

    // get the parent and child
    // NOTE: parent will be write-locked; child will not be
    rc = fs_entry_open_parent_and_child( core, path, user, vol, &parent, &child );
    if( rc != 0 ) {

        SG_error("fs_entry_open_parent_and_child( %s ) rc = %d\n", path, rc );

        *err = rc;
        free( path );
        return NULL;
    }

    if( flags & O_CREAT ) {
        // creating...

        if( child != NULL ) {

            // can't create--child exists
            *err = -EEXIST;

            free( path );
            return NULL;
        }

        // carry out the local create
        rc = fs_entry_do_create( core, path, parent, &child, user, vol, mode );
        if( rc != 0 ) {

            SG_error("fs_entry_do_create( %s ) rc = %d\n", path, rc );
            *err = rc;

            free( path );
            return NULL;
        }

        // preserve these before unlocking, since we'll need them for the file handle
        parent_id = parent->file_id;
        parent_name = strdup( parent->name );

        fs_entry_wlock( child );
        fs_entry_unlock( parent );

        // carry out the remote create
        rc = fs_entry_do_MS_create( core, path, child, parent_id, parent_name );

        if( rc != 0 ) {
            SG_error("fs_entry_do_MS_create(%s) rc = %d\n", path, rc );

            if( rc == -EAGAIN ) {
                *err = rc;
            }
            else {
                *err = -EREMOTEIO;
            }

            // NOTE: parent is guaranteed to exist, since child is attached to it and is write-locked (so it can't be unlinked)
            fs_entry_wlock( parent );
            fs_entry_undo_create( core, path, parent, child );
            fs_entry_unlock( parent );

            child = NULL;

            free( path );
            free( parent_name );
            return NULL;
        }
    }
    else {
        // opening...

        if( child == NULL ) {
            fs_entry_unlock( parent );

            // can't open--child doesn't exist
            *err = -ENOENT;

            free( path );
            return NULL;
        }

        // preserve these before unlocking, since we'll need them for the file handle
        parent_id = parent->file_id;
        parent_name = strdup( parent->name );

        fs_entry_wlock( child );
        fs_entry_unlock( parent );

        // carry out the open
        rc = fs_entry_do_open( core, path, child, user, vol, flags );
        if( rc != 0 ) {

            fs_entry_unlock( child );

            SG_error("fs_entry_do_open(%s) rc = %d\n", path, rc );

            *err = rc;

            free( path );
            free( parent_name );
            return NULL;
        }

        // if we're truncating, do so as well
        if( flags & O_TRUNC ) {
            rc = fs_entry_open_truncate( core, path, child, parent_id, parent_name );

            if( rc != 0 ) {

                fs_entry_unlock( child );

                SG_error("fs_entry_open_truncate(%s) rc = %d\n", path, rc );

                *err = rc;
                free( path );
                free( parent_name );
                return NULL;
            }
        }
    }

    // success!
    child->atime = md_current_time_seconds();

    // give back a file handle
    ret = fs_file_handle_create( core, child, path, parent_id, parent_name );
    fs_file_handle_open( ret, flags, mode );

    fs_entry_unlock( child );

    free( path );
    free( parent_name );
    return ret;
}