/* open file and return fd; to make our life easier, always open RW */ int fs_open(const char *filename, int flags, int mode) { int flag, fd; struct inode_s *ino, *dir; ino = dir = NULL; flag = (flags & O_CREAT) ? FS_SEARCH_CREAT : FS_SEARCH_GET; dir = current_dir(); if ( (ino = find_inode(dir, filename, flag)) == NULL) goto err; release_inode(dir); if (ino->i_zone[0] == 0 && (flags & O_CREAT)) fill_inode(ino, mode); if (flags & O_TRUNC) { ino->i_size = 0; ino->i_dirty = 1; } if ( (fd = get_fd(ino, (flags & O_APPEND) ? ino->i_size : 0)) == ERROR) goto err; return fd; err: release_inode(dir); release_inode(ino); return ERROR; }
/* make new device file in /dev folder, with type, major and minor numbers */ int fs_make_dev(const char *name, int type, dev_t major, dev_t minor) { struct inode_s *ino, *dev; ino = dev = NULL; if ( (dev = find_inode(NULL, "/dev", FS_SEARCH_CREAT)) == NULL) debug_panic("fs_make_dev: error searching/creating /dev"); if ( (ino = find_inode(dev, name, FS_SEARCH_CREAT)) == NULL) goto err; ino->i_zone[0] = major; ino->i_zone[1] = minor; ino->i_dirty = 1; release_inode(dev); release_inode(ino); return OK; err: release_inode(dev); release_inode(ino); return ERROR; }
static struct inode *truncate_existing(struct filsys *fs, char *name, int len) { struct inode *inode; vfs_ino_t ino; ino = lookup_name(fs, DFS_INODE_ROOT, name, len); if (ino == -1) return NULL; inode = get_inode(fs, ino); if (!inode) return NULL; if (VFS_S_ISDIR(inode->desc->mode)) { release_inode(inode); return NULL; } if (truncate_inode(inode, 0) < 0) { release_inode(inode); return NULL; } inode->desc->size = 0; mark_inode_dirty(inode); return inode; }
static bool_t L2_Translate_m (USDCallback_cl *self, USD_StreamID sid /* IN */, USD_ClientID cid /* IN */, const FileIO_Request *req /* IN */, USD_Extent *extent /* OUT */, uint32_t *notification /* OUT */ ) { ext2fs_st *st = self->st; Client_st *cur; Ext2_Handle handle; struct inode *ino; FTRC("entered: self=%p, st=%p.\n", self, st); if (req->nblocks == 0) { /* Inode prefectch */ ino = get_inode(st, req->user1); release_inode(st, ino); return False; } /* All checked once by L1 (XXX are there concurrency problems?) */ cur = (Client_st *)(word_t)cid; handle = req->user1; ino = cur->handles[handle].ino; translate(st, ino, req, extent); FTRC("leaving, returning true.\n"); return(True); }
int dfs_opendir(struct file *filp, char *name) { struct filsys *fs; int len; vfs_ino_t ino; struct inode *inode; fs = (struct filsys *) filp->fs->data; len = strlen(name); ino = lookup_name(fs, DFS_INODE_ROOT, name, len); if (ino == -1) return -1; inode = get_inode(fs, ino); if (!inode) return -1; if (!VFS_S_ISDIR(inode->desc->mode)) { release_inode(inode); return -1; } filp->data = inode; return 0; }
static int create_new(struct filsys *fs, char *name, ino_t ino, int mode, struct inode **retval) { struct inode *dir; struct inode *inode; int rc; int len = strlen(name); rc = diri(fs, &name, &len, &dir); if (rc < 0) return rc; rc = find_dir_entry(dir, name, len, NULL); if (rc != -ENOENT) { release_inode(dir); return rc >= 0 ? -EEXIST : rc; } if (ino == NOINODE) { inode = alloc_inode(dir, S_IFREG | (mode & S_IRWXUGO)); if (!inode) rc = -ENOSPC; } else { rc = get_inode(fs, ino, &inode); if (rc < 0) inode = NULL; if (inode) { inode->desc->ctime = inode->desc->mtime = time(NULL); inode->desc->uid = inode->desc->gid = 0; inode->desc->mode = S_IFREG | 0700; inode->desc->linkcount++; mark_inode_dirty(inode); } } if (!inode) { release_inode(dir); return rc; } rc = add_dir_entry(dir, name, len, inode->ino); if (rc < 0) { unlink_inode(inode); release_inode(inode); release_inode(dir); return rc; } release_inode(dir); *retval = inode; return 0; }
int dfs_destroy(struct file *filp) { struct inode *inode; inode = (struct inode *) filp->data; release_inode(inode); return 0; }
//******** rmdir ******************** int8_t cnrmdir(const char* name) { char parent_name[512]; char entry_name[256]; dir_entry* entry; inode dir_inode; memset(&dir_inode, 0, sizeof(inode)); strcpy(parent_name, name); strcat(parent_name, "/.."); dir_ptr* parent = cnopendir(parent_name); check(parent != NULL, "Cannot open parent directory"); //Copy the entire directory minus the entry dir_ptr* new_parent = calloc(1,sizeof(dir_ptr)); new_parent->data = calloc(parent->inode_st.blocks, sizeof(block)); dir_entry* new_dir_entry = (dir_entry*)new_parent->data; new_parent->inode_st = parent->inode_st; new_parent->inode_id = parent->inode_id; new_parent->inode_st.size = 0; new_parent->index = 0; while((entry = cnreaddir(parent))) { memcpy(entry_name, entry->name, entry->name_len); entry_name[entry->name_len] = 0; if(strcmp(entry_name, name) == 0) //If this is the directory we want { inode_read(entry->inode, &dir_inode); check(dir_inode.size == 24, "Directory is not empty"); release_block(dir_inode.data0[0]); //Release target directory block release_inode(entry->inode); //Release target inode continue; } new_dir_entry->entry_len = entry->entry_len; new_dir_entry->name_len = entry->name_len; new_dir_entry->file_type = entry->file_type; new_dir_entry->inode = entry->inode; memcpy(new_dir_entry->name, entry->name, entry->name_len); new_parent->inode_st.size += entry->entry_len; new_parent->index += entry->entry_len; new_dir_entry = (dir_entry*)((uint8_t*)new_parent->data+new_parent->index); } inode_write(new_parent->inode_id, &new_parent->inode_st); llwrite(&new_parent->inode_st, new_parent->data); free(new_parent->data); free(new_parent); cnclosedir(parent); return 0; error: if(new_parent != NULL && new_parent->data != NULL) free(new_parent->data); if(new_parent != NULL) free(new_parent); if(parent != NULL) cnclosedir(parent); return -1; }
static struct inode *create_new(struct filsys *fs, char *name, int len, int mode) { struct inode *dir; struct inode *inode; struct inode *oldinode; vfs_ino_t oldino; dir = parse_name(fs, &name, &len); if (!dir) return NULL; inode = alloc_inode(dir, VFS_S_IFREG | mode); if (!inode) { release_inode(dir); return NULL; } inode->desc->linkcount++; mark_inode_dirty(inode); oldino = modify_dir_entry(dir, name, len, inode->ino); if (oldino != -1) { oldinode = get_inode(fs, oldino); if (oldinode) { unlink_inode(oldinode); release_inode(oldinode); } } else { if (add_dir_entry(dir, name, len, inode->ino) < 0) { unlink_inode(inode); release_inode(inode); release_inode(dir); return NULL; } } release_inode(dir); return inode; }
static struct inode *create_always(struct filsys *fs, char *name, int len, vfs_ino_t ino, int mode) { struct inode *dir; struct inode *inode; dir = parse_name(fs, &name, &len); if (!dir) return NULL; if (find_dir_entry(dir, name, len) != -1) { release_inode(dir); return NULL; } if (ino == -1) inode = alloc_inode(dir, VFS_S_IFREG | mode); else { inode = get_inode(fs, ino); if (inode->desc->ctime == 0) inode->desc->ctime = time(NULL); inode->desc->mode = VFS_S_IFREG | mode; } if (!inode) { release_inode(dir); return NULL; } inode->desc->linkcount++; mark_inode_dirty(inode); if (add_dir_entry(dir, name, len, inode->ino) < 0) { unlink_inode(inode); release_inode(inode); release_inode(dir); return NULL; } release_inode(dir); return inode; }
/* remove file/dir from fs */ int fs_unlink(const char *pathname) { struct inode_s *ino, *dir; ino = dir = NULL; dir = current_dir(); if ( (ino = find_inode(dir, pathname, FS_SEARCH_REMOVE)) == NULL) goto err; rm_inode(ino->i_num); release_inode(dir); release_inode(ino); return OK; err: release_inode(dir); release_inode(ino); return ERROR; }
static int truncate_existing(struct filsys *fs, char *name, struct inode **retval) { struct inode *inode; int rc; rc = namei(fs, name, &inode); if (rc < 0) return rc; if (S_ISDIR(inode->desc->mode)) { release_inode(inode); return -EISDIR; } rc = truncate_inode(inode, 0); if (rc < 0) { release_inode(inode); return rc; } inode->desc->size = 0; mark_inode_dirty(inode); *retval = inode; return 0; }
int dfs_close(struct file *filp) { struct inode *inode; inode = (struct inode *) filp->data; if (filp->flags & F_MODIFIED) { inode->desc->mtime = time(NULL); mark_inode_dirty(inode); } release_inode(inode); return 0; }
int fs_chdir(const char *path) { struct inode_s *ino, *dir; ino = dir = NULL; dir = current_dir(); if ( (ino = find_inode(dir, path, FS_SEARCH_GET)) == NULL) goto err; release_inode(dir); if (!IS_DIR(ino->i_mode)) goto err; set_current_dir(ino); release_inode(ino); return OK; err: release_inode(dir); release_inode(ino); return ERROR; }
static struct inode *open_always(struct filsys *fs, char *name, int len, int mode) { struct inode *dir; struct inode *inode; vfs_ino_t ino; dir = parse_name(fs, &name, &len); if (!dir) return NULL; ino = find_dir_entry(dir, name, len); if (ino == -1) { inode = alloc_inode(dir, VFS_S_IFREG | mode); if (!inode) { release_inode(dir); return NULL; } inode->desc->linkcount++; mark_inode_dirty(inode); if (add_dir_entry(dir, name, len, inode->ino) < 0) { unlink_inode(inode); release_inode(inode); release_inode(dir); return NULL; } } else { inode = get_inode(fs, ino); if (!inode) { release_inode(dir); return NULL; } if (VFS_S_ISDIR(inode->desc->mode)) { release_inode(dir); release_inode(inode); return NULL; } } release_inode(dir); return inode; }
static struct inode *open_existing(struct filsys *fs, char *name, int len) { struct inode *inode; vfs_ino_t ino; ino = lookup_name(fs, DFS_INODE_ROOT, name, len); if (ino == -1) return NULL; inode = get_inode(fs, ino); if (!inode) return NULL; if (VFS_S_ISDIR(inode->desc->mode)) { release_inode(inode); return NULL; } return inode; }
int fs_getdents(int fd, char *buf, size_t n) { unsigned int i, pos; struct inode_s *dir, *ino; struct dir_entry_s dentry; struct dirent *dent; struct file_s *flip; flip = get_file(fd); dir = flip->f_ino; if (!IS_DIR(dir->i_mode)) return ERROR; i = 0; pos = flip->f_pos; while (n >= sizeof(struct dirent) + 1) { if (next_entry(dir, &pos, &dentry) == ERROR) break; ino = get_inode(dentry.num); dent = (struct dirent *) (buf + i); dent->d_ino = dentry.num; dent->d_off = pos - sizeof(struct dir_entry_s); dent->d_reclen = mystrncpy(dent->d_name, dentry.name, MAX_NAME) + 1 + /* add the \0 */ sizeof(ino_t) + /* add the d_ino */ sizeof(off_t) + /* add the d_off */ sizeof(unsigned short) + /* add the d_reclen */ 1; /* add the d_type */ /* add d_type */ *(buf + i + dent->d_reclen - 1) = (IS_DIR(ino->i_mode) ? DT_DIR : IS_FILE(ino->i_mode) ? DT_REG : IS_CHAR(ino->i_mode) ? DT_CHR : DT_UNK); i += dent->d_reclen; n -= dent->d_reclen; release_inode(ino); } flip->f_pos = pos; return i; }
struct inode *parse_name(struct filsys *fs, char **name, int *len) { char *start; char *p; vfs_ino_t ino; struct inode *dir; if (*len == 0) return get_inode(fs, DFS_INODE_ROOT); start = *name; p = start + *len - 1; while (p > start && *p != PS1 && *p != PS2) p--; if (p == start) { if (*p == PS1 || *p == PS2) { (*name)++; (*len)--; } return get_inode(fs, DFS_INODE_ROOT); } ino = lookup_name(fs, DFS_INODE_ROOT, start, p - start); if (ino == -1) return NULL; dir = get_inode(fs, ino); if (!dir) return NULL; if (!VFS_S_ISDIR(dir->desc->mode)) { release_inode(dir); return NULL; } *name = p + 1; *len -= p - start + 1; return dir; }
vfs_ino_t lookup_name(struct filsys *fs, vfs_ino_t ino, char *name, int len) { char *p; int l; struct inode *inode; while (1) { // Skip path separator if (*name == PS1 || *name == PS2) { name++; len--; } if (len == 0) return ino; // Find next part of name p = name; l = 0; while (l < len && *p != PS1 && *p != PS2) { l++; p++; } // Find inode for next name part inode = get_inode(fs, ino); if (!inode) return -1; ino = find_dir_entry(inode, name, l); release_inode(inode); if (ino == -1) return -1; // If we have parsed the whole name return the inode number if (l == len) return ino; // Prepare for next name part name = p; len -= l; } }
/* rename oldpath to newpath */ int fs_rename(const char *oldpath, const char *newpath) { struct inode_s *dir, *last_dir, *ino; char path[MAX_PATH], name[MAX_NAME]; dir = last_dir = ino = NULL; /* get last component of path */ process_path(newpath, path, name); if (name[0] == '\0') { char tmp[MAX_PATH]; process_path(oldpath, tmp, name); } dir = current_dir(); /* get last directory of target path */ if ( (last_dir = find_inode(dir, path, FS_SEARCH_GET)) == NULL) goto err; /* remove entry from the old directory */ if ( (ino = find_inode(dir, oldpath, FS_SEARCH_REMOVE)) == NULL) goto err; /* new entry in the last directory of path (or old one if file exists) */ if (add_entry(last_dir, ino->i_num, name) == ERROR) goto err; /* check if oldpath was a dir, and update '..' in that case */ if (IS_DIR(ino->i_mode)) { add_entry(ino, last_dir->i_num, ".."); last_dir->i_nlinks++; } release_inode(last_dir); release_inode(dir); release_inode(ino); return OK; err: release_inode(last_dir); release_inode(dir); release_inode(ino); return ERROR; }
/* create new directory */ int fs_mkdir(const char *pathname, mode_t mode) { struct inode_s *ino, *dir, *tmpdir; char path[MAX_PATH], name[MAX_NAME]; ino = dir = tmpdir = NULL; process_path(pathname, path, name); tmpdir = current_dir(); /* get inode numbers from parent and new dir */ if ( (dir = find_inode(tmpdir, path, FS_SEARCH_GET)) == NULL) goto err; release_inode(tmpdir); if ( (ino = find_inode(dir, name, FS_SEARCH_ADD)) == NULL) goto err; /* fill new dir inode */ fill_inode(ino, mode); ino->i_mode = (ino->i_mode & ~I_TYPE) | I_DIRECTORY; /* add '.' */ empty_entry(ino, ino->i_num, "."); ino->i_nlinks++; /* and '..' */ empty_entry(ino, dir->i_num, ".."); dir->i_nlinks++; dir->i_dirty = 1; /* update dir size */ ino->i_size = DIRENTRY_SIZE * 2; release_inode(dir); release_inode(ino); return OK; err: release_inode(tmpdir); release_inode(dir); release_inode(ino); return ERROR; }
/* remove directory (only if it is empty) */ int fs_rmdir(const char *pathname) { struct inode_s *ino, *dir, *tmpdir; char path[MAX_PATH], name[MAX_NAME]; ino = dir = tmpdir = NULL; process_path(pathname, path, name); tmpdir = current_dir(); /* get inode numbers from parent and new dir */ if ( (dir = find_inode(tmpdir, path, FS_SEARCH_GET)) == NULL) goto err; release_inode(tmpdir); if ( (ino = find_inode(dir, name, FS_SEARCH_ADD)) == NULL) goto err; /* check if its a dir and it is empty */ if (!IS_DIR(ino->i_mode) || ino->i_size != DIRENTRY_SIZE * 2) goto err; /* this cant give an error */ release_inode(find_inode(dir, name, FS_SEARCH_REMOVE)); /* free blocks and inode */ rm_inode(ino->i_num); release_inode(dir); release_inode(ino); return OK; err: release_inode(tmpdir); release_inode(dir); release_inode(ino); return ERROR; }
static int open_always(struct filsys *fs, char *name, int mode, struct inode **retval) { struct inode *dir; struct inode *inode; ino_t ino; int rc; int len = strlen(name); rc = diri(fs, &name, &len, &dir); if (rc < 0) return rc; rc = find_dir_entry(dir, name, len, &ino); if (rc < 0 && rc != -ENOENT) { release_inode(dir); return rc; } if (rc == -ENOENT) { inode = alloc_inode(dir, S_IFREG | (mode & S_IRWXUGO)); if (!inode) { release_inode(dir); return -ENOSPC; } rc = add_dir_entry(dir, name, len, inode->ino); if (rc < 0) { unlink_inode(inode); release_inode(inode); release_inode(dir); return rc; } } else { rc = get_inode(fs, ino, &inode); if (rc < 0) { release_inode(dir); return rc; } } release_inode(dir); *retval = inode; return 0; }
struct filsys *create_filesystem(vfs_devno_t devno, int blocksize, int inode_ratio, int quick) { struct filsys *fs; unsigned int blocks; unsigned int first_block; struct groupdesc *gd; struct buf *buf; unsigned int i, j; vfs_ino_t ino; struct inode *root; char *buffer; // Allocate file system fs = (struct filsys *) malloc(sizeof(struct filsys)); memset(fs, 0, sizeof(struct filsys)); // Allocate super block fs->super = (struct superblock *) malloc(SECTORSIZE); memset(fs->super, 0, SECTORSIZE); fs->super_dirty = 1; // Set device number and block size fs->devno = devno; fs->blocksize = blocksize; // Initialize buffer cache fs->cache = init_buffer_pool(devno, CACHEBUFFERS, fs->blocksize); // Set signature, version and block size in super block fs->super->signature = DFS_SIGNATURE; fs->super->version = DFS_VERSION; fs->super->log_block_size = bits(blocksize); // Each group has as many blocks as can be represented by the block bitmap block fs->super->blocks_per_group = fs->blocksize * 8; // Get the device size in sectors from the device and convert it to blocks fs->super->block_count = dev_getsize(fs->devno) / (fs->blocksize / SECTORSIZE); // Set cache size fs->super->cache_buffers = CACHEBUFFERS; if (fs->super->cache_buffers > fs->super->block_count) fs->super->cache_buffers = 64; // The number of inodes in a group is computed as a ratio of the size of group fs->inodes_per_block = fs->blocksize / sizeof(struct inodedesc); if (fs->super->blocks_per_group < fs->super->block_count) fs->super->inodes_per_group = fs->blocksize * fs->super->blocks_per_group / inode_ratio; else fs->super->inodes_per_group = fs->blocksize * fs->super->block_count / inode_ratio; if (fs->super->inodes_per_group > fs->blocksize * 8) fs->super->inodes_per_group = fs->blocksize * 8; fs->inode_blocks_per_group = (fs->super->inodes_per_group * sizeof(struct inodedesc) + fs->blocksize - 1) / fs->blocksize; // Calculate the number of block pointers per block directory page fs->log_blkptrs_per_block = fs->super->log_block_size - 2; // Calculate the number of group descriptors and the number of blocks to store them fs->super->group_count = (fs->super->block_count + fs->super->blocks_per_group - 1) / fs->super->blocks_per_group; fs->groupdescs_per_block = fs->blocksize / sizeof(struct groupdesc); fs->groupdesc_blocks = (fs->super->group_count * sizeof(struct groupdesc) + fs->blocksize - 1) / fs->blocksize; // The reserved blocks are allocated right after the super block fs->super->first_reserved_block = 1; if (fs->blocksize <= SECTORSIZE) fs->super->first_reserved_block++; fs->super->reserved_blocks = RESERVED_BLOCKS; // The group descriptor table starts after the superblock and reserved blocks fs->super->groupdesc_table_block = fs->super->first_reserved_block + fs->super->reserved_blocks; // If the last group is too small to hold the bitmaps and inode table skip it blocks = fs->super->block_count % fs->super->blocks_per_group; if (blocks > 0 && blocks < fs->inode_blocks_per_group + 2) fs->super->group_count--; if (fs->super->group_count == 0) panic("filesystem too small"); // Zero all blocks on disk if (!quick) { buffer = (char *) malloc(fs->blocksize); memset(buffer, 0, fs->blocksize); for (i = fs->super->groupdesc_table_block + fs->groupdesc_blocks; i < fs->super->block_count; i++) { dev_write(fs->devno, buffer, fs->blocksize, i); } free(buffer); } // Allocate group descriptors fs->groupdesc_buffers = (struct buf **) malloc(sizeof(struct buf *) * fs->groupdesc_blocks); fs->groups = (struct group *) malloc(sizeof(struct group) * fs->super->group_count); for (i = 0; i < fs->groupdesc_blocks; i++) { fs->groupdesc_buffers[i] = alloc_buffer(fs->cache, fs->super->groupdesc_table_block + i); } for (i = 0; i < fs->super->group_count; i++) { gd = (struct groupdesc *) fs->groupdesc_buffers[i / fs->groupdescs_per_block]->data; gd += (i % fs->groupdescs_per_block); fs->groups[i].desc = gd; fs->groups[i].first_free_block = 0; fs->groups[i].first_free_inode = 0; } // Reserve inode for root directory fs->super->reserved_inodes = RESERVED_INODES; // Set inode count based on group count fs->super->inode_count = fs->super->inodes_per_group * fs->super->group_count; // All blocks and inodes initially free fs->super->free_inode_count = fs->super->inode_count; fs->super->free_block_count = fs->super->block_count; // Initialize block bitmaps for (i = 0; i < fs->super->group_count; i++) { gd = fs->groups[i].desc; blocks = 0; first_block = fs->super->blocks_per_group * i; // The first group needs blocks for the super block and the group descriptors if (i == 0) blocks = fs->super->groupdesc_table_block + fs->groupdesc_blocks; // Next blocks in group are the block bitmap, inode bitmap and the inode table gd->block_bitmap_block = first_block + blocks++; gd->inode_bitmap_block = first_block + blocks++; gd->inode_table_block = first_block + blocks; blocks += fs->inode_blocks_per_group; // Update block bitmap buf = alloc_buffer(fs->cache, gd->block_bitmap_block); set_bits(buf->data, 0, blocks); mark_buffer_updated(buf); release_buffer(fs->cache, buf); // Determine the block count for the group. The last group may be truncated if (fs->super->blocks_per_group * (i + 1) > fs->super->block_count) gd->block_count = fs->super->block_count - fs->super->blocks_per_group * i; else gd->block_count = fs->super->blocks_per_group; // Set the count of free blocks and inodes for group gd->free_inode_count = fs->super->inodes_per_group; gd->free_block_count = gd->block_count - blocks; // Update super block fs->super->free_block_count -= blocks; mark_group_desc_dirty(fs, i); } // Zero out block and inode bitmaps and inode tables if (quick) { buffer = (char *) malloc(fs->blocksize); memset(buffer, 0, fs->blocksize); for (i = 0; i < fs->super->group_count; i++) { gd = fs->groups[i].desc; dev_write(fs->devno, buffer, fs->blocksize, gd->block_bitmap_block); dev_write(fs->devno, buffer, fs->blocksize, gd->inode_bitmap_block); for (j = 0; j < fs->inode_blocks_per_group; j++) { dev_write(fs->devno, buffer, fs->blocksize, gd->inode_table_block + j); } } free(buffer); } // Reserve inodes for (i = 0; i < RESERVED_INODES; i++) { ino = new_inode(fs, 0, 0); if (ino != i) panic("unexpected inode"); } // Create root directory root = get_inode(fs, DFS_INODE_ROOT); root->desc->mode = VFS_S_IFDIR | VFS_S_IRWXU | VFS_S_IRWXG | VFS_S_IRWXO; root->desc->ctime = root->desc->mtime = time(NULL); root->desc->linkcount = 1; mark_buffer_updated(root->buf); release_inode(root); return fs; }
static IDCOffer_clp Mount_m(MountLocal_cl *self, IDCOffer_clp drive, uint32_t partition, MountLocal_Options options, Context_clp settings) { IDCOffer_clp res; ext2fs_st *st; Type_Any any; Heap_clp heap; struct inode *root = NULL; uint32_t blockcache_size = 1024*128; /* Size of blockcache in bytes */ CSClientStubMod_cl *stubmod_clp; TRC(printf("ext2fs: mount %d from %p\n", partition, drive)); /* It's probably a good idea to have a separate heap for the filesystem. For now let's just use Pvs(heap), but eventually create a stretch of our own. */ heap = Pvs(heap); if(!(st = Heap$Malloc(heap, sizeof(*st)))) { fprintf(stderr, "ext2fs: cannot allocate state.\n"); RAISE_MountLocal$Failure(); } /* Where is this declared? */ bzero(st, sizeof(*st)); /* Fill in the fields that we can initialise without accessing the filesystem */ st->heap = heap; st->entrymod = NAME_FIND("modules>EntryMod", EntryMod_clp); st->shmtransport = NAME_FIND("modules>ShmTransport", IDCTransport_clp); st->csidc = NAME_FIND("modules>CSIDCTransport", CSIDCTransport_clp); st->client.entry = Pvs(entry); /* It's not clearn how many entries we are going to require yet We probably want separate ones for the USDCallback and the FSClient offers. We need to arrange that the entry threads die properly when the FS is unmounted. */ /* Interpret mount flags */ st->fs.readonly = SET_IN(options,MountLocal_Option_ReadOnly); st->fs.debug = SET_IN(options,MountLocal_Option_Debug); /* Place the drive in the state. */ st->disk.partition = partition; st->disk.drive_offer = drive; st->disk.drive_binding = IDCOffer$Bind(drive, Pvs(gkpr), &any); st->disk.usddrive = NARROW(&any, USDDrive_clp); TRC(printf("ext2fs: state at [%p, %p]\n",st, (void *)st + sizeof(*st))); DBO(printf("ext2fs: debugging output is switched on\n")); /* Connect to the disk */ init_usd(st); /* We need a stretch shared between us and the USD to allow us to read and write metadata. We'll use this stretch as a cache of blocks read from the disk. Because we won't know the blocksize until we have managed to read the superblock, we'd better make this buffer a multiple of 8k long (8k is currently the maximum blocksize). */ st->cache.str = Gatekeeper$GetStretch(Pvs(gkpr), IDCOffer$PDID(drive), blockcache_size, SET_ELEM(Stretch_Right_Read) | SET_ELEM(Stretch_Right_Write), PAGE_WIDTH, PAGE_WIDTH); st->cache.buf = STR_RANGE(st->cache.str, &st->cache.size); TRC(printf("ext2fs: buf is %d bytes at %p\n", st->cache.size, st->cache.buf)); if (st->cache.size < blockcache_size) { printf("ext2fs: warning: couldn't allocate a large blockcache\n"); } /* Now we can get at the disk. Read the superblock, and calculate constants from it. */ if (!read_superblock(st)) { printf("ext2fs: couldn't read superblock\n"); shutdown_usd(st); RAISE_MountLocal$BadFS(MountLocal_Problem_BadSuperblock); } /* XXX should sanity check filesystem size with partition size */ TRC(printf("ext2fs: filesystem size %d blocks (%d phys)\n" " partition size %d blocks (%d phys)\n", st->superblock->s_blocks_count, PHYS_BLKS(st, st->superblock->s_blocks_count), LOGICAL_BLKS(st, st->disk.partition_size), st->disk.partition_size)); if (st->disk.partition_size < PHYS_BLKS(st, st->superblock->s_blocks_count)) { printf("WARNING - filesystem is larger than partition **********\n"); /* XXX should probably give up now */ } /* Now that we know the logical block size we can initialise the block cache */ init_block_cache(st); /* From this point on, all access to the filesystem should be done through the block cache. DON'T call logical_read, call bread instead. Remember to free blocks once you're finished with them. */ init_groups(st); if(!init_inodes(st)) { fprintf(stderr, "ext2fs: failed to initialise inode cache.\n"); shutdown_usd(st); RAISE_MountLocal$Failure(); } /* Checking this probably isn't a bad idea, but let's wait until later */ /* Ok, now we are capable of reading the root inode (I hope!) */ TRC(printf("ext2fs: checking root inode.\n")); root = get_inode(st, EXT2_ROOT_INO); if(!root) { fprintf(stderr, "ext2fs: failed to read root inode.\n"); shutdown_usd(st); RAISE_MountLocal$BadFS(MountLocal_Problem_BadRoot); } if(!S_ISDIR(root->i_mode)) { fprintf(stderr, "ext2fs: urk!\n" " inode %d does not refer to a directory\n", EXT2_ROOT_INO); shutdown_usd(st); RAISE_MountLocal$BadFS(MountLocal_Problem_BadRoot); } release_inode(st, root); /* *thinks* should probably do something about deallocating state if we fail, too. */ /* Initialise the list of clients */ LINK_INIT(&st->client.clients); /* We create a server for the local domain; it lives in the head of the list of clients. The call to CSIDCTransport$Offer() will set up client-side stubs for this domain and put them in the object table. */ create_client(st, &st->client.clients, NULL); /* Now we do all the export stuff */ CL_INIT(st->client.callback, &client_callback_ms, st); ANY_INIT(&any, Ext2_clp, &st->client.clients.cl); stubmod_clp = Heap$Malloc(st->heap, sizeof(*stubmod_clp)); CLP_INIT(stubmod_clp, &stubmod_ms, NULL); res = CSIDCTransport$Offer ( st->csidc, &any, FSClient_clp__code, stubmod_clp, &st->client.callback, /* XXX produces a warning */ st->heap, Pvs(gkpr), st->client.entry, &st->client.service); TRC(printf("ext2fs: offer at %p\n",res)); return res; }
static int create_always(struct filsys *fs, char *name, int mode, struct inode **retval) { struct inode *dir; struct inode *inode; struct inode *oldinode; ino_t oldino; int rc; int len = strlen(name); rc = diri(fs, &name, &len, &dir); if (rc < 0) return rc; rc = find_dir_entry(dir, name, len, &oldino); if (rc == 0) { rc = get_inode(fs, oldino, &oldinode); if (rc < 0) { release_inode(dir); return rc; } if (S_ISDIR(oldinode->desc->mode) && oldinode->desc->linkcount == 1) { release_inode(dir); return -EISDIR; } inode = alloc_inode(dir, S_IFREG | (mode & S_IRWXUGO)); if (!inode) { release_inode(dir); return -ENOSPC; } rc = modify_dir_entry(dir, name, len, inode->ino, NULL); if (rc < 0) { unlink_inode(inode); release_inode(inode); release_inode(dir); return rc; } unlink_inode(oldinode); release_inode(oldinode); } else if (rc == -ENOENT) { inode = alloc_inode(dir, S_IFREG | (mode & S_IRWXUGO)); if (!inode) { release_inode(dir); return -ENOSPC; } rc = add_dir_entry(dir, name, len, inode->ino); if (rc < 0) { unlink_inode(inode); release_inode(inode); release_inode(dir); return rc; } } else { release_inode(dir); return rc; } release_inode(dir); *retval = inode; return 0; }