// stat an inode directly // fill in the stat buffer, and call the user route // NOTE: fent must NOT be locked, but it must be ref'ed int fskit_fstat( struct fskit_core* core, char const* fs_path, struct fskit_entry* fent, struct stat* sb ) { // fill in defaults fskit_entry_rlock( fent ); fskit_entry_fstat( fent, sb ); fskit_entry_unlock( fent ); // route to user callback int rc = fskit_do_user_stat( core, fs_path, fent, sb ); 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; }
// readdir: equivocate about which devices exist, depending on who's asking // omit entries if the ACLs forbid them int vdevfs_readdir( struct fskit_core* core, struct fskit_match_group* grp, struct fskit_entry* fent, struct fskit_dir_entry** dirents, size_t num_dirents ) { int rc = 0; struct fskit_entry* child = NULL; // entries to omit in the listing vector<int> omitted_idx; pid_t pid = 0; uid_t uid = 0; gid_t gid = 0; struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); struct stat sb; struct pstat ps; char* child_path = NULL; pid = fskit_fuse_get_pid(); uid = fskit_fuse_get_uid( fs_state ); gid = fskit_fuse_get_gid( fs_state ); vdev_debug("vdevfs_readdir(%s, %zu) from user %d group %d task %d\n", grp->path, num_dirents, uid, gid, pid ); // see who's asking rc = pstat( pid, &ps, 0 ); if( rc != 0 ) { vdev_error("pstat(%d) rc = %d\n", pid, rc ); return -EIO; } for( unsigned int i = 0; i < num_dirents; i++ ) { // skip . and .. if( strcmp(dirents[i]->name, ".") == 0 || strcmp(dirents[i]->name, "..") == 0 ) { continue; } // find the associated fskit_entry child = fskit_dir_find_by_name( fent, dirents[i]->name ); if( child == NULL ) { // strange, shouldn't happen... continue; } fskit_entry_rlock( child ); // construct a stat buffer from what we actually need memset( &sb, 0, sizeof(struct stat) ); sb.st_uid = child->owner; sb.st_gid = child->group; sb.st_mode = fskit_fullmode( child->type, child->mode ); child_path = fskit_fullpath( grp->path, child->name, NULL ); if( child_path == NULL ) { // can't continue; OOM fskit_entry_unlock( child ); rc = -ENOMEM; break; } // filter it rc = vdev_acl_apply_all( vdev->config, vdev->acls, vdev->num_acls, child_path, &ps, uid, gid, &sb ); if( rc < 0 ) { vdev_error("vdev_acl_apply_all('%s', uid=%d, gid=%d, pid=%d) rc = %d\n", child_path, uid, gid, pid, rc ); rc = -EIO; } else if( rc == 0 || (sb.st_mode & 0777) == 0 ) { // omit this one vdev_debug("Filter '%s'\n", child->name ); omitted_idx.push_back( i ); rc = 0; } else { // success; matched rc = 0; } fskit_entry_unlock( child ); free( child_path ); // error? if( rc != 0 ) { break; } } // skip ACL'ed entries for( unsigned int i = 0; i < omitted_idx.size(); i++ ) { fskit_readdir_omit( dirents, omitted_idx[i] ); } return rc; }