// low-level mkdir int fs_entry_mkdir_lowlevel( struct fs_core* core, char const* path, struct fs_entry* parent, char const* path_basename, mode_t mode, uint64_t user, uint64_t vol, int64_t mtime_sec, int32_t mtime_nsec ) { // resolve the child struct fs_entry* child = fs_entry_set_find_name( parent->children, path_basename ); int err = 0; if( child == NULL ) { // create an fs_entry and attach it child = CALLOC_LIST( struct fs_entry, 1 ); fs_entry_init_dir( core, child, path_basename, 0, fs_entry_next_file_version(), user, 0, vol, mode, mtime_sec, mtime_nsec, 0, 0 ); // add . and .. fs_entry_set_insert( child->children, ".", child ); fs_entry_set_insert( child->children, "..", parent ); fs_entry_attach_lowlevel( core, parent, child ); }
// make a node (regular files only at this time) int fs_entry_mknod( struct fs_core* core, char const* path, mode_t mode, dev_t dev, uint64_t user, uint64_t vol ) { // only regular files at this time... if( ! ( S_ISREG( mode ) || S_ISFIFO( mode ) ) ) { return -ENOTSUP; } // revalidate this path int rc = fs_entry_revalidate_path( core, path ); if( rc != 0 && rc != -ENOENT ) { // consistency cannot be guaranteed SG_error("fs_entry_revalidate_path(%s) rc = %d\n", path, rc ); return rc; } int err = 0; // get the parent directory and lock it char* path_dirname = md_dirname( path, NULL ); struct fs_entry* parent = fs_entry_resolve_path( core, path_dirname, user, vol, true, &err ); free( path_dirname ); if( !IS_DIR_READABLE( parent->mode, parent->owner, parent->volume, user, vol ) ) { // not searchable fs_entry_unlock( parent ); return -EACCES; } if( !IS_WRITEABLE( parent->mode, parent->owner, parent->volume, user, vol ) ) { // not writeable fs_entry_unlock( parent ); return -EACCES; } uint64_t parent_id = parent->file_id; char* parent_name = strdup( parent->name ); char* path_basename = md_basename( path, NULL ); // make sure it doesn't exist already (or isn't in the process of being deleted, since we might have to re-create it if deleting it fails) if( fs_entry_set_find_name( parent->children, path_basename ) != NULL ) { free( path_basename ); fs_entry_unlock( parent ); free( parent_name ); return -EEXIST; } struct fs_entry* child = (struct fs_entry*)calloc( sizeof(struct fs_entry), 1 ); struct timespec ts; clock_gettime( CLOCK_REALTIME, &ts ); int mmode = 0; if (S_ISFIFO(mode)) { mmode = ( mode & 0777 ) | S_IFIFO; err = fs_entry_init_fifo( core, child, path_basename, 0, fs_entry_next_file_version(), user, core->gateway, vol, mmode, 0, ts.tv_sec, ts.tv_nsec, 0, 0 ); } if (S_ISREG(mode)) { mmode = ( mode & 0777 ); err = fs_entry_init_file( core, child, path_basename, 0, fs_entry_next_file_version(), user, core->gateway, vol, mmode, 0, ts.tv_sec, ts.tv_nsec, 0, 0 ); } if( err == 0 ) { // mark it as created in this session child->created_in_session = true; // we're creating, so this manifest is initialized (to zero blocks) child->manifest->initialize_empty( child->version ); fs_entry_wlock( child ); // call the driver err = driver_create_file( core, core->closure, path, child ); if( err != 0 ) { // undo SG_error("driver_create_file(%s) rc = %d\n", path, err ); child->open_count = 0; fs_entry_unlock( child ); fs_entry_destroy( child, false ); free( child ); } else { // attach the file fs_entry_attach_lowlevel( core, parent, child ); struct md_entry data; fs_entry_to_md_entry( core, &data, child, parent_id, parent_name ); // create the child on the MS, obtaining its file ID and write nonce err = ms_client_create( core->ms, &child->file_id, &child->write_nonce, &data ); md_entry_free( &data ); if( err != 0 ) { SG_error( "ms_client_create(%s) rc = %d\n", path, err ); err = -EREMOTEIO; child->open_count = 0; fs_entry_unlock( child ); fs_entry_detach_lowlevel( core, parent, child ); free( child ); } else { fs_entry_unlock( child ); } } } fs_entry_unlock( parent ); free( parent_name ); free( path_basename ); return err; }
// carry out the create locally. // check permissions, initialize the child, and add it as a child of parent. // return the initialized child (which will NOT be locked) via *ret_child // return 0 on success // return -EACCES on permission failure // parent MUST be write locked int fs_entry_do_create( struct fs_core* core, char const* path, struct fs_entry* parent, struct fs_entry** ret_child, uint64_t user, uint64_t vol, mode_t mode ) { int rc = 0; struct fs_entry* child = NULL; if( !IS_WRITEABLE(parent->mode, parent->owner, parent->volume, user, vol) ) { // can't create return -EACCES; } else { struct timespec ts; clock_gettime( CLOCK_REALTIME, &ts ); // can create--initialize the child child = SG_CALLOC( struct fs_entry, 1 ); char* path_basename = md_basename( path, NULL ); rc = fs_entry_init_file( core, child, path_basename, 0, fs_entry_next_file_version(), user, core->gateway, vol, mode, 0, ts.tv_sec, ts.tv_nsec, 0, 0 ); free( path_basename ); if( rc != 0 ) { SG_error("fs_entry_init_file(%s) rc = %d\n", path, rc ); fs_entry_destroy( child, false ); free( child ); return rc; } else { // mark it as created in this session child->created_in_session = true; // we're creating, so this manifest is initialized (to zero blocks) child->manifest->initialize_empty( child->version ); // run the driver int driver_rc = driver_create_file( core, core->closure, path, child ); if( driver_rc != 0 ) { SG_error("driver_create_file(%s) rc = %d\n", path, driver_rc ); fs_entry_destroy( child, false ); free( child ); return driver_rc; } // insert it into the filesystem fs_entry_wlock( child ); // open it child->open_count++; fs_entry_setup_working_data( core, child ); fs_entry_attach_lowlevel( core, parent, child ); fs_entry_unlock( child ); *ret_child = child; } } return 0; }