brintos

brintos / linux-shallow public Read only

0
0
Text · 10.6 KiB · 0210df8 Raw
420 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  linux/fs/affs/inode.c4 *5 *  (c) 1996  Hans-Joachim Widmaier - Rewritten6 *7 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.8 *9 *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.10 *11 *  (C) 1991  Linus Torvalds - minix filesystem12 */13#include <linux/sched.h>14#include <linux/cred.h>15#include <linux/gfp.h>16#include "affs.h"17 18struct inode *affs_iget(struct super_block *sb, unsigned long ino)19{20	struct affs_sb_info	*sbi = AFFS_SB(sb);21	struct buffer_head	*bh;22	struct affs_tail	*tail;23	struct inode		*inode;24	u32			 block;25	u32			 size;26	u32			 prot;27	u16			 id;28 29	inode = iget_locked(sb, ino);30	if (!inode)31		return ERR_PTR(-ENOMEM);32	if (!(inode->i_state & I_NEW))33		return inode;34 35	pr_debug("affs_iget(%lu)\n", inode->i_ino);36 37	block = inode->i_ino;38	bh = affs_bread(sb, block);39	if (!bh) {40		affs_warning(sb, "read_inode", "Cannot read block %d", block);41		goto bad_inode;42	}43	if (affs_checksum_block(sb, bh) || be32_to_cpu(AFFS_HEAD(bh)->ptype) != T_SHORT) {44		affs_warning(sb,"read_inode",45			   "Checksum or type (ptype=%d) error on inode %d",46			   AFFS_HEAD(bh)->ptype, block);47		goto bad_inode;48	}49 50	tail = AFFS_TAIL(sb, bh);51	prot = be32_to_cpu(tail->protect);52 53	inode->i_size = 0;54	set_nlink(inode, 1);55	inode->i_mode = 0;56	AFFS_I(inode)->i_extcnt = 1;57	AFFS_I(inode)->i_ext_last = ~1;58	AFFS_I(inode)->i_protect = prot;59	atomic_set(&AFFS_I(inode)->i_opencnt, 0);60	AFFS_I(inode)->i_blkcnt = 0;61	AFFS_I(inode)->i_lc = NULL;62	AFFS_I(inode)->i_lc_size = 0;63	AFFS_I(inode)->i_lc_shift = 0;64	AFFS_I(inode)->i_lc_mask = 0;65	AFFS_I(inode)->i_ac = NULL;66	AFFS_I(inode)->i_ext_bh = NULL;67	AFFS_I(inode)->mmu_private = 0;68	AFFS_I(inode)->i_lastalloc = 0;69	AFFS_I(inode)->i_pa_cnt = 0;70 71	if (affs_test_opt(sbi->s_flags, SF_SETMODE))72		inode->i_mode = sbi->s_mode;73	else74		inode->i_mode = affs_prot_to_mode(prot);75 76	id = be16_to_cpu(tail->uid);77	if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETUID))78		inode->i_uid = sbi->s_uid;79	else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS))80		i_uid_write(inode, 0);81	else82		i_uid_write(inode, id);83 84	id = be16_to_cpu(tail->gid);85	if (id == 0 || affs_test_opt(sbi->s_flags, SF_SETGID))86		inode->i_gid = sbi->s_gid;87	else if (id == 0xFFFF && affs_test_opt(sbi->s_flags, SF_MUFS))88		i_gid_write(inode, 0);89	else90		i_gid_write(inode, id);91 92	switch (be32_to_cpu(tail->stype)) {93	case ST_ROOT:94		inode->i_uid = sbi->s_uid;95		inode->i_gid = sbi->s_gid;96		fallthrough;97	case ST_USERDIR:98		if (be32_to_cpu(tail->stype) == ST_USERDIR ||99		    affs_test_opt(sbi->s_flags, SF_SETMODE)) {100			if (inode->i_mode & S_IRUSR)101				inode->i_mode |= S_IXUSR;102			if (inode->i_mode & S_IRGRP)103				inode->i_mode |= S_IXGRP;104			if (inode->i_mode & S_IROTH)105				inode->i_mode |= S_IXOTH;106			inode->i_mode |= S_IFDIR;107		} else108			inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;109		/* Maybe it should be controlled by mount parameter? */110		//inode->i_mode |= S_ISVTX;111		inode->i_op = &affs_dir_inode_operations;112		inode->i_fop = &affs_dir_operations;113		break;114	case ST_LINKDIR:115#if 0116		affs_warning(sb, "read_inode", "inode is LINKDIR");117		goto bad_inode;118#else119		inode->i_mode |= S_IFDIR;120		/* ... and leave ->i_op and ->i_fop pointing to empty */121		break;122#endif123	case ST_LINKFILE:124		affs_warning(sb, "read_inode", "inode is LINKFILE");125		goto bad_inode;126	case ST_FILE:127		size = be32_to_cpu(tail->size);128		inode->i_mode |= S_IFREG;129		AFFS_I(inode)->mmu_private = inode->i_size = size;130		if (inode->i_size) {131			AFFS_I(inode)->i_blkcnt = (size - 1) /132					       sbi->s_data_blksize + 1;133			AFFS_I(inode)->i_extcnt = (AFFS_I(inode)->i_blkcnt - 1) /134					       sbi->s_hashsize + 1;135		}136		if (tail->link_chain)137			set_nlink(inode, 2);138		inode->i_mapping->a_ops = affs_test_opt(sbi->s_flags, SF_OFS) ?139					  &affs_aops_ofs : &affs_aops;140		inode->i_op = &affs_file_inode_operations;141		inode->i_fop = &affs_file_operations;142		break;143	case ST_SOFTLINK:144		inode->i_size = strlen((char *)AFFS_HEAD(bh)->table);145		inode->i_mode |= S_IFLNK;146		inode_nohighmem(inode);147		inode->i_op = &affs_symlink_inode_operations;148		inode->i_data.a_ops = &affs_symlink_aops;149		break;150	}151 152	inode_set_mtime(inode,153			inode_set_atime(inode, inode_set_ctime(inode, (be32_to_cpu(tail->change.days) * 86400LL + be32_to_cpu(tail->change.mins) * 60 + be32_to_cpu(tail->change.ticks) / 50 + AFFS_EPOCH_DELTA) + sys_tz.tz_minuteswest * 60, 0).tv_sec, 0).tv_sec,154			0);155	affs_brelse(bh);156	unlock_new_inode(inode);157	return inode;158 159bad_inode:160	affs_brelse(bh);161	iget_failed(inode);162	return ERR_PTR(-EIO);163}164 165int166affs_write_inode(struct inode *inode, struct writeback_control *wbc)167{168	struct super_block	*sb = inode->i_sb;169	struct buffer_head	*bh;170	struct affs_tail	*tail;171	uid_t			 uid;172	gid_t			 gid;173 174	pr_debug("write_inode(%lu)\n", inode->i_ino);175 176	if (!inode->i_nlink)177		// possibly free block178		return 0;179	bh = affs_bread(sb, inode->i_ino);180	if (!bh) {181		affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);182		return -EIO;183	}184	tail = AFFS_TAIL(sb, bh);185	if (tail->stype == cpu_to_be32(ST_ROOT)) {186		affs_secs_to_datestamp(inode_get_mtime_sec(inode),187				       &AFFS_ROOT_TAIL(sb, bh)->root_change);188	} else {189		tail->protect = cpu_to_be32(AFFS_I(inode)->i_protect);190		tail->size = cpu_to_be32(inode->i_size);191		affs_secs_to_datestamp(inode_get_mtime_sec(inode),192				       &tail->change);193		if (!(inode->i_ino == AFFS_SB(sb)->s_root_block)) {194			uid = i_uid_read(inode);195			gid = i_gid_read(inode);196			if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_MUFS)) {197				if (uid == 0 || uid == 0xFFFF)198					uid = uid ^ ~0;199				if (gid == 0 || gid == 0xFFFF)200					gid = gid ^ ~0;201			}202			if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETUID))203				tail->uid = cpu_to_be16(uid);204			if (!affs_test_opt(AFFS_SB(sb)->s_flags, SF_SETGID))205				tail->gid = cpu_to_be16(gid);206		}207	}208	affs_fix_checksum(sb, bh);209	mark_buffer_dirty_inode(bh, inode);210	affs_brelse(bh);211	affs_free_prealloc(inode);212	return 0;213}214 215int216affs_notify_change(struct mnt_idmap *idmap, struct dentry *dentry,217		   struct iattr *attr)218{219	struct inode *inode = d_inode(dentry);220	int error;221 222	pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid);223 224	error = setattr_prepare(&nop_mnt_idmap, dentry, attr);225	if (error)226		goto out;227 228	if (((attr->ia_valid & ATTR_UID) &&229	      affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETUID)) ||230	    ((attr->ia_valid & ATTR_GID) &&231	      affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_SETGID)) ||232	    ((attr->ia_valid & ATTR_MODE) &&233	     (AFFS_SB(inode->i_sb)->s_flags &234	      (AFFS_MOUNT_SF_SETMODE | AFFS_MOUNT_SF_IMMUTABLE)))) {235		if (!affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_QUIET))236			error = -EPERM;237		goto out;238	}239 240	if ((attr->ia_valid & ATTR_SIZE) &&241	    attr->ia_size != i_size_read(inode)) {242		error = inode_newsize_ok(inode, attr->ia_size);243		if (error)244			return error;245 246		truncate_setsize(inode, attr->ia_size);247		affs_truncate(inode);248	}249 250	setattr_copy(&nop_mnt_idmap, inode, attr);251	mark_inode_dirty(inode);252 253	if (attr->ia_valid & ATTR_MODE)254		affs_mode_to_prot(inode);255out:256	return error;257}258 259void260affs_evict_inode(struct inode *inode)261{262	unsigned long cache_page;263	pr_debug("evict_inode(ino=%lu, nlink=%u)\n",264		 inode->i_ino, inode->i_nlink);265	truncate_inode_pages_final(&inode->i_data);266 267	if (!inode->i_nlink) {268		inode->i_size = 0;269		affs_truncate(inode);270	}271 272	invalidate_inode_buffers(inode);273	clear_inode(inode);274	affs_free_prealloc(inode);275	cache_page = (unsigned long)AFFS_I(inode)->i_lc;276	if (cache_page) {277		pr_debug("freeing ext cache\n");278		AFFS_I(inode)->i_lc = NULL;279		AFFS_I(inode)->i_ac = NULL;280		free_page(cache_page);281	}282	affs_brelse(AFFS_I(inode)->i_ext_bh);283	AFFS_I(inode)->i_ext_last = ~1;284	AFFS_I(inode)->i_ext_bh = NULL;285 286	if (!inode->i_nlink)287		affs_free_block(inode->i_sb, inode->i_ino);288}289 290struct inode *291affs_new_inode(struct inode *dir)292{293	struct super_block	*sb = dir->i_sb;294	struct inode		*inode;295	u32			 block;296	struct buffer_head	*bh;297 298	if (!(inode = new_inode(sb)))299		goto err_inode;300 301	if (!(block = affs_alloc_block(dir, dir->i_ino)))302		goto err_block;303 304	bh = affs_getzeroblk(sb, block);305	if (!bh)306		goto err_bh;307	mark_buffer_dirty_inode(bh, inode);308	affs_brelse(bh);309 310	inode->i_uid     = current_fsuid();311	inode->i_gid     = current_fsgid();312	inode->i_ino     = block;313	set_nlink(inode, 1);314	simple_inode_init_ts(inode);315	atomic_set(&AFFS_I(inode)->i_opencnt, 0);316	AFFS_I(inode)->i_blkcnt = 0;317	AFFS_I(inode)->i_lc = NULL;318	AFFS_I(inode)->i_lc_size = 0;319	AFFS_I(inode)->i_lc_shift = 0;320	AFFS_I(inode)->i_lc_mask = 0;321	AFFS_I(inode)->i_ac = NULL;322	AFFS_I(inode)->i_ext_bh = NULL;323	AFFS_I(inode)->mmu_private = 0;324	AFFS_I(inode)->i_protect = 0;325	AFFS_I(inode)->i_lastalloc = 0;326	AFFS_I(inode)->i_pa_cnt = 0;327	AFFS_I(inode)->i_extcnt = 1;328	AFFS_I(inode)->i_ext_last = ~1;329 330	insert_inode_hash(inode);331 332	return inode;333 334err_bh:335	affs_free_block(sb, block);336err_block:337	iput(inode);338err_inode:339	return NULL;340}341 342/*343 * Add an entry to a directory. Create the header block344 * and insert it into the hash table.345 */346 347int348affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)349{350	struct super_block *sb = dir->i_sb;351	struct buffer_head *inode_bh = NULL;352	struct buffer_head *bh;353	u32 block = 0;354	int retval;355 356	pr_debug("%s(dir=%lu, inode=%lu, \"%pd\", type=%d)\n", __func__,357		 dir->i_ino, inode->i_ino, dentry, type);358 359	retval = -EIO;360	bh = affs_bread(sb, inode->i_ino);361	if (!bh)362		goto done;363 364	affs_lock_link(inode);365	switch (type) {366	case ST_LINKFILE:367	case ST_LINKDIR:368		retval = -ENOSPC;369		block = affs_alloc_block(dir, dir->i_ino);370		if (!block)371			goto err;372		retval = -EIO;373		inode_bh = bh;374		bh = affs_getzeroblk(sb, block);375		if (!bh)376			goto err;377		break;378	default:379		break;380	}381 382	AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);383	AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);384	affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);385	AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);386	AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);387 388	if (inode_bh) {389		__be32 chain;390	       	chain = AFFS_TAIL(sb, inode_bh)->link_chain;391		AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);392		AFFS_TAIL(sb, bh)->link_chain = chain;393		AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);394		affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));395		mark_buffer_dirty_inode(inode_bh, inode);396		set_nlink(inode, 2);397		ihold(inode);398	}399	affs_fix_checksum(sb, bh);400	mark_buffer_dirty_inode(bh, inode);401	dentry->d_fsdata = (void *)(long)bh->b_blocknr;402 403	affs_lock_dir(dir);404	retval = affs_insert_hash(dir, bh);405	mark_buffer_dirty_inode(bh, inode);406	affs_unlock_dir(dir);407	affs_unlock_link(inode);408 409	d_instantiate(dentry, inode);410done:411	affs_brelse(inode_bh);412	affs_brelse(bh);413	return retval;414err:415	if (block)416		affs_free_block(sb, block);417	affs_unlock_link(inode);418	goto done;419}420