예제 #1
0
파일: file.c 프로젝트: rbowden91/fp261
// Write at most 'n' bytes from 'buf' to 'fd' at the current seek position.
// Advance 'fd->f_offset' by the number of bytes written.
//
// Returns:
//	 The number of bytes successfully written.
//	 < 0 on error.
static ssize_t
devfile_write(struct Fd *fd, const void *buf, size_t n)
{
	// Use inode_open, inode_close, maybe inode_set_size, and inode_data.
	// Be careful of block boundaries!
	// Flush any blocks you change using BCREQ_FLUSH.
	//
	// LAB 5: Your code here.
    int r;
    size_t orig_offset = fd->fd_offset;
    struct Inode *ino;
    if((r = inode_open(fd->fd_file.inum, &ino)) < 0)
        return r;
    void *data;
    size_t n2 = ROUNDUP(fd->fd_offset, PGSIZE) - fd->fd_offset;
    if (n2 > n)
        n2 = n;
    if(n2)
    {
        n -= n2;
        if(fd->fd_offset + n2 > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + n2) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, n2);
        fd->fd_offset += n2;
        bcache_ipc(data, BCREQ_FLUSH);
        buf = (void *)((char *)buf + n2);
    }
    while (n / PGSIZE)
    {
        if(fd->fd_offset + PGSIZE > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + PGSIZE) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, PGSIZE);
        bcache_ipc(data, BCREQ_FLUSH);
        n -= PGSIZE;
        buf = (void *)((char *)buf + PGSIZE);
        fd->fd_offset += PGSIZE;
    }
    if (n > 0)
    {
        if(fd->fd_offset + n > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + n) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, n);
        bcache_ipc(data, BCREQ_FLUSH);
        fd->fd_offset += n;
    }

wrapup:
    inode_close(ino);
    return fd->fd_offset - orig_offset;
}
예제 #2
0
int
fs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
{
	struct inode *ino = (struct inode *)fi->fh;
	ino->i_mtime = time(NULL);
	return inode_set_size(ino, size);
}
예제 #3
0
int
fs_truncate(const char *path, off_t size)
{
	struct inode *ino;
	int r;

	if ((r = inode_open(path, &ino)) < 0)
		return r;
	ino->i_mtime = time(NULL);
	return inode_set_size(ino, size);
}
예제 #4
0
파일: file.c 프로젝트: rbowden91/fp261
// Truncate or extend an open file to 'size' bytes
static int
devfile_trunc(struct Fd *fd, off_t newsize)
{
	int r;
	struct Inode *ino;

	if ((r = inode_open(fd->fd_file.inum, &ino)) < 0)
		return r;

	r = inode_set_size(ino, newsize);

	inode_close(ino);
	return r;
}
예제 #5
0
파일: process.c 프로젝트: krichter722/gfarm
gfarm_error_t
process_close_file_write(struct process *process, struct peer *peer, int fd,
	gfarm_off_t size,
	struct gfarm_timespec *atime, struct gfarm_timespec *mtime)
{
	struct file_opening *fo;
	gfarm_error_t e = process_get_file_opening(process, fd, &fo);
	struct host *spool_host;

	if (e != GFARM_ERR_NO_ERROR)
		return (e);
	if (!inode_is_file(fo->inode))
		return (GFARM_ERR_OPERATION_NOT_PERMITTED);
	if (fo->u.f.spool_opener != peer)
		return (GFARM_ERR_OPERATION_NOT_PERMITTED);
	if ((accmode_to_op(fo->flag) & GFS_W_OK) == 0)
		return (GFARM_ERR_BAD_FILE_DESCRIPTOR);

	if (fo->opener != peer && fo->opener != NULL) {
		spool_host = fo->u.f.spool_host;
		/* closing REOPENed file, but the client is still opening */
		fo->u.f.spool_opener = NULL;
		fo->u.f.spool_host = NULL;
		/*
		 * GFARM_FILE_CREATE_REPLICA means just to create a
		 * file replica.
		 */
		if ((fo->flag & GFARM_FILE_CREATE_REPLICA) != 0) {
			e = inode_add_replica(fo->inode, spool_host, 1);
			/* if this is not the first replica, return */
			if (e != GFARM_ERR_ALREADY_EXISTS)
				return (e);
		}
		else if (gfarm_timespec_cmp(inode_get_mtime(fo->inode), mtime))
			/* invalidate file replicas if updated */
			inode_remove_every_other_replicas(
				fo->inode, spool_host);

		inode_set_size(fo->inode, size);
		inode_set_atime(fo->inode, atime);
		inode_set_mtime(fo->inode, mtime);
		return (GFARM_ERR_NO_ERROR);
	}

	inode_close_write(fo, size, atime, mtime);
	file_opening_free(fo, 1);
	process->filetab[fd] = NULL;
	return (GFARM_ERR_NO_ERROR);
}
예제 #6
0
파일: file.c 프로젝트: rbowden91/fp261
// Find a directory entry in the 'ino' directory.
// Looks for name 'name' with length 'namelen'.
// If 'create != 0', such an entry is created if none is found.
//   A newly created entry will have de_inum == 0.
// Returns 0 on success (storing a pointer to the struct Direntry in
//   *de_store), and < 0 on error.
// Error codes:
//	-E_BAD_PATH if 'ino' is not a directory.
//	-E_NO_DISK if out of space.
//	(possibly others)
//
static int
dir_find(struct Inode *ino, const char *name, int namelen,
	 struct Direntry **de_store, int create)
{
	off_t off;
	struct Direntry *empty = 0;

	*de_store = 0;

	if (ino->i_ftype != FTYPE_DIR)
		return -E_BAD_PATH;

	for (off = 0; off < ino->i_size; off += sizeof(struct Direntry)) {
		struct Direntry *de = (struct Direntry *) inode_data(ino, off);

		if (de->de_inum != 0
		    && de->de_namelen == namelen
		    && memcmp(de->de_name, name, namelen) == 0) {
			*de_store = de;
			return 0;
		}

		if (de->de_inum == 0 && !empty)
			empty = de;
	}

	if (!create)
		return -E_NOT_FOUND;

	if (!empty) {
		int r = inode_set_size(ino, ino->i_size + sizeof(struct Direntry));
		if (r < 0)
			return r;
		empty = (struct Direntry *) inode_data(ino, ino->i_size - sizeof(struct Direntry));
	}

	memset(empty, 0, sizeof(struct Direntry));
	empty->de_namelen = namelen;
	memcpy(empty->de_name, name, namelen);
	*de_store = empty;
	return 0;
}
예제 #7
0
파일: file.c 프로젝트: rbowden91/fp261
// Sets inode 'ino's size to 'size',
// either allocating or freeing data blocks as required.
// Returns 0 on success, < 0 on error.
// Error codes:
//	-E_FILE_SIZE if 'size' is too big
//	-E_NO_DISK if out of disk space
//	possibly others
// On error, the inode's size and disk's allocation state should be unchanged.
// On success, any changed blocks are flushed.
//
static int
inode_set_size(struct Inode *ino, size_t size)
{
	// This function is correct as far as it goes, but does not handle
	// all cases.  Read the spec carefully: what is missing?
	// LAB 5: Your code somewhere here

	int b1, b2;

	if (size > MAXFILESIZE)
		return -E_FILE_SIZE;
    b1 = ino->i_size / BLKSIZE;
    b2 = ROUNDUP(size, BLKSIZE) / BLKSIZE;
    if (size >= (size_t)ino->i_size)
    {
        for (; b1 < b2; ++b1)
            if (ino->i_direct[b1] == 0) {
                blocknum_t b = block_alloc();
                if (b < 0) {
                    inode_set_size(ino, ino->i_size);
                    return -E_NO_DISK;
                }
                ino->i_direct[b1] = b;
            }
    }
    else
    {
        if(!(size % BLKSIZE))
            b2--;
	    bcache_ipc(freemap, BCREQ_MAP_WLOCK);
        for(; b2 < b1; b1--)
            if (ino->i_direct[b1] != 0)
            {
                freemap[ino->i_direct[b1]] = 1;
                ino->i_direct[b1] = 0;
            }
	    bcache_ipc(freemap, BCREQ_UNLOCK_FLUSH);
    }
	ino->i_size = size;
	bcache_ipc(ino, BCREQ_FLUSH);
	return 0;
}
예제 #8
0
void
fs_test(void)
{
	struct inode *ino, *ino2;
	int r;
	char *blk;
	uint32_t bits[4096];

	// back up bitmap
	memmove(bits, bitmap, 4096);
	// allocate block
	if ((r = alloc_block()) < 0)
		panic("alloc_block: %s", strerror(-r));
	// check that block was free
	assert(bits[r/32] & (1 << (r%32)));
	// and is not free any more
	assert(!(bitmap[r/32] & (1 << (r%32))));
	free_block(r);
	printf("alloc_block is good\n");

	if ((r = inode_open("/not-found", &ino)) < 0 && r != -ENOENT)
		panic("inode_open /not-found: %s", strerror(-r));
	else if (r == 0)
		panic("inode_open /not-found succeeded!");
	if ((r = inode_open("/msg", &ino)) < 0)
		panic("inode_open /msg: %s", strerror(-r));
	printf("inode_open is good\n");

	if ((r = inode_get_block(ino, 0, &blk)) < 0)
		panic("inode_get_block: %s", strerror(-r));
	if (strcmp(blk, msg) != 0)
		panic("inode_get_block returned wrong data");
	printf("inode_get_block is good\n");

	if ((r = inode_set_size(ino, 0)) < 0)
		panic("inode_set_size: %s", strerror(-r));
	assert(ino->i_direct[0] == 0);
	printf("inode_truncate is good\n");

	if ((r = inode_set_size(ino, strlen(msg))) < 0)
		panic("inode_set_size 2: %s", strerror(-r));
	if ((r = inode_get_block(ino, 0, &blk)) < 0)
		panic("inode_get_block 2: %s", strerror(-r));
	strcpy(blk, msg);
	printf("file rewrite is good\n");

	if ((r = inode_link("/msg", "/linkmsg")) < 0)
		panic("inode_link /msg /linkmsg: %s", strerror(-r));
	if ((r = inode_open("/msg", &ino)) < 0)
		panic("inode_open /msg: %s", strerror(-r));
	if ((r = inode_open("/linkmsg", &ino2)) < 0)
		panic("inode_open /linkmsg: %s", strerror(-r));
	if (ino != ino2)
		panic("linked files do not point to same inode");
	if (ino->i_nlink != 2)
		panic("link count incorrect: %u, expected 2", ino->i_nlink);
	printf("inode_link is good\n");

	if ((r = inode_unlink("/linkmsg")) < 0)
		panic("inode_unlink /linkmsg: %s", strerror(-r));
	if ((r = inode_open("/linkmsg", &ino2)) < 0 && r != -ENOENT)
		panic("inode_open /linkmsg after unlink: %s", strerror(-r));
	else if (r == 0)
		panic("inode_open /linkmsg after unlink succeeded!");
	if ((r = inode_open("/msg", &ino)) < 0)
		panic("inode_open /msg after /linkmsg unlinked: %s", strerror(-r));
	if (ino->i_nlink != 1)
		panic("link count incorrect: %u, expected 1", ino->i_nlink);
	printf("inode_unlink is good\n");
}
예제 #9
0
파일: file.c 프로젝트: rbowden91/fp261
// Open a file (or directory).
//
// Returns:
// 	The file descriptor index on success
// 	-E_BAD_PATH if the path is too long (>= MAXPATHLEN)
//	-E_BAD_PATH if an intermediate path component is not a directory
//	-E_MAX_FD if no more file descriptors
//	-E_NOT_FOUND if the file (or a path component) was not found
//	(and others)
int
open(const char *path, int mode)
{
	// Find an unused file descriptor page using fd_find_unused
	// and allocate a page there (PTE_P|PTE_U|PTE_W|PTE_SHARE).
	//
	// LAB 5: Your code here
    int r;
    struct Fd *fd;
    if((r = fd_find_unused(&fd)) < 0 || 
    (r = sys_page_alloc(0, fd, PTE_P|PTE_U|PTE_W|PTE_SHARE)) < 0)
        goto err1;
	// Check the pathname.  Error if too long.
	// Use path_walk to find the corresponding directory entry.
	// If '(mode & O_CREAT) == 0' (Exercise 4),
	//   Return -E_NOT_FOUND if the file is not found.
	//   Otherwise, use inode_open to open the inode.
	// If '(mode & O_CREAT) != 0' (Exercise 7),
	//   Create the file if it doesn't exist yet.
	//   Allocate a new inode, initialize its fields, and
	//   reference that inode from the new directory entry.
	//   Flush any blocks you change.
	// Directories can be opened, but only as read-only:
	// return -E_IS_DIR if '(mode & O_ACCMODE) != O_RDONLY'.
	//
	// Check for errors.  On error, make sure you clean up any
	// allocated objects.
	//
	// The root directory is a special case -- if you aren't careful,
	// you will deadlock when the root directory is opened.  (Why?)
	//
	// LAB 5: Your code here.
    int i;
    for(i = 0; i < MAXNAMELEN && path[i]; i++); 
    if(i == MAXNAMELEN)
    {
        r = -E_BAD_PATH;
        goto err2;
    }
    struct Inode *dirino;
    struct Direntry *de;
    if((r = path_walk(path, &dirino, &de, mode & O_CREAT)))
        goto err2;
    struct Inode *fileino;
    
    if(!(mode & O_CREAT))
    {
        if(de == &super->s_root)
            fileino = dirino;
        else if((r = inode_open(de->de_inum, &fileino)) < 0)
            goto err3;
        
        if(fileino->i_ftype == FTYPE_DIR && (
           mode & O_ACCMODE) != O_RDONLY)
        {
            r = -E_IS_DIR;
            goto err4;
        }
    }
    else 
    {
        if((r = inode_alloc(&fileino)) < 0)
            goto err3;
        fileino->i_ftype = FTYPE_REG;
        fileino->i_refcount = 1;
        fileino->i_size = 0;
        memset(&fileino->i_direct, 0, NDIRECT * sizeof (blocknum_t));
        de->de_inum = fileino->i_inum;
        bcache_ipc(fileino, BCREQ_FLUSH); 
        bcache_ipc(dirino, BCREQ_FLUSH); 
    }
	// If '(mode & O_TRUNC) != 0' and the open mode is not read-only,
	// set the file's length to 0.  Flush any blocks you change.
	//
	// LAB 5: Your code here (Exercise 8).
    if((mode & O_TRUNC))
    {
        inode_set_size(fileino, 0);
    }        

	// The open has succeeded.
	// Fill in all parts of the 'fd' appropriately.  Use 'devfile.dev_id'.
	// Copy the file's pathname into 'fd->fd_file.open_path' to improve
	// error messages later.
	// You must account for the open file reference in the inode as well.
	// Clean up any open inodes.
	//
	// LAB 5: Your code here (Exercise 4).
    fd->fd_dev_id = devfile.dev_id;
    fd->fd_offset = 0;
    fd->fd_omode = mode;
    fd->fd_file.inum = fileino->i_inum; 
    strcpy(fd->fd_file.open_path, path);
    fileino->i_opencount++;
    inode_close(dirino);
    inode_close(fileino);
    return fd2num(fd);

err4:
    inode_close(fileino);
err3:
    inode_close(dirino);
err2:
    sys_page_unmap(thisenv->env_id, fd);
err1:
    return r;
}