/** * Create an inode. * @param pin_dir The directory on which the inode resides. * @param pathname The pathname. * @param mode Inode mode. * @param b Block to start searching. * @return Zero on success. */ PRIVATE ext2_inode_t * ext2_new_inode(ext2_inode_t * pin_dir, char * pathname, mode_t mode, block_t initial_block, uid_t uid, gid_t gid) { /* the directory does not actually exist */ if (pin_dir->i_links_count == 0) { err_code = ENOENT; return NULL; } char * lastc = pathname; while (*lastc != '/') { lastc--; } lastc++; /* try to get the last component */ ext2_inode_t * pin = ext2_advance(pin_dir, lastc, 0); if (pin == NULL && err_code == ENOENT) { pin = ext2_alloc_inode(pin_dir, mode); if (pin == NULL) return NULL; } pin->i_uid = uid; pin->i_gid = gid; pin->i_links_count++; pin->i_block[0] = initial_block; /* update all times */ pin->i_update = ATIME | CTIME | MTIME; ext2_rw_inode(pin, DEV_WRITE); /* create the directory entry */ int retval = ext2_search_dir(pin_dir, lastc, &pin->i_num, SD_MAKE, 0, pin->i_mode & I_TYPE); if (retval != 0) { pin->i_links_count--; pin->i_dirt = 1; put_ext2_inode(pin); err_code = retval; return NULL; } if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) { retval = EEXIST; } err_code = retval; return pin; }
SVFUNC(ext2_mknod, inode_t *_inode) { ext2_device_t *device; ext2_vinode_t *inode; int status; if (!_inode) { THROWV(EFAULT); } device = (ext2_device_t *) _inode->device; inode = (ext2_vinode_t *) _inode; status = ext2_alloc_inode(device, (uint32_t *) &(_inode->id)); if (status) THROWV(status); memset(&(inode->inode), 0, sizeof(ext2_inode_t)); ext2_vfstoe2_inode(inode, _inode->id); CHAINRETV(ext2_store_e2inode,device, &(inode->inode), _inode->id); }
/* The user must define this function. Allocate a new node to be of mode MODE in locked directory DP (don't actually set the mode or modify the dir, that will be done by the caller); the user responsible for the request can be identified with CRED. Set *NP to be the newly allocated node. */ error_t diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node) { error_t err; int sex, block; struct node *np; struct stat *st; ino_t inum; assert (!diskfs_readonly); inum = ext2_alloc_inode (dir->cache_id, mode); if (inum == 0) return ENOSPC; err = diskfs_cached_lookup (inum, &np); if (err) return err; st = &np->dn_stat; if (st->st_blocks) { st->st_blocks = 0; np->dn_set_ctime = 1; } /* Zero out the block pointers in case there's some noise left on disk. */ for (block = 0; block < EXT2_N_BLOCKS; block++) if (np->dn->info.i_data[block] != 0) { np->dn->info.i_data[block] = 0; np->dn_set_ctime = 1; } if (np->dn->info_i_translator != 0) { np->dn->info_i_translator = 0; np->dn_set_ctime = 1; } st->st_mode &= ~S_IPTRANS; if (np->allocsize) { st->st_size = 0; np->allocsize = 0; np->dn_set_ctime = 1; } /* Propagate initial inode flags from the directory, as Linux does. */ np->dn->info.i_flags = ext2_mask_flags(mode, dir->dn->info.i_flags & EXT2_FL_INHERITED); st->st_flags = 0; /* * Set up a new generation number for this inode. */ pthread_spin_lock (&generation_lock); sex = diskfs_mtime->seconds; if (++next_generation < (u_long)sex) next_generation = sex; st->st_gen = next_generation; pthread_spin_unlock (&generation_lock); alloc_sync (np); *node = np; return 0; }