Esempio n. 1
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;
}
Esempio n. 2
0
// truncate a file to a given size
// return zero on success
// return negative on failure.
int fskit_ftrunc( struct fskit_core* core, struct fskit_file_handle* fh, off_t new_size ) {

   fskit_file_handle_rlock( fh );

   // sanity check
   if( (fh->flags & (O_RDWR | O_WRONLY)) == 0 ) {

      fskit_file_handle_unlock( fh );
      return -EBADF;
   }

   int rc = fskit_run_user_trunc( core, fh->path, fh->fent, new_size, fh->app_data );

   fskit_file_handle_unlock( fh );

   return rc;
}
Esempio n. 3
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;
}