Пример #1
0
static ssize_t
affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
	struct inode		*inode = filp->f_dentry->d_inode;
	char			*start;
	ssize_t			 left, offset, size, sector;
	ssize_t			 blocksize;
	struct buffer_head	*bh;
	void			*data;

	pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,
		 (unsigned long)*ppos,count);

	if (!inode) {
		affs_error(inode->i_sb,"file_read_ofs","Inode = NULL");
		return -EINVAL;
	}
	blocksize = AFFS_I2BSIZE(inode) - 24;
	if (!(S_ISREG(inode->i_mode))) {
		pr_debug("AFFS: file_read: mode = %07o",inode->i_mode);
		return -EINVAL;
	}
	if (*ppos >= inode->i_size || count <= 0)
		return 0;

	start = buf;
	for (;;) {
		left = MIN (inode->i_size - *ppos,count - (buf - start));
		if (!left)
			break;
		sector = affs_bmap(inode,(u32)*ppos / blocksize);
		if (!sector)
			break;
		offset = (u32)*ppos % blocksize;
		bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
		if (!bh)
			break;
		data = bh->b_data + 24;
		size = MIN(blocksize - offset,left);
		*ppos += size;
		copy_to_user(buf,data + offset,size);
		buf += size;
		affs_brelse(bh);
	}
	if (start == buf)
		return -EIO;
	return buf - start;
}
Пример #2
0
static struct buffer_head *
affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
{
	struct buffer_head	*bh;
	int			 intl = AFFS_I2FSTYPE(dir);
	s32			 key;
	const char		*name = dentry->d_name.name;
	int			 namelen = dentry->d_name.len;

	pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);

	bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
	if (!bh)
		return NULL;

	if (namelen == 1 && name[0] == '.') {
		*ino = dir->i_ino;
		return bh;
	}
	if (namelen == 2 && name[0] == '.' && name[1] == '.') {
		*ino = affs_parent_ino(dir);
		return bh;
	}

	key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));

	for (;;) {
		unsigned char *cname;
		int cnamelen;

		affs_brelse(bh);
		bh = NULL;
		if (key == 0)
			break;
		bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
		if (!bh)
			break;
		cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
		if (affs_match(name,namelen,cname,cnamelen,intl))
			break;
		key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain);
	}
	*ino = key;
	return bh;
}
Пример #3
0
void
affs_write_inode(struct inode *inode)
{
	struct buffer_head	*bh;
	struct file_end		*file_end;
	uid_t			 uid;
	gid_t			 gid;

	pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);

	if (!inode->i_nlink)
		return;
	if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
		affs_error(inode->i_sb,"write_inode","Cannot read block %lu",inode->i_ino);
		return;
	}
	file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
	if (file_end->secondary_type == be32_to_cpu(ST_ROOT)) {
		secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered);
	} else {
		file_end->protect   = cpu_to_be32(inode->u.affs_i.i_protect ^ FIBF_OWNER);
		file_end->byte_size = cpu_to_be32(inode->i_size);
		secs_to_datestamp(inode->i_mtime,&file_end->created);
		if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) {
			uid = inode->i_uid;
			gid = inode->i_gid;
			if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
				if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
					uid = inode->i_uid ^ ~0;
				if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
					gid = inode->i_gid ^ ~0;
			}
			if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID))
				file_end->owner_uid = cpu_to_be16(uid);
			if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID))
				file_end->owner_gid = cpu_to_be16(gid);
		}
	}
	affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
	mark_buffer_dirty(bh,1);
	brelse(bh);
}
Пример #4
0
static int
affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	int			 j, namelen;
	s32			 i;
	int			 hash_pos;
	int			 chain_pos;
	unsigned long		 ino;
	int			 stored;
	unsigned char		*name;
	struct buffer_head	*dir_bh;
	struct buffer_head	*fh_bh;
	struct inode		*dir;
	struct inode		*inode = filp->f_dentry->d_inode;

	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);

	stored = 0;
	dir_bh = NULL;
	fh_bh  = NULL;
	dir    = NULL;
	ino    = inode->i_ino;

	if (filp->f_pos == 0) {
		filp->private_data = (void *)0;
		if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
			return 0;
		}
		++filp->f_pos;
		stored++;
	}
	if (filp->f_pos == 1) {
		if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
			return stored;
		}
		filp->f_pos = 2;
		stored++;
	}
	chain_pos = (filp->f_pos - 2) & 0xffff;
	hash_pos  = (filp->f_pos - 2) >> 16;
	if (chain_pos == 0xffff) {
		affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
		chain_pos = 0;
		hash_pos++;
		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
	}
	if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
				  AFFS_I2BSIZE(inode))))
		goto readdir_done;

	while (1) {
		while (hash_pos < AFFS_I2HSIZE(inode) &&
		     !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
			hash_pos++;
		if (hash_pos >= AFFS_I2HSIZE(inode))
			break;
		
		i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
		j = chain_pos;

		/* If the directory hasn't changed since the last call to readdir(),
		 * we can jump directly to where we left off.
		 */
		if (filp->private_data && filp->f_version == inode->i_version) {
			i = (s32)filp->private_data;
			j = 0;
			pr_debug("AFFS: readdir() left off=%d\n",i);
		}
		filp->f_version = inode->i_version;
		pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
		while (i) {
			if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
				affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
				goto readdir_done;
			}
			ino = i;
			i   = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
			if (j == 0)
				break;
			affs_brelse(fh_bh);
			fh_bh = NULL;
			j--;
		}
		if (fh_bh) {
			namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
			pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
				 namelen,name,ino,i);
			filp->private_data = (void *)ino;
			if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
				goto readdir_done;
			filp->private_data = (void *)i;
			affs_brelse(fh_bh);
			fh_bh = NULL;
			stored++;
		}
		if (i == 0) {
			hash_pos++;
			chain_pos = 0;
		} else
			chain_pos++;
		filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
	}

readdir_done:
	affs_brelse(dir_bh);
	affs_brelse(fh_bh);
	pr_debug("AFFS: readdir()=%d\n",stored);
	return stored;
}
Пример #5
0
int
affs_rename(struct inode *old_dir, struct dentry *old_dentry,
	    struct inode *new_dir, struct dentry *new_dentry)
{
	struct inode		*old_inode = old_dentry->d_inode;
	struct inode		*new_inode = new_dentry->d_inode;
	struct buffer_head	*old_bh;
	struct buffer_head	*new_bh;
	unsigned long		 old_ino;
	unsigned long		 new_ino;
	int			 retval;

	pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p))\n",
		 old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode,
		 new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode);
	
	if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
		goto out;

	new_bh = NULL;
	retval = -ENOENT;
	old_bh = affs_find_entry(old_dir,old_dentry,&old_ino);
	if (!old_bh)
		goto end_rename;

	new_bh = affs_find_entry(new_dir,new_dentry,&new_ino);
	if (new_bh && !new_inode) {
		affs_error(old_inode->i_sb,"affs_rename",
			   "No inode for entry found (key=%lu)\n",new_ino);
		goto end_rename;
	}
	if (S_ISDIR(old_inode->i_mode)) {
		if (new_inode) {
			retval = -ENOTEMPTY;
			if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
				goto end_rename;
		}

		retval = -ENOENT;
		if (affs_parent_ino(old_inode) != old_dir->i_ino)
			goto end_rename;
	}
	/* Unlink destination if it already exists */
	if (new_inode) {
		if ((retval = affs_remove_header(new_bh,new_dir)) < 0)
			goto end_rename;
		new_inode->i_nlink = retval;
		mark_inode_dirty(new_inode);
		if (new_inode->i_ino == new_ino)
			new_inode->i_nlink = 0;
	}
	/* Remove header from its parent directory. */
	if ((retval = affs_remove_hash(old_bh,old_dir)))
		goto end_rename;
	/* And insert it into the new directory with the new name. */
	affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name);
	if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir)))
		goto end_rename;
	affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5);

	new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime
			   = old_dir->i_mtime = CURRENT_TIME;
	new_dir->i_version = ++event;
	old_dir->i_version = ++event;
	retval             = 0;
	mark_inode_dirty(new_dir);
	mark_inode_dirty(old_dir);
	mark_buffer_dirty(old_bh,1);
	
end_rename:
	affs_brelse(old_bh);
	affs_brelse(new_bh);
out:
	return retval;
}
Пример #6
0
int
affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
	struct buffer_head	*bh;
	struct inode		*inode;
	char			*p;
	unsigned long		 tmp;
	int			 i, maxlen, error;
	char			 c, lc;

	pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
		 (int)dentry->d_name.len,dentry->d_name.name,symname);
	
	maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
	error = -ENOSPC;
	inode  = affs_new_inode(dir);
	if (!inode)
		goto out;

	inode->i_op   = &affs_symlink_inode_operations;
	inode->i_mode = S_IFLNK | 0777;
	inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
	error = -EIO;
	bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
	if (!bh)
		goto out_iput;
	i  = 0;
	p  = ((struct slink_front *)bh->b_data)->symname;
	lc = '/';
	if (*symname == '/') {
		while (*symname == '/')
			symname++;
		while (inode->i_sb->u.affs_sb.s_volume[i])	/* Cannot overflow */
			*p++ = inode->i_sb->u.affs_sb.s_volume[i++];
	}
	while (i < maxlen && (c = *symname++)) {
		if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
			*p++ = '/';
			i++;
			symname += 2;
			lc = '/';
		} else if (c == '.' && lc == '/' && *symname == '/') {
			symname++;
			lc = '/';
		} else {
			*p++ = c;
			lc   = c;
			i++;
		}
		if (lc == '/')
			while (*symname == '/')
				symname++;
	}
	*p = 0;
	mark_buffer_dirty(bh,1);
	affs_brelse(bh);
	mark_inode_dirty(inode);

	/* N.B. This test shouldn't be necessary ... dentry must be negative */
	error = -EEXIST;
	bh = affs_find_entry(dir,dentry,&tmp);
	if (bh)
		goto out_release;
	/* N.B. Shouldn't we add the entry before dirtying the buffer? */
	error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
	if (error)
		goto out_release;
	d_instantiate(dentry,inode);
	dir->i_version = ++event;
	mark_inode_dirty(dir);

out:
	return error;

out_release:
	affs_brelse(bh);
out_iput:
	inode->i_nlink = 0;
	mark_inode_dirty(inode);
	iput(inode);
	goto out;
}
Пример #7
0
void
affs_truncate(struct inode *inode)
{
	struct buffer_head	*bh = NULL;
	int	 first;			/* First block to be thrown away	*/
	int	 block;
	s32	 key;
	s32	*keyp;
	s32	 ekey;
	s32	 ptype, stype;
	int	 freethis;
	int	 net_blocksize;
	int	 blocksize = AFFS_I2BSIZE(inode);
	int	 rem;
	int	 ext;

	pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);

	net_blocksize = blocksize - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
	first = (inode->i_size + net_blocksize - 1) / net_blocksize;
	if (inode->u.affs_i.i_lastblock < first - 1) {
		/* There has to be at least one new block to be allocated */
		if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) {
			/* XXX Fine! No way to indicate an error. */
			return /* -ENOSPC */;
		}
		bh = affs_getblock(inode,first - 1);
		if (!bh) {
			affs_warning(inode->i_sb,"truncate","Cannot extend file");
			inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1);
		} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
			rem = inode->i_size % net_blocksize;
			DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize);
			affs_fix_checksum(blocksize,bh->b_data,5);
			mark_buffer_dirty(bh,0);
		}
		goto out_truncate;
	}
	ekey = inode->i_ino;
	ext  = 0;

	/* Free all blocks starting at 'first' and all then-empty
	 * extension blocks. Do not free the header block, though.
	 */
	while (ekey) {
		if (!(bh = affs_bread(inode->i_dev,ekey,blocksize))) {
			affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey);
			goto out_truncate;
		}
		if (affs_checksum_block(blocksize,bh->b_data,&ptype,&stype)) {
			affs_error(inode->i_sb,"truncate","Checksum error in header/ext block %d",
				   ekey);
			goto out_truncate;
		}
		if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
			affs_error(inode->i_sb,"truncate",
				   "Bad block (key=%d, ptype=%d, stype=%d)",ekey,ptype,stype);
			goto out_truncate;
		}
		/* Do we have to free this extension block after
		 * freeing the data blocks pointed to?
		 */
		freethis = first == 0 && ekey != inode->i_ino;

		/* Free the data blocks. 'first' is relative to this
		 * extension block and may well lie behind this block.
		 */
		for (block = first; block < AFFS_I2HSIZE(inode); block++) {
			keyp = &AFFS_BLOCK(bh->b_data,inode,block);
			key  = be32_to_cpu(*keyp);
			if (key) {
				*keyp = 0;
				affs_free_block(inode->i_sb,key);
			} else
				break;
		}
		keyp = &GET_END_PTR(struct file_end,bh->b_data,blocksize)->extension;
		key  = be32_to_cpu(*keyp);

		/* If 'first' is in this block or is the first
		 * in the next one, this will be the last in
		 * the list, thus we have to adjust the count
		 * and zero the pointer to the next ext block.
		 */
		if (first <= AFFS_I2HSIZE(inode)) {
			((struct file_front *)bh->b_data)->block_count = cpu_to_be32(first);
			first = 0;
			*keyp = 0;
			affs_fix_checksum(blocksize,bh->b_data,5);
			mark_buffer_dirty(bh,1);
		} else
			first -= AFFS_I2HSIZE(inode);
		affs_brelse(bh);
		bh = NULL;
		if (freethis)			/* Don't bother fixing checksum */
			affs_free_block(inode->i_sb,ekey);
		ekey = key;
	}
	block = ((inode->i_size + net_blocksize - 1) / net_blocksize) - 1;
	inode->u.affs_i.i_lastblock = block;

	/* If the file is not truncated to a block boundary,
	 * the partial block after the EOF must be zeroed
	 * so it cannot become accessible again.
	 */

	rem = inode->i_size % net_blocksize;
	if (rem) {
		if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) 
			rem += 24;
		pr_debug("AFFS: Zeroing from offset %d in block %d\n",rem,block);
		bh = affs_getblock(inode,block);
		if (bh) {
			memset(bh->b_data + rem,0,blocksize - rem);
			if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) {
				((struct data_front *)bh->b_data)->data_size = cpu_to_be32(rem);
				((struct data_front *)bh->b_data)->next_data = 0;
				affs_fix_checksum(blocksize,bh->b_data,5);
			}
			mark_buffer_dirty(bh,1);
		} else 
			affs_error(inode->i_sb,"truncate","Cannot read block %d",block);
	}

out_truncate:
	affs_brelse(bh);
	/* Invalidate cache */
	if (inode->u.affs_i.i_ec) {
		inode->u.affs_i.i_ec->max_ext = 0;
		for (key = 0; key < 3; key++) {
			inode->u.affs_i.i_ec->kc[key].kc_next_key = 0;
			inode->u.affs_i.i_ec->kc[key].kc_last     = -1;
		}
	}
	mark_inode_dirty(inode);
}
Пример #8
0
static ssize_t
affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
	struct inode		*inode = filp->f_dentry->d_inode;
	off_t			 pos;
	ssize_t			 written;
	ssize_t			 c;
	ssize_t			 blocksize;
	struct buffer_head	*bh;
	char			*p;

	pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
		(unsigned long)*ppos,count);

	if (!count)
		return 0;
	if (!inode) {
		affs_error(inode->i_sb,"file_write_ofs","Inode = NULL");
		return -EINVAL;
	}
	if (!S_ISREG(inode->i_mode)) {
		affs_error(inode->i_sb,"file_write_ofs",
			   "Trying to write to non-regular file (mode=%07o)",
			   inode->i_mode);
		return -EINVAL;
	}
	if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode))
		return -ENOMEM;
	if (filp->f_flags & O_APPEND)
		pos = inode->i_size;
	else
		pos = *ppos;

	bh        = NULL;
	blocksize = AFFS_I2BSIZE(inode) - 24;
	written   = 0;
	while (written < count) {
		bh = affs_getblock(inode,pos / blocksize);
		if (!bh) {
			if (!written)
				written = -ENOSPC;
			break;
		}
		c = blocksize - (pos % blocksize);
		if (c > count - written)
			c = count - written;
		if (c != blocksize && !buffer_uptodate(bh)) {
			ll_rw_block(READ,1,&bh);
			wait_on_buffer(bh);
			if (!buffer_uptodate(bh)) {
				affs_brelse(bh);
				if (!written)
					written = -EIO;
				break;
			}
		}
		p  = (pos % blocksize) + bh->b_data + 24;
		c -= copy_from_user(p,buf,c);
		if (!c) {
			affs_brelse(bh);
			if (!written)
				written = -EFAULT;
			break;
		}
		update_vm_cache(inode,pos,p,c);

		pos     += c;
		buf     += c;
		written += c;
		DATA_FRONT(bh)->data_size = cpu_to_be32(be32_to_cpu(DATA_FRONT(bh)->data_size) + c);
		affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
		mark_buffer_uptodate(bh,1);
		mark_buffer_dirty(bh,0);
		affs_brelse(bh);
	}
	if (pos > inode->i_size)
		inode->i_size = pos;
	*ppos = pos;
	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
	mark_inode_dirty(inode);
	return written;
}
Пример #9
0
static struct buffer_head *
affs_getblock(struct inode *inode, s32 block)
{
	struct super_block	*sb = inode->i_sb;
	int			 ofs = sb->u.affs_sb.s_flags & SF_OFS;
	int			 ext = block / AFFS_I2HSIZE(inode);
	struct buffer_head	*bh, *ebh, *pbh = NULL;
	struct key_cache	*kc;
	s32			 key, nkey;
	int			 cf, j, pt;
	int			 index;
	int			 err;

	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);

	if (block < 0)
		goto out_fail;

	key    = calc_key(inode,&ext);
	block -= ext * AFFS_I2HSIZE(inode);
	pt     = ext ? T_LIST : T_SHORT;

	/* Key refers now to the last known extension block,
	 * ext is its sequence number (if 0, key refers to the
	 * header block), and block is the block number relative
	 * to the first block stored in that extension block.
	 */
	for (;;) {	/* Loop over header block and extension blocks */
		struct file_front *fdp;

		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
		if (!bh)
			goto out_fail;
		fdp = (struct file_front *) bh->b_data;
		err = affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j);
		if (err || cf != pt || j != ST_FILE) {
		    	affs_error(sb, "getblock",
				"Block %d is not a valid %s", key,
				pt == T_SHORT ? "file header" : "ext block");
			goto out_free_bh;
		}
		j  = be32_to_cpu(((struct file_front *)bh->b_data)->block_count);
		for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) {
			if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
				if (j > 0) {
					s32 k = AFFS_BLOCK(bh->b_data, inode,
								j - 1);
					pbh = affs_bread(inode->i_dev,
							be32_to_cpu(k),
							AFFS_I2BSIZE(inode));
				} else
					pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
				if (!pbh) {
					affs_error(sb,"getblock",
						"Cannot get last block in file");
					break;
				}
			}
			nkey = affs_new_data(inode);
			if (!nkey)
				break;
			inode->u.affs_i.i_lastblock++;
			if (AFFS_BLOCK(bh->b_data,inode,j)) {
				affs_warning(sb,"getblock","Block already allocated");
				affs_free_block(sb,nkey);
				continue;
			}
			AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey);
			if (ofs) {
				ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
				if (!ebh) {
					affs_error(sb,"getblock",
						   "Cannot get block %d",nkey);
					affs_free_block(sb,nkey);
					AFFS_BLOCK(bh->b_data,inode,j) = 0;
					break;
				}
				DATA_FRONT(ebh)->primary_type    = cpu_to_be32(T_DATA);
				DATA_FRONT(ebh)->header_key      = cpu_to_be32(inode->i_ino);
				DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);
				affs_fix_checksum(AFFS_I2BSIZE(inode),
							ebh->b_data, 5);
				mark_buffer_dirty(ebh, 0);
				if (pbh) {
					DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);
					DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey);
					affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
					mark_buffer_dirty(pbh,0);
					affs_brelse(pbh);
				}
				pbh = ebh;
			}
			cf = 1;
		}
		/* N.B. May need to release pbh after here */

		if (cf) {
			if (pt == T_SHORT)
				fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0);
			fdp->block_count = cpu_to_be32(j);
			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
			mark_buffer_dirty(bh,1);
		}

		if (block < j) {
			if (pbh)
				affs_brelse(pbh);
			break;
		}
		if (j < AFFS_I2HSIZE(inode)) {
			/* N.B. What about pbh here? */
			goto out_free_bh;
		}

		block -= AFFS_I2HSIZE(inode);
		key    = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
		if (!key) {
			key = affs_new_header(inode);
			if (!key)
				goto out_free_bh;
			ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
			if (!ebh) {
				/* N.B. must free bh here */
				goto out_free_block;
			}
			((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST);
			((struct file_front *)ebh->b_data)->own_key      = cpu_to_be32(key);
			FILE_END(ebh->b_data,inode)->secondary_type      = cpu_to_be32(ST_FILE);
			FILE_END(ebh->b_data,inode)->parent              = cpu_to_be32(inode->i_ino);
			affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
			mark_buffer_dirty(ebh, 1);
			FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key);
			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
			mark_buffer_dirty(bh,1);
			affs_brelse(bh);
			bh = ebh;
		}
		pt = T_LIST;
		ext++;
		index = seqnum_to_index(ext);
		if (index > inode->u.affs_i.i_ec->max_ext &&
		    AFFS_ISINDEX(ext)) {
			inode->u.affs_i.i_ec->ec[index] = key;
			inode->u.affs_i.i_ec->max_ext   = index;
		}
		affs_brelse(bh);
	}

	/* Invalidate key cache */
	for (j = 0; j < 4; j++) {
		kc = &inode->u.affs_i.i_ec->kc[j];
		kc->kc_last = -1;
	}
	key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
	affs_brelse(bh);
	if (!key)
		goto out_fail;

	bh = affs_bread(inode->i_dev, key, AFFS_I2BSIZE(inode));
	return bh;

out_free_block:
	affs_free_block(sb, key);
out_free_bh:
	affs_brelse(bh);
out_fail:
	return NULL;
}
Пример #10
0
static int
affs_bmap(struct inode *inode, int block)
{
	struct buffer_head	*bh;
	s32			 key, nkey;
	s32			 ptype, stype;
	int			 ext;
	int			 index;
	int			 keycount;
	struct key_cache	*kc;
	struct key_cache	*tkc;
	struct timeval		 tv;
	s32			*keyp;
	int			 i;

	pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);

	if (block < 0) {
		affs_error(inode->i_sb,"bmap","Block < 0");
		return 0;
	}
	if (!inode->u.affs_i.i_ec) {
		if (alloc_ext_cache(inode)) {
			return 0;
		}
	}

	/* Try to find the requested key in the cache.
	 * In order to speed this up as much as possible,
	 * the cache line lookup is done in a separate
	 * step.
	 */

	for (i = 0; i < 4; i++) {
		tkc = &inode->u.affs_i.i_ec->kc[i];
		/* Look in any cache if the key is there */
		if (block <= tkc->kc_last && block >= tkc->kc_first) {
			return tkc->kc_keys[block - tkc->kc_first];
		}
	}
	kc = NULL;
#ifdef OSKIT
	tv.tv_sec  = CURRENT_TIME;
	tv.tv_usec = 0;
#else
	tv = xtime;
#endif
	for (i = 0; i < 4; i++) {
		tkc = &inode->u.affs_i.i_ec->kc[i];
		if (tkc->kc_lru_time.tv_sec > tv.tv_sec)
			continue;
		if (tkc->kc_lru_time.tv_sec < tv.tv_sec ||
		    tkc->kc_lru_time.tv_usec < tv.tv_usec) {
			kc = tkc;
			tv = tkc->kc_lru_time;
		}
	}
	if (!kc)	/* Really shouldn't happen */
		kc = tkc;
#ifdef OSKIT
	kc->kc_lru_time.tv_sec  = CURRENT_TIME;
	kc->kc_lru_time.tv_usec = 0;
#else
	kc->kc_lru_time = xtime;
#endif
	keyp            = kc->kc_keys;
	kc->kc_first    = block;
	kc->kc_last     = -1;
	keycount        = AFFS_KCSIZE;

	/* Calculate sequence number of the extension block where the
	 * number of the requested block is stored. 0 means it's in
	 * the file header.
	 */

	ext    = block / AFFS_I2HSIZE(inode);
	key    = calc_key(inode,&ext);
	block -= ext * AFFS_I2HSIZE(inode);

	for (;;) {
		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
		if (!bh) 
			return 0;
		index = seqnum_to_index(ext);
		if (index > inode->u.affs_i.i_ec->max_ext &&
		    (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
		     (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE)) {
			affs_brelse(bh);
			return 0;
		}
		nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
		if (block < AFFS_I2HSIZE(inode)) {
			/* Fill cache as much as possible */
			if (keycount) {
				kc->kc_first = ext * AFFS_I2HSIZE(inode) + block;
				keycount     = keycount < AFFS_I2HSIZE(inode) - block ? keycount :
						AFFS_I2HSIZE(inode) - block;
				for (i = 0; i < keycount; i++)
					kc->kc_keys[i] = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block + i));
				kc->kc_last = kc->kc_first + i - 1;
			}
			break;
		}
		block -= AFFS_I2HSIZE(inode);
		affs_brelse(bh);
		ext++;
		if (index > inode->u.affs_i.i_ec->max_ext && AFFS_ISINDEX(ext)) {
			inode->u.affs_i.i_ec->ec[index] = nkey;
			inode->u.affs_i.i_ec->max_ext   = index;
		}
		key = nkey;
	}
	kc->kc_this_key = key;
	kc->kc_this_seq = ext;
	kc->kc_next_key = nkey;
	key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
	affs_brelse(bh);
	return key;
}
Пример #11
0
void
affs_read_inode(struct inode *inode)
{
	struct buffer_head	*bh;
	struct file_front	*file_front;
	struct file_end		*file_end;
	s32			 block;
	unsigned long		 prot;
	s32			 ptype, stype;
	unsigned short		 id;

	pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);

	block = inode->i_ino;
	if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
		affs_error(inode->i_sb,"read_inode","Cannot read block %d",block);
		return;
	}
	if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) {
		affs_error(inode->i_sb,"read_inode",
			   "Checksum or type (ptype=%d) error on inode %d",ptype,block);
		affs_brelse(bh);
		return;
	}

	file_front = (struct file_front *)bh->b_data;
	file_end   = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
	prot       = (be32_to_cpu(file_end->protect) & ~0x10) ^ FIBF_OWNER;

	inode->u.affs_i.i_protect      = prot;
	inode->u.affs_i.i_parent       = be32_to_cpu(file_end->parent);
	inode->u.affs_i.i_original     = 0;
	inode->u.affs_i.i_zone         = 0;
	inode->u.affs_i.i_hlink        = 0;
	inode->u.affs_i.i_pa_cnt       = 0;
	inode->u.affs_i.i_pa_next      = 0;
	inode->u.affs_i.i_pa_last      = 0;
	inode->u.affs_i.i_ec           = NULL;
	inode->u.affs_i.i_lastblock    = -1;
	inode->i_nlink                 = 1;
	inode->i_mode                  = 0;

	if (inode->i_sb->u.affs_sb.s_flags & SF_SETMODE)
		inode->i_mode = inode->i_sb->u.affs_sb.s_mode;
	else
		inode->i_mode = prot_to_mode(prot);

	if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
		inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
	id = be16_to_cpu(file_end->owner_uid);
	if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
		inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
	else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
		inode->i_uid = 0;
	else 
		inode->i_uid = id;

	id = be16_to_cpu(file_end->owner_gid);
	if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETGID)
		inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
	else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS)
		inode->i_gid = 0;
	else
		inode->i_gid = id;

	switch (be32_to_cpu(file_end->secondary_type)) {
		case ST_ROOT:
			inode->i_uid   = inode->i_sb->u.affs_sb.s_uid;
			inode->i_gid   = inode->i_sb->u.affs_sb.s_gid;
		case ST_USERDIR:
			if (be32_to_cpu(file_end->secondary_type) == ST_USERDIR ||
			    inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) {
				if (inode->i_mode & S_IRUSR)
					inode->i_mode |= S_IXUSR;
				if (inode->i_mode & S_IRGRP)
					inode->i_mode |= S_IXGRP;
				if (inode->i_mode & S_IROTH)
					inode->i_mode |= S_IXOTH;
				inode->i_mode |= S_IFDIR;
			} else
				inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
			inode->i_size  = 0;
			break;
		case ST_LINKDIR:
			affs_error(inode->i_sb,"read_inode","inode is LINKDIR");
			affs_brelse(bh);
			return;
		case ST_LINKFILE:
			affs_error(inode->i_sb,"read_inode","inode is LINKFILE");
			affs_brelse(bh);
			return;
		case ST_FILE:
			inode->i_mode |= S_IFREG;
			inode->i_size  = be32_to_cpu(file_end->byte_size);
			if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
				block = AFFS_I2BSIZE(inode) - 24;
			else
				block = AFFS_I2BSIZE(inode);
			inode->u.affs_i.i_lastblock = ((inode->i_size + block - 1) / block) - 1;
			break;
		case ST_SOFTLINK:
			inode->i_mode |= S_IFLNK;
			inode->i_size  = 0;
			break;
	}

	inode->i_mtime = inode->i_atime = inode->i_ctime
		       = (be32_to_cpu(file_end->created.ds_Days) * (24 * 60 * 60) +
		         be32_to_cpu(file_end->created.ds_Minute) * 60 +
			 be32_to_cpu(file_end->created.ds_Tick) / 50 +
			 ((8 * 365 + 2) * 24 * 60 * 60)) +
			 sys_tz.tz_minuteswest * 60;
	affs_brelse(bh);

	inode->i_op = NULL;
	if (S_ISREG(inode->i_mode)) {
		if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
			inode->i_op = &affs_file_inode_operations_ofs;
		} else {
			inode->i_op = &affs_file_inode_operations;
		}
	} else if (S_ISDIR(inode->i_mode)) {
		/* Maybe it should be controlled by mount parameter? */
		inode->i_mode |= S_ISVTX;
		inode->i_op = &affs_dir_inode_operations;
	}
	else if (S_ISLNK(inode->i_mode))
		inode->i_op = &affs_symlink_inode_operations;
}
Пример #12
0
int
affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
	       struct dentry *dentry, int type)
{
	struct buffer_head	*dir_bh;
	struct buffer_head	*inode_bh;
	struct buffer_head	*link_bh;
	int			 retval;
	const unsigned char	*name = dentry->d_name.name;
	int			 len  = dentry->d_name.len;

	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino,
		 len,name,type);

	if ((retval = affs_check_name(name,len)))
		return retval;
	if (len > 30)
		len = 30;

	dir_bh   = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
	inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
	link_bh  = NULL;
	retval   = -EIO;
	if (!dir_bh || !inode_bh)
		goto addentry_done;
	if (link) {
		link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
		if (!link_bh)
			goto addentry_done;
	}
	((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT);
	((struct dir_front *)inode_bh->b_data)->own_key      = cpu_to_be32(inode->i_ino);
	DIR_END(inode_bh->b_data,inode)->dir_name[0]         = len;
	strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
	DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type);
	DIR_END(inode_bh->b_data,inode)->parent         = cpu_to_be32(dir->i_ino);

	lock_super(inode->i_sb);
	retval = affs_insert_hash(dir->i_ino,inode_bh,dir);

	if (link_bh) {
		LINK_END(inode_bh->b_data,inode)->original   = cpu_to_be32(link->i_ino);
		LINK_END(inode_bh->b_data,inode)->link_chain =
						FILE_END(link_bh->b_data,link)->link_chain;
		FILE_END(link_bh->b_data,link)->link_chain   = cpu_to_be32(inode->i_ino);
		affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
		link->i_version = ++global_event;
		mark_inode_dirty(link);
		mark_buffer_dirty(link_bh,1);
	}
	affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
	affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
	dir->i_version = ++global_event;
	dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
	unlock_super(inode->i_sb);

	mark_inode_dirty(dir);
	mark_inode_dirty(inode);
	mark_buffer_dirty(dir_bh,1);
	mark_buffer_dirty(inode_bh,1);

addentry_done:
	affs_brelse(dir_bh);
	affs_brelse(inode_bh);
	affs_brelse(link_bh);

	return retval;
}