// write up to buflen bytes into buf, starting at the given offset in the file. // return the number of bytes written on success. // return negative on failure. ssize_t fskit_write( struct fskit_core* core, struct fskit_file_handle* fh, char const* buf, size_t buflen, off_t offset ) { fskit_file_handle_rlock( fh ); // sanity check if( (fh->flags & (O_RDWR | O_WRONLY)) == 0 ) { fskit_file_handle_unlock( fh ); return -EBADF; } ssize_t num_written = fskit_run_user_write( core, fh->path, fh->fent, buf, buflen, offset, fh->app_data ); if( num_written >= 0 ) { // update metadata fskit_entry_wlock( fh->fent ); fskit_entry_set_mtime( fh->fent, NULL ); fskit_entry_set_atime( fh->fent, NULL ); fh->fent->size = ((unsigned)(offset + buflen) > fh->fent->size ? offset + buflen : fh->fent->size); fskit_entry_unlock( fh->fent ); } fskit_file_handle_unlock( fh ); return num_written; }
// 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; }
// stat a file's block--build a manifest request, and set its mode // return 0 on success // return -ESTALE if the inode is not local // return -ENOENT if we don't have it // return -ENOMEM on OOM // return -errno on error static int UG_impl_stat_block( struct SG_gateway* gateway, struct SG_request_data* reqdat, struct SG_request_data* entity_info, mode_t* mode, void* cls ) { int rc = 0; struct UG_state* ug = (struct UG_state*)SG_gateway_cls( gateway ); int64_t block_version = 0; UG_handle_t* fi = NULL; struct fskit_entry* fent = NULL; struct UG_inode* inode = NULL; uint64_t file_id = 0; int64_t file_version = 0; int close_rc = 0; fi = UG_open( ug, reqdat->fs_path, O_RDONLY, &rc ); if( fi == NULL ) { SG_error("UG_open('%s') rc = %d\n", reqdat->fs_path, rc ); return rc; } fskit_file_handle_rlock( fi->fh ); fent = fskit_file_handle_get_entry( fi->fh ); if( fent == NULL ) { SG_error("BUG: no entry for handle %p\n", fi->fh ); exit(1); } fskit_entry_rlock( fent ); inode = (struct UG_inode*)fskit_entry_get_user_data( fent ); if( inode == NULL ) { SG_error("BUG: no inode for entry %p\n", fent ); exit(1); } if( UG_inode_coordinator_id( inode ) != SG_gateway_id( gateway ) ) { // not ours SG_error("Not the coordinator of '%s' (it is now %" PRIu64 ")\n", reqdat->fs_path, UG_inode_coordinator_id( inode ) ); fskit_entry_unlock( fent ); fskit_file_handle_unlock( fi->fh ); rc = UG_close( ug, fi ); if( rc != 0 ) { SG_error("UG_close('%s') rc = %d\n", reqdat->fs_path, rc ); } return rc; } file_id = UG_inode_file_id( inode ); file_version = UG_inode_file_version( inode ); if( mode != NULL ) { *mode = fskit_entry_get_mode( fent ); } if( entity_info != NULL ) { rc = UG_getblockinfo( ug, reqdat->block_id, &block_version, NULL, fi ); } fskit_entry_unlock( fent ); fskit_file_handle_unlock( fi->fh ); inode = NULL; if( rc != 0 ) { SG_error("UG_getblockinfo(%s[%" PRIu64 "]) rc = %d\n", reqdat->fs_path, reqdat->block_id, rc); goto UG_impl_stat_block_out; } rc = SG_request_data_init_block( gateway, reqdat->fs_path, file_id, file_version, reqdat->block_id, block_version, entity_info ); if( rc != 0 ) { SG_error("SG_request_data_init_block rc = %d\n", rc ); goto UG_impl_stat_block_out; } UG_impl_stat_block_out: close_rc = UG_close( ug, fi ); if( close_rc != 0 ) { SG_error("UG_close('%s') rc = %d\n", reqdat->fs_path, close_rc ); } return rc; }