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; }
int dfs_ftruncate(struct file *filp, off64_t size) { struct inode *inode; int rc; unsigned int blocks; blkno_t blk; struct buf *buf; if (size > DFS_MAXFILESIZE) return -EFBIG; inode = (struct inode *) filp->data; if (S_ISDIR(inode->desc->mode)) return -EISDIR; if (size < 0) return -EINVAL; if (size == inode->desc->size) return 0; blocks = ((size_t) size + inode->fs->blocksize - 1) / inode->fs->blocksize; if (size > inode->desc->size) { while (inode->desc->blocks < blocks) { blk = expand_inode(inode); if (blk == NOBLOCK) return -ENOSPC; buf = alloc_buffer(inode->fs->cache, blk); if (!buf) return -EIO; memset(buf->data, 0, inode->fs->blocksize); mark_buffer_updated(inode->fs->cache, buf); release_buffer(inode->fs->cache, buf); } } else { rc = truncate_inode(inode, blocks); if (rc < 0) return rc; } inode->desc->size = size; mark_inode_dirty(inode); filp->flags |= F_MODIFIED; return 0; }
int dfs_chsize(struct file *filp, vfs_loff_t size) { struct inode *inode; int rc; unsigned int blocks; inode = (struct inode *) filp->data; if (size < 0 || size > inode->desc->size) return -1; inode->desc->size = size; mark_inode_dirty(inode); filp->flags |= F_MODIFIED; if (filp->pos > size) filp->pos = size; blocks = (size + inode->fs->blocksize - 1) / inode->fs->blocksize; rc = truncate_inode(inode, blocks); if (rc < 0) return rc; return 0; }
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 delete_dir_entry(struct inode *dir, char *name, int len) { unsigned int block; vfs_blkno_t blk; vfs_blkno_t lastblk; struct buf *buf; char *p; struct dentry *de; struct dentry *prevde; struct dentry *nextde; if (len <= 0 || len >= MAXPATH) return -1; if (!VFS_S_ISDIR(dir->desc->mode)) return -1; for (block = 0; block < dir->desc->blocks; block++) { blk = get_inode_block(dir, block); buf = get_buffer(dir->fs->cache, blk); if (!buf) return -1; p = buf->data; prevde = NULL; while (p < buf->data + dir->fs->blocksize) { de = (struct dentry *) p; if (fnmatch(name, len, de->name, de->namelen)) { if (prevde) { // Merge entry with previous entry prevde->reclen += de->reclen; memset(de, 0, sizeof(struct dentry) + NAME_ALIGN_LEN(de->namelen)); mark_buffer_updated(buf); } else if (de->reclen == dir->fs->blocksize) { // Block is empty, swap this block with last block and truncate if (block != dir->desc->blocks - 1) { lastblk = get_inode_block(dir, dir->desc->blocks - 1); set_inode_block(dir, block, lastblk); set_inode_block(dir, dir->desc->blocks - 1, buf->blkno); } truncate_inode(dir, dir->desc->blocks - 1); dir->desc->size -= dir->fs->blocksize; mark_buffer_invalid(buf); } else { // Merge with next entry nextde = (struct dentry *) (p + de->reclen); de->ino = nextde->ino; de->reclen += nextde->reclen; de->namelen = nextde->namelen; memcpy(de->name, nextde->name, nextde->namelen); // TODO: should be memmove? mark_buffer_updated(buf); } release_buffer(dir->fs->cache, buf); dir->desc->mtime = time(NULL); mark_inode_dirty(dir); return 0; } prevde = de; p += de->reclen; } release_buffer(dir->fs->cache, buf); } return -1; }
/*===========================================================================* * common_open * *===========================================================================*/ PRIVATE int common_open(register int oflags, mode_t omode) { /* Common code from do_creat and do_open. */ struct inode *rip, *ldirp; int r, b, exist = TRUE; dev_t dev; mode_t bits; off_t pos; struct filp *fil_ptr, *filp2; /* Remap the bottom two bits of oflags. */ bits = (mode_t) mode_map[oflags & O_ACCMODE]; /* See if file descriptor and filp slots are available. */ if ( (r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r); /* If O_CREATE is set, try to make the file. */ if (oflags & O_CREAT) { /* Create a new inode by calling new_node(). */ omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask); rip = new_node(&ldirp, user_path, omode, NO_ZONE, oflags&O_EXCL, NULL); r = err_code; put_inode(ldirp); if (r == OK) exist = FALSE; /* we just created the file */ else if (r != EEXIST) return(r); /* other error */ else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL flag is set this is an error */ } else { /* Scan path name. */ if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); } /* Claim the file descriptor and filp slot and fill them in. */ fp->fp_filp[m_in.fd] = fil_ptr; FD_SET(m_in.fd, &fp->fp_filp_inuse); fil_ptr->filp_count = 1; fil_ptr->filp_ino = rip; fil_ptr->filp_flags = oflags; /* Only do the normal open code if we didn't just create the file. */ if (exist) { /* Check protections. */ if ((r = forbidden(rip, bits)) == OK) { /* Opening reg. files directories and special files differ. */ switch (rip->i_mode & I_TYPE) { case I_REGULAR: /* Truncate regular file if O_TRUNC. */ if (oflags & O_TRUNC) { if ((r = forbidden(rip, W_BIT)) !=OK) break; truncate_inode(rip, 0); wipe_inode(rip); /* Send the inode from the inode cache to the * block cache, so it gets written on the next * cache flush. */ rw_inode(rip, WRITING); } break; case I_DIRECTORY: /* Directories may be read but not written. */ r = (bits & W_BIT ? EISDIR : OK); break; case I_CHAR_SPECIAL: case I_BLOCK_SPECIAL: /* Invoke the driver for special processing. */ dev = (dev_t) rip->i_zone[0]; r = dev_open(dev, who_e, bits | (oflags & ~O_ACCMODE)); break; case I_NAMED_PIPE: oflags |= O_APPEND; /* force append mode */ fil_ptr->filp_flags = oflags; r = pipe_open(rip, bits, oflags); if (r != ENXIO) { /* See if someone else is doing a rd or wt on * the FIFO. If so, use its filp entry so the * file position will be automatically shared. */ b = (bits & R_BIT ? R_BIT : W_BIT); fil_ptr->filp_count = 0; /* don't find self */ if ((filp2 = find_filp(rip, b)) != NIL_FILP) { /* Co-reader or writer found. Use it.*/ fp->fp_filp[m_in.fd] = filp2; filp2->filp_count++; filp2->filp_ino = rip; filp2->filp_flags = oflags; /* i_count was incremented incorrectly * by eatpath above, not knowing that * we were going to use an existing * filp entry. Correct this error. */ rip->i_count--; } else { /* Nobody else found. Restore filp. */ fil_ptr->filp_count = 1; if (b == R_BIT) pos = rip->i_zone[V2_NR_DZONES+0]; else pos = rip->i_zone[V2_NR_DZONES+1]; fil_ptr->filp_pos = pos; } } break; } } } /* If error, release inode. */ if (r != OK) { if (r == SUSPEND) return(r); /* Oops, just suspended */ fp->fp_filp[m_in.fd] = NIL_FILP; FD_CLR(m_in.fd, &fp->fp_filp_inuse); fil_ptr->filp_count= 0; put_inode(rip); return(r); } return(m_in.fd); }