Exemple #1
0
// read the target in a symlink (including the null character at the end)
// return the number of bytes read on success (up to MIN(buflen, linkpath size))
// return -EINVAL if the entry isn't a symlink
// return -EIO if the entry is corrupt (indicates a bug in fskit)
// return -errno if path resolution fails
ssize_t fskit_readlink( struct fskit_core* core, char const* path, uint64_t user, uint64_t group, char* buf, size_t buflen ) {

   int err = 0;
   ssize_t num_read = 0;
   struct fskit_entry* fent = NULL;

   // find this
   fent = fskit_entry_resolve_path( core, path, user, group, false, &err );
   if( err != 0 || fent == NULL ) {
      return err;
   }

   // symlink?
   if( fent->type != FSKIT_ENTRY_TYPE_LNK ) {
      fskit_entry_unlock( fent );
      return -EINVAL;
   }

   // sanity check
   if( fent->symlink_target == NULL ) {

      fskit_error("BUG: fskit entry %" PRIX64 " (at %p) is a symlink, but has no target path set\n", fent->file_id, fent );
      fskit_entry_unlock( fent );
      return -EIO;
   }

   // read it (including null character)
   num_read = (ssize_t)MIN( buflen, (unsigned)fent->size + 1 );

   memcpy( buf, fent->symlink_target, num_read );

   fskit_entry_unlock( fent );
   return num_read;
}
Exemple #2
0
int fskit_access( struct fskit_core* core, char const* path, uint64_t user, uint64_t group, mode_t mode ) {

   int err = 0;
   struct fskit_entry* fent = fskit_entry_resolve_path( core, path, user, group, false, &err );
   if( !fent || err ) {
      if( !err ) {
         err = -ENOMEM;
      }
      return err;
   }

   // F_OK implicitly satisfied
   // give the application a chance to process the stat buffer
   struct stat sb;

   err = fskit_entry_fstat( fent, &sb );
   if( err == 0 ) {

      // check against stat buffer
      if( (mode & R_OK) && !FSKIT_ENTRY_IS_READABLE( sb.st_mode, sb.st_uid, sb.st_gid, user, group ) ) {
         err = -EACCES;
      }
      else if( (mode & W_OK) && !FSKIT_ENTRY_IS_WRITEABLE( sb.st_mode, sb.st_uid, sb.st_gid, user, group ) ) {
         err = -EACCES;
      }
      else if( (mode & X_OK) && !FSKIT_ENTRY_IS_EXECUTABLE( sb.st_mode, sb.st_uid, sb.st_gid, user, group ) ) {
         err = -EACCES;
      }
   }

   fskit_entry_unlock( fent );
   return err;
}
Exemple #3
0
// update a file's manifest, in response to a remote call 
// return 0 on success
// return -ENOENT if not found
// return -ESTALE if not local
// return -errno on error 
// NOTE: the permissions will already have been checked by the server
static int UG_impl_manifest_patch( struct SG_gateway* gateway, struct SG_request_data* reqdat, struct SG_manifest* write_delta, void* cls ) {
   
   int rc = 0;
   int ref_rc = 0;
   struct fskit_entry* fent = NULL;
   struct UG_state* ug = (struct UG_state*)SG_gateway_cls( gateway );
   
   struct fskit_core* fs = UG_state_fs( ug );
   struct UG_inode* inode = NULL;
   
   struct ms_client* ms = SG_gateway_ms( gateway );
   uint64_t volume_id = ms_client_get_volume_id( ms );

   rc = UG_consistency_path_ensure_fresh( gateway, reqdat->fs_path );
   if( rc != 0 ) {
      SG_error("UG_consistency_path_ensure_fresh('%s') rc = %d\n", reqdat->fs_path, rc );
      return rc;
   }

   rc = UG_consistency_manifest_ensure_fresh( gateway, reqdat->fs_path );
   if( rc != 0 ) {
      SG_error("UG_consistency_manifest_ensure_fresh('%s') rc = %d\n", reqdat->fs_path, rc );
      return rc;
   }
   
   // look up 
   fent = fskit_entry_resolve_path( fs, reqdat->fs_path, reqdat->user_id, volume_id, true, &rc );
   if( fent == NULL ) {
      
      return rc;
   }
   
   inode = (struct UG_inode*)fskit_entry_get_user_data( fent );
   
   // must be coordinated by us 
   if( UG_inode_coordinator_id( inode ) != SG_gateway_id( gateway ) ) {
      
      fskit_entry_unlock( fent );
      return -ESTALE;
   }
   
   // update the manifest 
   fskit_entry_ref_entry( fent );
   rc = UG_write_patch_manifest( gateway, reqdat, inode, write_delta );
   
   fskit_entry_unlock( fent );

   ref_rc = fskit_entry_unref( fs, reqdat->fs_path, fent );
   if( ref_rc != 0 ) {
      SG_warn("fskit_entry_unref('%s') rc = %d\n", reqdat->fs_path, rc );
   }
   
   return rc;
}
Exemple #4
0
// truncate a file to a given size
// return 0 on success
// return negative on failure
int fskit_trunc( struct fskit_core* core, char const* path, uint64_t user, uint64_t group, off_t new_size ) {

   int err = 0;
   int rc = 0;

   // get the fent
   struct fskit_entry* fent = fskit_entry_resolve_path( core, path, user, group, true, &err );
   if( fent == NULL || err != 0 ) {
      return err;
   }

   // reference the fent, so it won't go anywhere
   fent->open_count++;

   fskit_entry_unlock( fent );

   rc = fskit_run_user_trunc( core, path, fent, new_size, NULL );

   // unreference
   fskit_entry_wlock( fent );

   fent->open_count--;

   // need to free?  note that this may unlock and re-lock fent, but only if it cannot be resolved by any path
   // NOTE: this may unlock and destroy the fent
   rc = fskit_entry_try_destroy_and_free( core, path, fent );
   if( rc > 0 ) {

      // fent was unlocked and destroyed
      rc = 0;
   }
   else if( rc < 0 ) {

      // some error occurred
      fskit_error("fskit_entry_try_destroy(%p) rc = %d\n", fent, rc );
      fskit_entry_unlock( fent );

      return rc;
   }
   else {

      // done with this entry
      fskit_entry_unlock( fent );
   }

   return rc;
}
Exemple #5
0
int fskit_listxattr( struct fskit_core* core, char const* path, uint64_t user, uint64_t group, char* list, size_t size ) {

   int err = 0;
   int rc = 0;

   // get the fent
   struct fskit_entry* fent = fskit_entry_resolve_path( core, path, user, group, false, &err );
   if( fent == NULL || err != 0 ) {
      return err;
   }

   // get the xattr
   rc = fskit_flistxattr( core, fent, list, size );

   fskit_entry_unlock( fent );

   return rc;
}
Exemple #6
0
// change the owner of a path.
// the file must be owned by the given user.
// NOTE: no ingroup-checking occurs--if the caller is the owner, the new_group can be arbitrary.
// the caller should verify that the new_group is allowed by its security model.
// Return 0 on success, negative on error:
// -ENOMEM if oom
// -EPERM if the caller doesn't own the file
// -EACCES if the caller can't search a component of the path
// -ENOTDIR if the path has a parent non-directory
// -ENOENT if the entry doesn't exist
int fskit_chown( struct fskit_core* core, char const* path, uint64_t user, uint64_t group, uint64_t new_user, uint64_t new_group ) {

   int err = 0;

   struct fskit_entry* fent = fskit_entry_resolve_path( core, path, user, group, true, &err );
   if( !fent || err ) {
      if( !err ) {
         err = -ENOMEM;
      }
      return err;
   }

   // can't chown unless we own the file
   if( fent->owner != user ) {
      fskit_entry_unlock( fent );
      return -EPERM;
   }

   fskit_entry_set_owner_and_group( fent, new_user, new_group );

   fskit_entry_unlock( fent );

   return err;
}
Exemple #7
0
Fichier : fs.cpp Projet : 8l/vdev
// load the filesystem with metadata from under the mountpoint
// return 0 on success 
// return -ENOMEM on OOM
static int vdevfs_dev_import( struct fskit_fuse_state* fs, void* arg ) {
   
   struct vdevfs* vdev = (struct vdevfs*)arg;
   int rc = 0;
   queue<int> dirfds;           // directory descriptors
   queue<char*> dirpaths;       // relative paths to the mountpoint 
   struct fskit_entry* dir_ent = NULL;
   
   struct vdevfs_scandirat_context scan_context;
   
   char* root = vdev_strdup_or_null("/");
   if( root == NULL ) {
      return -ENOMEM;
   }
   
   int root_fd = dup( vdev->mountpoint_dirfd );
   if( root_fd < 0 ) {
      
      vdev_error("dup(%d) rc = %d\n", vdev->mountpoint_dirfd, rc );
      rc = -errno;
      free( root );
      return rc;
   }
   
   // start at the mountpoint
   try {
      
      dirfds.push( root_fd );
      dirpaths.push( root );
   }
   catch( bad_alloc& ba ) {
      
      free( root );
      return -ENOMEM;
   }
   
   while( dirfds.size() > 0 ) {
      
      // next directory 
      int dirfd = dirfds.front();
      char* dirpath = dirpaths.front();
      
      dirfds.pop();
      dirpaths.pop();
      
      // look up this entry 
      dir_ent = fskit_entry_resolve_path( fskit_fuse_get_core( vdev->fs ), dirpath, 0, 0, true, &rc );
      if( rc != 0 ) {
         
         // shouldn't happen--we're going breadth-first 
         vdev_error("fskit_entry_resolve_path('%s') rc = %d\n", dirpath, rc );
         
         close( dirfd );
         free( dirpath );
         dirpath = NULL;
        
         break;
      }
      
      // make a scan context 
      vdevfs_scandirat_context_init( &scan_context, fskit_fuse_get_core( vdev->fs ), dir_ent, dirpath, &dirfds, &dirpaths );
      
      // scan this directory 
      rc = vdev_load_all_at( dirfd, vdevfs_scandirat_context_callback, &scan_context );
      
      fskit_entry_unlock( dir_ent );
      
      if( rc != 0 ) {
         
         // failed
         vdev_error("vdev_load_all_at(%d, '%s') rc = %d\n", dirfd, dirpath, rc );
      }
      
      close( dirfd );
      free( dirpath );
      dirpath = NULL;
      
      if( rc != 0 ) {
         break;
      }
   }
   
   // free any remaining directory state 
   size_t num_dirfds = dirfds.size();
   for( unsigned int i = 0; i < num_dirfds; i++ ) {
      
      int next_dirfd = dirfds.front();
      dirfds.pop();
      
      close( next_dirfd );
   }
   
   size_t num_dirpaths = dirpaths.size();
   for( unsigned int i = 0; i < num_dirpaths; i++ ) {
      
      char* path = dirpaths.front();
      dirpaths.pop();
      
      free( path );
   }
   
   return rc;
}
Exemple #8
0
// create/open a file, with the given flags and (if creating) mode
// on success, return a file handle to the created/opened file.
// on failure, return NULL and set *err to the appropriate errno
struct fskit_file_handle* fskit_open_ex( struct fskit_core* core, char const* _path, uint64_t user, uint64_t group, int flags, mode_t mode, void* cls, int* err ) {

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

   int rc = 0;

   char* path = strdup(_path);

   if( path == NULL ) {
      *err = -ENOMEM;
      return NULL;
   }

   fskit_sanitize_path( path );

   size_t basename_len = fskit_basename_len( path );
   if( basename_len > FSKIT_FILESYSTEM_NAMEMAX ) {

      free( path );
      *err = -ENAMETOOLONG;

      return NULL;
   }

   void* handle_data = NULL;

   // resolve the parent of this child (and write-lock it)
   char* path_dirname = fskit_dirname( path, NULL );
   char path_basename[FSKIT_FILESYSTEM_NAMEMAX + 1];

   memset( path_basename, 0, FSKIT_FILESYSTEM_NAMEMAX + 1 );

   fskit_basename( path, path_basename );

   struct fskit_file_handle* ret = NULL;

   // write-lock parent--we need to ensure that the child does not disappear on us between attaching it and routing the user-given callback
   struct fskit_entry* parent = fskit_entry_resolve_path( core, path_dirname, user, group, true, err );

   if( parent == NULL ) {

      fskit_safe_free( path_dirname );
      fskit_safe_free( path );

      // err is set appropriately
      return NULL;
   }

   fskit_safe_free( path_dirname );

   rc = fskit_do_parent_check( parent, flags, user, group );
   if( rc != 0 ) {

      // can't perform this operation
      fskit_entry_unlock( parent );
      fskit_safe_free( path );
      *err = rc;
      return NULL;
   }

   // resolve the child (which may be in the process of being deleted)
   struct fskit_entry* child = fskit_entry_set_find_name( parent->children, path_basename );
   bool created = false;

   if( flags & O_CREAT ) {

      if( child != NULL ) {

         fskit_entry_wlock( child );

         // it might have been marked for garbage-collection
         rc = fskit_entry_try_garbage_collect( core, path, parent, child );

         if( rc >= 0 ) {

            if( rc == 0 ) {
               
               // not destroyed, but no longer attached
               fskit_entry_unlock( child );
            }

            // safe to create
            child = NULL;
         }
         else {

            // can't garbage-collect--child still exists
            fskit_entry_unlock( parent );
            fskit_entry_unlock( child );
            fskit_safe_free( path );

            if( rc == -EEXIST ) {

               *err = -EEXIST;
               return NULL;
            }
            else {

               // shouldn't happen
               fskit_error("BUG: fskit_entry_try_garbage_collect(%s) rc = %d\n", path, rc );

               *err = -EIO;
            }

            return NULL;
         }
      }

      if( child == NULL ) {

         // can create!
         // NOTE: do *not* lock child--it has to be unlocked for running user-given routes
         rc = fskit_do_create( core, parent, path, mode, user, group, cls, &child, &handle_data );
         if( rc != 0 ) {

            fskit_entry_unlock( parent );
            fskit_safe_free( path );
            *err = rc;
            return NULL;
         }

         // created!
         created = true;
      }
   }

   else if( child == NULL ) {

      // not found
      fskit_entry_unlock( parent );
      fskit_safe_free( path );
      *err = -ENOENT;
      return NULL;
   }

   // now child exists.
   // don't lock it, though, since we have to pass it to truncate or open 
   
   // do we have to truncate?
   if( (flags & O_TRUNC) && (flags & (O_RDWR | O_WRONLY)) ) {

      // run user truncate
      // NOTE: do *not* lock it--it has to be unlocked for running user-given routes
      rc = fskit_run_user_trunc( core, path, child, 0, NULL );
      if( rc != 0 ) {

         // truncate failed
         fskit_entry_unlock( parent );
         fskit_safe_free( path );
         *err = rc;
         return NULL;
      }
   }

   if( !created ) {
      
      // do the open
      // NOTE: do *not* lock it--it has to be unlocked for running user-given routes
      rc = fskit_do_open( core, path, parent, child, flags, user, group, &handle_data );
      if( rc != 0 ) {

         // open failed
         fskit_entry_unlock( parent );
         fskit_safe_free( path );
         *err = rc;
         return NULL;
      }
   }
   
   // done with parent 
   fskit_entry_unlock( parent );

   // still here--we can open the file now!
   fskit_entry_set_atime( child, NULL );
   ret = fskit_file_handle_create( core, child, path, flags, handle_data );

   fskit_safe_free( path );

   if( ret == NULL ) {
      // only possible if we're out of memory!
      *err = -ENOMEM;
   }

   return ret;
}
Exemple #9
0
// open a directory.
// On success, return an fskit_dir_handle
// Return any error code via the *err argument (which will be non-zero if there was an error).
// on error, return NULL, and set *err appropriately:
// * -ENAMETOOLONG if _path is too long
// * -EACCES if some part of _path is in accessible to the given user and group
// * -ENOTDIR if the entry referred to by _path isn't a directory
// * -ENOENT if the entry doesn't exist
// * -ENOMEM on OOM
struct fskit_dir_handle* fskit_opendir( struct fskit_core* core, char const* _path, uint64_t user, uint64_t group, int* err ) {

   void* app_handle_data = NULL;
   int rc = 0;
   struct fskit_entry* dir = NULL;
   struct fskit_dir_handle* dirh = NULL;
   char path[PATH_MAX];
   
   if( strlen(_path) >= PATH_MAX ) {
      // too long
      *err = -ENAMETOOLONG;
      return NULL;
   }

   // ensure path ends in /
   memset( path, 0, PATH_MAX );
   strncpy( path, _path, PATH_MAX - 1 );

   fskit_sanitize_path( path );

   dir = fskit_entry_resolve_path( core, path, user, group, true, err );
   if( dir == NULL ) {
      // resolution error; err is set appropriately
      return NULL;
   }

   // make sure it's a directory
   if( dir->type != FSKIT_ENTRY_TYPE_DIR ) {
      *err = -ENOTDIR;
      fskit_entry_unlock( dir );
      return NULL;
   }

   // reference it--it cannot be unlinked 
   fskit_entry_ref_entry( dir );
   fskit_entry_unlock( dir );
   
   // generate handle data
   rc = fskit_run_user_open( core, path, dir, 0, &app_handle_data );
   
   fskit_entry_wlock( dir );
   
   if( rc != 0 ) {

      // user-run open code failed
      fskit_error("fskit_run_user_open(%s) rc = %d\n", path, rc );
      fskit_entry_unlock( dir );
      *err = rc;
      
      fskit_entry_unref( core, path, dir );
      return NULL;
   }
   
   // make a handle to it
   dirh = fskit_dir_handle_create( dir, path, app_handle_data );
   if( dirh == NULL ) {
      
      // OOM
      fskit_entry_unlock( dir );
      fskit_entry_unref( core, path, dir );
      *err = -ENOMEM;
   }

   else {
      // release the directory
      fskit_entry_unlock( dir );
   }

   return dirh;
}