Ejemplo n.º 1
0
int sysv_add_link(struct dentry *dentry, struct inode *inode)
{
	struct inode *dir = dentry->d_parent->d_inode;
	const char * name = dentry->d_name.name;
	int namelen = dentry->d_name.len;
	struct page *page = NULL;
	struct sysv_dir_entry * de;
	unsigned long npages = dir_pages(dir);
	unsigned long n;
	char *kaddr;
	loff_t pos;
	int err;

	/* We take care of directory expansion in the same loop */
	for (n = 0; n <= npages; n++) {
		page = dir_get_page(dir, n);
		err = PTR_ERR(page);
		if (IS_ERR(page))
			goto out;
		kaddr = (char*)page_address(page);
		de = (struct sysv_dir_entry *)kaddr;
		kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
		while ((char *)de <= kaddr) {
			if (!de->inode)
				goto got_it;
			err = -EEXIST;
			if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) 
				goto out_page;
			de++;
		}
		dir_put_page(page);
	}
	BUG();
	return -EINVAL;

got_it:
	pos = page_offset(page) +
			(char*)de - (char*)page_address(page);
	lock_page(page);
	err = __sysv_write_begin(NULL, page->mapping, pos, SYSV_DIRSIZE,
				AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
	if (err)
		goto out_unlock;
	memcpy (de->name, name, namelen);
	memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
	de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
	err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
	mark_inode_dirty(dir);
out_page:
	dir_put_page(page);
out:
	return err;
out_unlock:
	unlock_page(page);
	goto out_page;
}
Ejemplo n.º 2
0
/*
 * ok, we cannot use strncmp, as the name is not in our data space. [Now it is!]
 * Thus we'll have to use sysv_match. No big problem. Match also makes
 * some sanity tests.
 *
 * NOTE! unlike strncmp, sysv_match returns 1 for success, 0 for failure.
 */
static int sysv_match(int len, const char * name, struct sysv_dir_entry * de)
{
	if (!de->inode || len > SYSV_NAMELEN)
		return 0;
	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
	if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
		return 1;
	return namecompare(len, SYSV_NAMELEN, name, de->name);
}
Ejemplo n.º 3
0
int sysv_add_link(struct dentry *dentry, struct inode *inode)
{
	struct inode *dir = dentry->d_parent->d_inode;
	const char * name = dentry->d_name.name;
	int namelen = dentry->d_name.len;
	struct page *page = NULL;
	struct sysv_dir_entry * de;
	unsigned long npages = dir_pages(dir);
	unsigned long n;
	char *kaddr;
	unsigned from, to;
	int err;

	/* We take care of directory expansion in the same loop */
	for (n = 0; n <= npages; n++) {
		page = dir_get_page(dir, n);
		err = PTR_ERR(page);
		if (IS_ERR(page))
			goto out;
		kaddr = (char*)page_address(page);
		de = (struct sysv_dir_entry *)kaddr;
		kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
		while ((char *)de <= kaddr) {
			if (!de->inode)
				goto got_it;
			err = -EEXIST;
			if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) 
				goto out_page;
			de++;
		}
		dir_put_page(page);
	}
	BUG();
	return -EINVAL;

got_it:
	from = (char*)de - (char*)page_address(page);
	to = from + SYSV_DIRSIZE;
	lock_page(page);
	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
	if (err)
		goto out_unlock;
	memcpy (de->name, name, namelen);
	memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
	de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
	err = dir_commit_chunk(page, from, to);
	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
	mark_inode_dirty(dir);
out_unlock:
	UnlockPage(page);
out_page:
	dir_put_page(page);
out:
	return err;
}
Ejemplo n.º 4
0
/*
 * ok, we cannot use strncmp, as the name is not in our data space.
 * Thus we'll have to use minix_match. No big problem. Match also makes
 * some sanity tests.
 *
 * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
 *
 * Note2: bh must already be mapped! 
 */
static int elksfs_match(size_t len, char *name, struct buffer_head *bh,
			loff_t *offset, register struct elksfs_sb_info *info)
{
    register struct elksfs_dir_entry *de;

    de = (struct elksfs_dir_entry *) (bh->b_data + *offset);
    *offset += info->s_dirsize;
    if (!de->inode || (unsigned long int) len > info->s_namelen)
	return 0;
    /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
    if (!len && (de->name[0] == '.') && (de->name[1] == '\0'))
	return 1;
    return namecompare(len, (size_t) info->s_namelen, name, de->name);
}
Ejemplo n.º 5
0
Archivo: namei.c Proyecto: lithoxs/elks
/*
 * ok, we cannot use strncmp, as the name is not in our data space.
 * Thus we'll have to use minix_match. No big problem. Match also makes
 * some sanity tests.
 *
 * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
 *
 * Note2: bh must already be mapped!
 */
static int minix_match(size_t len,
		       char *name,
		       struct buffer_head *bh,
		       loff_t offset, register struct minix_sb_info *info)
{
    register struct minix_dir_entry *de;

    de = (struct minix_dir_entry *) (bh->b_data + offset);
    if (!de->inode || len > info->s_namelen) {
	return 0;
    }
    /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
    if (!len && (de->name[0] == '.') && (de->name[1] == '\0')) {
	return 1;
    }
    return namecompare(len, info->s_namelen, name, de->name);
}
Ejemplo n.º 6
0
/*
 *	sysv_find_entry()
 *
 * finds an entry in the specified directory with the wanted name. It
 * returns the cache buffer in which the entry was found, and the entry
 * itself (as a parameter - res_dir). It does NOT read the inode of the
 * entry - you'll have to do that yourself if you want to.
 */
struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page)
{
	const char * name = dentry->d_name.name;
	int namelen = dentry->d_name.len;
	struct inode * dir = dentry->d_parent->d_inode;
	unsigned long start, n;
	unsigned long npages = dir_pages(dir);
	struct page *page = NULL;
	struct sysv_dir_entry *de;

	*res_page = NULL;

	start = SYSV_I(dir)->i_dir_start_lookup;
	if (start >= npages)
		start = 0;
	n = start;

	do {
		char *kaddr;
		page = dir_get_page(dir, n);
		if (!IS_ERR(page)) {
			kaddr = (char*)page_address(page);
			de = (struct sysv_dir_entry *) kaddr;
			kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
			for ( ; (char *) de <= kaddr ; de++) {
				if (!de->inode)
					continue;
				if (namecompare(namelen, SYSV_NAMELEN,
							name, de->name))
					goto found;
			}
			dir_put_page(page);
		}

		if (++n >= npages)
			n = 0;
	} while (n != start);

	return NULL;

found:
	SYSV_I(dir)->i_dir_start_lookup = n;
	*res_page = page;
	return de;
}
Ejemplo n.º 7
0
/*
 *	minix_find_entry()
 *
 * finds an entry in the specified directory with the wanted name. It
 * returns the cache buffer in which the entry was found, and the entry
 * itself (as a parameter - res_dir). It does NOT read the inode of the
 * entry - you'll have to do that yourself if you want to.
 */
static struct buffer_head * minix_find_entry(struct inode * dir,
	const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
	unsigned long block, offset;
	struct buffer_head * bh;
	struct minix_sb_info * info;
	struct minix_dir_entry *de;

	*res_dir = NULL;
	if (!dir || !dir->i_sb)
		return NULL;
	info = &dir->i_sb->u.minix_sb;
	if (namelen > info->s_namelen) {
#ifdef NO_TRUNCATE
		return NULL;
#else
		namelen = info->s_namelen;
#endif
	}
	bh = NULL;
	block = offset = 0;
	while (block*BLOCK_SIZE+offset < dir->i_size) {
		if (!bh) {
			bh = minix_bread(dir,block,0);
			if (!bh) {
				block++;
				continue;
			}
		}
		de = (struct minix_dir_entry *) (bh->b_data + offset);
		offset += info->s_dirsize;
		if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) {
			*res_dir = de;
			return bh;
		}
		if (offset < bh->b_size)
			continue;
		brelse(bh);
		bh = NULL;
		offset = 0;
		block++;
	}
	brelse(bh);
	return NULL;
}
Ejemplo n.º 8
0
static int elksfs_add_entry(register struct inode *dir, char *name,
			    size_t namelen, struct buffer_head **res_buf,
			    struct elksfs_dir_entry **res_dir)
{
    struct buffer_head *bh;
    struct elksfs_dir_entry *de;
    struct elksfs_sb_info *info;
    unsigned long int i;
    block_t block;
    loff_t offset;

    *res_buf = NULL;
    *res_dir = NULL;
    if (!dir || !dir->i_sb)
	return -ENOENT;
    info = &dir->i_sb->u.elksfs_sb;
    if (namelen > info->s_namelen) {

#ifdef NO_TRUNCATE
	return -ENAMETOOLONG;
#else
	namelen = info->s_namelen;
#endif

    }
    if (!namelen)
	return -ENOENT;
    bh = NULL;
    block = 0;
    offset = 0;
    while (1) {
	if (!bh) {
	    bh = elksfs_bread(dir, block, 1);
	    if (!bh)
		return -ENOSPC;
	}
	map_buffer(bh);
	de = (struct elksfs_dir_entry *) (bh->b_data + offset);
	offset += info->s_dirsize;
	if (block * 1024 + offset > dir->i_size) {
	    de->inode = 0;
	    dir->i_size = block * 1024 + offset;
	    dir->i_dirt = 1;
	}
	if (de->inode) {
	    if (namecompare(namelen, (size_t) info->s_namelen, name,
			    de->name)) {
		debug2("ELKSFSadd_entry: file %t==%s (already exists)\n",
		     name, de->name);
		unmap_brelse(bh);
		return -EEXIST;
	    }
	} else {
	    dir->i_mtime = dir->i_ctime = CURRENT_TIME;
	    dir->i_dirt = 1;
	    for (i = 0; i < info->s_namelen; i++)
		de->name[i] = (i < namelen)
			? (char) get_fs_byte((unsigned char *) name + i)
			: 0;

#ifdef BLOAT_FS
	    dir->i_version = ++event;
#endif

	    unmap_buffer(bh);
	    mark_buffer_dirty(bh, 1);
	    *res_dir = de;
	    break;
	}
	if (offset < 1024)
	    continue;
	printk("elksfs_add_entry may need another unmap_buffer :)\n");
	brelse(bh);
	bh = NULL;
	offset = 0;
	block++;
    }
    *res_buf = bh;
    return 0;
}
Ejemplo n.º 9
0
Archivo: namei.c Proyecto: foolsh/elks
static int minix_add_entry(register struct inode *dir,
			   char *name,
			   size_t namelen,
			   ino_t ino)
{
    unsigned short block;
    loff_t offset;
    register struct buffer_head *bh;
    struct minix_dir_entry *de;
    struct minix_sb_info *info;

    if (!dir || !dir->i_sb)
	return -ENOENT;
    info = &dir->i_sb->u.minix_sb;
    if (namelen > info->s_namelen) {
#ifdef NO_TRUNCATE
	return -ENAMETOOLONG;
#else
	namelen = info->s_namelen;
#endif
    }
    if (!namelen)
	return -ENOENT;
    bh = NULL;
    block = 0;
    offset = 0L;
    while (1) {
	if (!bh) {
	    bh = minix_bread(dir, block, 1);
	    if (!bh)
		return -ENOSPC;
	    map_buffer(bh);
	}
	de = (struct minix_dir_entry *) (bh->b_data + offset);
	offset += info->s_dirsize;
	if (block * 1024L + offset > dir->i_size) {
	    de->inode = 0;
	    dir->i_size = block * 1024L + offset;
	    dir->i_dirt = 1;
	}
	if (de->inode) {
	    if (namecompare(namelen, info->s_namelen, name, de->name)) {
		debug2("MINIXadd_entry: file %t==%s (already exists)\n",
		     name, de->name);
		unmap_brelse(bh);
		return -EEXIST;
	    }
	} else {
	    size_t i;

	    dir->i_mtime = dir->i_ctime = CURRENT_TIME;
	    dir->i_dirt = 1;
	    memcpy_fromfs(de->name, name, namelen);
	    if((i = info->s_namelen - namelen) > 0)
		memset(de->name + namelen, 0, i);

#ifdef BLOAT_FS
	    dir->i_version = ++event;
#endif

	    de->inode = ino;
	    mark_buffer_dirty(bh, 1);
	    unmap_brelse(bh);
	    break;
	}
	if (offset >= BLOCK_SIZE) {
	    unmap_brelse(bh);
	    bh = NULL;
	    offset = 0;
	    block++;
	}
    }
    return 0;
}
Ejemplo n.º 10
0
/*
 *	sysv_add_entry()
 *
 * adds a file entry to the specified directory, returning a possible
 * error value if it fails.
 *
 * NOTE!! The inode part of 'de' is left at 0 - which means you
 * may not sleep between calling this and putting something into
 * the entry, as someone else might have used it while you slept.
 */
static int sysv_add_entry(struct inode * dir,
	const char * name, int namelen,
	struct buffer_head ** res_buf,
	struct sysv_dir_entry ** res_dir)
{
	struct super_block * sb;
	int i;
	unsigned long pos, block, offset; /* pos = block * block_size + offset */
	struct buffer_head * bh;
	struct sysv_dir_entry * de;

	*res_buf = NULL;
	*res_dir = NULL;
	sb = dir->i_sb;
	if (namelen > SYSV_NAMELEN) {
		if (sb->sv_truncate)
			namelen = SYSV_NAMELEN;
		else
			return -ENAMETOOLONG;
	}
	if (!namelen)
		return -ENOENT;
	bh = NULL;
	pos = block = offset = 0;
	while (1) {
		if (!bh) {
			bh = sysv_file_bread(dir, block, 1);
			if (!bh)
				return -ENOSPC;
		}
		de = (struct sysv_dir_entry *) (bh->b_data + offset);
		pos += SYSV_DIRSIZE;
		offset += SYSV_DIRSIZE;
		if (pos > dir->i_size) {
			de->inode = 0;
			dir->i_size = pos;
			mark_inode_dirty(dir);
		}
		if (de->inode) {
			if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
				brelse(bh);
				return -EEXIST;
			}
		} else {
			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
			mark_inode_dirty(dir);
			for (i = 0; i < SYSV_NAMELEN ; i++)
				de->name[i] = (i < namelen) ? name[i] : 0;
			mark_buffer_dirty(bh);
			*res_dir = de;
			break;
		}
		if (offset < sb->sv_block_size)
			continue;
		brelse(bh);
		bh = NULL;
		offset = 0; block++;
	}
	*res_buf = bh;
	return 0;
}
Ejemplo n.º 11
0
/*
 *	minix_add_entry()
 *
 * adds a file entry to the specified directory, returning a possible
 * error value if it fails.
 *
 * NOTE!! The inode part of 'de' is left at 0 - which means you
 * may not sleep between calling this and putting something into
 * the entry, as someone else might have used it while you slept.
 */
static int minix_add_entry(struct inode * dir,
	const char * name, int namelen,
	struct buffer_head ** res_buf,
	struct minix_dir_entry ** res_dir)
{
	int i;
	unsigned long block, offset;
	struct buffer_head * bh;
	struct minix_dir_entry * de;
	struct minix_sb_info * info;

	*res_buf = NULL;
	*res_dir = NULL;
	if (!dir || !dir->i_sb)
		return -ENOENT;
	info = &dir->i_sb->u.minix_sb;
	if (namelen > info->s_namelen) {
#ifdef NO_TRUNCATE
		return -ENAMETOOLONG;
#else
		namelen = info->s_namelen;
#endif
	}
	if (!namelen)
		return -ENOENT;
	bh = NULL;
	block = offset = 0;
	while (1) {
		if (!bh) {
			bh = minix_bread(dir,block,1);
			if (!bh)
				return -ENOSPC;
		}
		de = (struct minix_dir_entry *) (bh->b_data + offset);
		offset += info->s_dirsize;
		if (block*bh->b_size + offset > dir->i_size) {
			de->inode = 0;
			dir->i_size = block*bh->b_size + offset;
			mark_inode_dirty(dir);
		}
		if (de->inode) {
			if (namecompare(namelen, info->s_namelen, name, de->name)) {
				brelse(bh);
				return -EEXIST;
			}
		} else {
			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
			mark_inode_dirty(dir);
			for (i = 0; i < info->s_namelen ; i++)
				de->name[i] = (i < namelen) ? name[i] : 0;
			dir->i_version = ++event;
			mark_buffer_dirty(bh, 1);
			*res_dir = de;
			break;
		}
		if (offset < bh->b_size)
			continue;
		brelse(bh);
		bh = NULL;
		offset = 0;
		block++;
	}
	*res_buf = bh;
	return 0;
}
Ejemplo n.º 12
0
static int minix_add_entry(register struct inode *dir,
			   char *name,
			   size_t namelen,
			   struct buffer_head **res_buf,
			   struct minix_dir_entry **res_dir)
{
    unsigned short block;
    loff_t offset;
    register struct buffer_head *bh;
    struct minix_dir_entry *de;
    struct minix_sb_info *info;

    *res_buf = NULL;
    *res_dir = NULL;
    if (!dir || !dir->i_sb)
	return -ENOENT;
    info = &dir->i_sb->u.minix_sb;
    if (namelen > info->s_namelen) {
#ifdef NO_TRUNCATE
	return -ENAMETOOLONG;
#else
	namelen = info->s_namelen;
#endif
    }
    if (!namelen)
	return -ENOENT;
    bh = NULL;
    block = 0;
    offset = 0L;
    while (1) {
	if (!bh) {
	    bh = minix_bread(dir, block, 1);
	    if (!bh)
		return -ENOSPC;
	    map_buffer(bh);
	}
	de = (struct minix_dir_entry *) (bh->b_data + offset);
	offset += info->s_dirsize;
	if (block * 1024L + offset > dir->i_size) {
	    de->inode = 0;
	    dir->i_size = block * 1024L + offset;
	    dir->i_dirt = 1;
	}
	if (de->inode) {
	    if (namecompare(namelen, info->s_namelen, name, de->name)) {
		debug2("MINIXadd_entry: file %t==%s (already exists)\n",
		     name, de->name);
		unmap_brelse(bh);
		return -EEXIST;
	    }
	} else {
	    size_t i;

	    dir->i_mtime = dir->i_ctime = CURRENT_TIME;
	    dir->i_dirt = 1;
	    for (i = 0; i < info->s_namelen; i++)
		de->name[i] = (i < namelen) ? (char) get_fs_byte(name + i)
					    : '\0';

#ifdef BLOAT_FS
	    dir->i_version = ++event;
#endif

	    unmap_buffer(bh);
	    mark_buffer_dirty(bh, 1);
	    *res_dir = de;
	    break;
	}
	if (offset < 1024)
	    continue;
	unmap_brelse(bh);
	bh = NULL;
	offset = 0;
	block++;
    }
    *res_buf = bh;
    return 0;
}