xref: /OK3568_Linux_fs/kernel/fs/affs/amigaffs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/fs/affs/amigaffs.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  (c) 1996  Hans-Joachim Widmaier - Rewritten
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *  (C) 1993  Ray Burr - Amiga FFS filesystem.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *  Please send bug reports to: hjw@zvw.de
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/math64.h>
13*4882a593Smuzhiyun #include <linux/iversion.h>
14*4882a593Smuzhiyun #include "affs.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /*
17*4882a593Smuzhiyun  * Functions for accessing Amiga-FFS structures.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* Insert a header block bh into the directory dir
22*4882a593Smuzhiyun  * caller must hold AFFS_DIR->i_hash_lock!
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun int
affs_insert_hash(struct inode * dir,struct buffer_head * bh)26*4882a593Smuzhiyun affs_insert_hash(struct inode *dir, struct buffer_head *bh)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	struct super_block *sb = dir->i_sb;
29*4882a593Smuzhiyun 	struct buffer_head *dir_bh;
30*4882a593Smuzhiyun 	u32 ino, hash_ino;
31*4882a593Smuzhiyun 	int offset;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	ino = bh->b_blocknr;
34*4882a593Smuzhiyun 	offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	pr_debug("%s(dir=%lu, ino=%d)\n", __func__, dir->i_ino, ino);
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	dir_bh = affs_bread(sb, dir->i_ino);
39*4882a593Smuzhiyun 	if (!dir_bh)
40*4882a593Smuzhiyun 		return -EIO;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
43*4882a593Smuzhiyun 	while (hash_ino) {
44*4882a593Smuzhiyun 		affs_brelse(dir_bh);
45*4882a593Smuzhiyun 		dir_bh = affs_bread(sb, hash_ino);
46*4882a593Smuzhiyun 		if (!dir_bh)
47*4882a593Smuzhiyun 			return -EIO;
48*4882a593Smuzhiyun 		hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 	AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
51*4882a593Smuzhiyun 	AFFS_TAIL(sb, bh)->hash_chain = 0;
52*4882a593Smuzhiyun 	affs_fix_checksum(sb, bh);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	if (dir->i_ino == dir_bh->b_blocknr)
55*4882a593Smuzhiyun 		AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
56*4882a593Smuzhiyun 	else
57*4882a593Smuzhiyun 		AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	affs_adjust_checksum(dir_bh, ino);
60*4882a593Smuzhiyun 	mark_buffer_dirty_inode(dir_bh, dir);
61*4882a593Smuzhiyun 	affs_brelse(dir_bh);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	dir->i_mtime = dir->i_ctime = current_time(dir);
64*4882a593Smuzhiyun 	inode_inc_iversion(dir);
65*4882a593Smuzhiyun 	mark_inode_dirty(dir);
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	return 0;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* Remove a header block from its directory.
71*4882a593Smuzhiyun  * caller must hold AFFS_DIR->i_hash_lock!
72*4882a593Smuzhiyun  */
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun int
affs_remove_hash(struct inode * dir,struct buffer_head * rem_bh)75*4882a593Smuzhiyun affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct super_block *sb;
78*4882a593Smuzhiyun 	struct buffer_head *bh;
79*4882a593Smuzhiyun 	u32 rem_ino, hash_ino;
80*4882a593Smuzhiyun 	__be32 ino;
81*4882a593Smuzhiyun 	int offset, retval;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	sb = dir->i_sb;
84*4882a593Smuzhiyun 	rem_ino = rem_bh->b_blocknr;
85*4882a593Smuzhiyun 	offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
86*4882a593Smuzhiyun 	pr_debug("%s(dir=%lu, ino=%d, hashval=%d)\n", __func__, dir->i_ino,
87*4882a593Smuzhiyun 		 rem_ino, offset);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	bh = affs_bread(sb, dir->i_ino);
90*4882a593Smuzhiyun 	if (!bh)
91*4882a593Smuzhiyun 		return -EIO;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	retval = -ENOENT;
94*4882a593Smuzhiyun 	hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
95*4882a593Smuzhiyun 	while (hash_ino) {
96*4882a593Smuzhiyun 		if (hash_ino == rem_ino) {
97*4882a593Smuzhiyun 			ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
98*4882a593Smuzhiyun 			if (dir->i_ino == bh->b_blocknr)
99*4882a593Smuzhiyun 				AFFS_HEAD(bh)->table[offset] = ino;
100*4882a593Smuzhiyun 			else
101*4882a593Smuzhiyun 				AFFS_TAIL(sb, bh)->hash_chain = ino;
102*4882a593Smuzhiyun 			affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
103*4882a593Smuzhiyun 			mark_buffer_dirty_inode(bh, dir);
104*4882a593Smuzhiyun 			AFFS_TAIL(sb, rem_bh)->parent = 0;
105*4882a593Smuzhiyun 			retval = 0;
106*4882a593Smuzhiyun 			break;
107*4882a593Smuzhiyun 		}
108*4882a593Smuzhiyun 		affs_brelse(bh);
109*4882a593Smuzhiyun 		bh = affs_bread(sb, hash_ino);
110*4882a593Smuzhiyun 		if (!bh)
111*4882a593Smuzhiyun 			return -EIO;
112*4882a593Smuzhiyun 		hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	affs_brelse(bh);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	dir->i_mtime = dir->i_ctime = current_time(dir);
118*4882a593Smuzhiyun 	inode_inc_iversion(dir);
119*4882a593Smuzhiyun 	mark_inode_dirty(dir);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return retval;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun static void
affs_fix_dcache(struct inode * inode,u32 entry_ino)125*4882a593Smuzhiyun affs_fix_dcache(struct inode *inode, u32 entry_ino)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct dentry *dentry;
128*4882a593Smuzhiyun 	spin_lock(&inode->i_lock);
129*4882a593Smuzhiyun 	hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
130*4882a593Smuzhiyun 		if (entry_ino == (u32)(long)dentry->d_fsdata) {
131*4882a593Smuzhiyun 			dentry->d_fsdata = (void *)inode->i_ino;
132*4882a593Smuzhiyun 			break;
133*4882a593Smuzhiyun 		}
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 	spin_unlock(&inode->i_lock);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /* Remove header from link chain */
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun static int
affs_remove_link(struct dentry * dentry)142*4882a593Smuzhiyun affs_remove_link(struct dentry *dentry)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	struct inode *dir, *inode = d_inode(dentry);
145*4882a593Smuzhiyun 	struct super_block *sb = inode->i_sb;
146*4882a593Smuzhiyun 	struct buffer_head *bh, *link_bh = NULL;
147*4882a593Smuzhiyun 	u32 link_ino, ino;
148*4882a593Smuzhiyun 	int retval;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	pr_debug("%s(key=%ld)\n", __func__, inode->i_ino);
151*4882a593Smuzhiyun 	retval = -EIO;
152*4882a593Smuzhiyun 	bh = affs_bread(sb, inode->i_ino);
153*4882a593Smuzhiyun 	if (!bh)
154*4882a593Smuzhiyun 		goto done;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	link_ino = (u32)(long)dentry->d_fsdata;
157*4882a593Smuzhiyun 	if (inode->i_ino == link_ino) {
158*4882a593Smuzhiyun 		/* we can't remove the head of the link, as its blocknr is still used as ino,
159*4882a593Smuzhiyun 		 * so we remove the block of the first link instead.
160*4882a593Smuzhiyun 		 */
161*4882a593Smuzhiyun 		link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
162*4882a593Smuzhiyun 		link_bh = affs_bread(sb, link_ino);
163*4882a593Smuzhiyun 		if (!link_bh)
164*4882a593Smuzhiyun 			goto done;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 		dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
167*4882a593Smuzhiyun 		if (IS_ERR(dir)) {
168*4882a593Smuzhiyun 			retval = PTR_ERR(dir);
169*4882a593Smuzhiyun 			goto done;
170*4882a593Smuzhiyun 		}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 		affs_lock_dir(dir);
173*4882a593Smuzhiyun 		/*
174*4882a593Smuzhiyun 		 * if there's a dentry for that block, make it
175*4882a593Smuzhiyun 		 * refer to inode itself.
176*4882a593Smuzhiyun 		 */
177*4882a593Smuzhiyun 		affs_fix_dcache(inode, link_ino);
178*4882a593Smuzhiyun 		retval = affs_remove_hash(dir, link_bh);
179*4882a593Smuzhiyun 		if (retval) {
180*4882a593Smuzhiyun 			affs_unlock_dir(dir);
181*4882a593Smuzhiyun 			goto done;
182*4882a593Smuzhiyun 		}
183*4882a593Smuzhiyun 		mark_buffer_dirty_inode(link_bh, inode);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 		memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
186*4882a593Smuzhiyun 		retval = affs_insert_hash(dir, bh);
187*4882a593Smuzhiyun 		if (retval) {
188*4882a593Smuzhiyun 			affs_unlock_dir(dir);
189*4882a593Smuzhiyun 			goto done;
190*4882a593Smuzhiyun 		}
191*4882a593Smuzhiyun 		mark_buffer_dirty_inode(bh, inode);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 		affs_unlock_dir(dir);
194*4882a593Smuzhiyun 		iput(dir);
195*4882a593Smuzhiyun 	} else {
196*4882a593Smuzhiyun 		link_bh = affs_bread(sb, link_ino);
197*4882a593Smuzhiyun 		if (!link_bh)
198*4882a593Smuzhiyun 			goto done;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) {
202*4882a593Smuzhiyun 		if (ino == link_ino) {
203*4882a593Smuzhiyun 			__be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
204*4882a593Smuzhiyun 			AFFS_TAIL(sb, bh)->link_chain = ino2;
205*4882a593Smuzhiyun 			affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
206*4882a593Smuzhiyun 			mark_buffer_dirty_inode(bh, inode);
207*4882a593Smuzhiyun 			retval = 0;
208*4882a593Smuzhiyun 			/* Fix the link count, if bh is a normal header block without links */
209*4882a593Smuzhiyun 			switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
210*4882a593Smuzhiyun 			case ST_LINKDIR:
211*4882a593Smuzhiyun 			case ST_LINKFILE:
212*4882a593Smuzhiyun 				break;
213*4882a593Smuzhiyun 			default:
214*4882a593Smuzhiyun 				if (!AFFS_TAIL(sb, bh)->link_chain)
215*4882a593Smuzhiyun 					set_nlink(inode, 1);
216*4882a593Smuzhiyun 			}
217*4882a593Smuzhiyun 			affs_free_block(sb, link_ino);
218*4882a593Smuzhiyun 			goto done;
219*4882a593Smuzhiyun 		}
220*4882a593Smuzhiyun 		affs_brelse(bh);
221*4882a593Smuzhiyun 		bh = affs_bread(sb, ino);
222*4882a593Smuzhiyun 		if (!bh)
223*4882a593Smuzhiyun 			goto done;
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 	retval = -ENOENT;
226*4882a593Smuzhiyun done:
227*4882a593Smuzhiyun 	affs_brelse(link_bh);
228*4882a593Smuzhiyun 	affs_brelse(bh);
229*4882a593Smuzhiyun 	return retval;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun static int
affs_empty_dir(struct inode * inode)234*4882a593Smuzhiyun affs_empty_dir(struct inode *inode)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	struct super_block *sb = inode->i_sb;
237*4882a593Smuzhiyun 	struct buffer_head *bh;
238*4882a593Smuzhiyun 	int retval, size;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	retval = -EIO;
241*4882a593Smuzhiyun 	bh = affs_bread(sb, inode->i_ino);
242*4882a593Smuzhiyun 	if (!bh)
243*4882a593Smuzhiyun 		goto done;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	retval = -ENOTEMPTY;
246*4882a593Smuzhiyun 	for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--)
247*4882a593Smuzhiyun 		if (AFFS_HEAD(bh)->table[size])
248*4882a593Smuzhiyun 			goto not_empty;
249*4882a593Smuzhiyun 	retval = 0;
250*4882a593Smuzhiyun not_empty:
251*4882a593Smuzhiyun 	affs_brelse(bh);
252*4882a593Smuzhiyun done:
253*4882a593Smuzhiyun 	return retval;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun /* Remove a filesystem object. If the object to be removed has
258*4882a593Smuzhiyun  * links to it, one of the links must be changed to inherit
259*4882a593Smuzhiyun  * the file or directory. As above, any inode will do.
260*4882a593Smuzhiyun  * The buffer will not be freed. If the header is a link, the
261*4882a593Smuzhiyun  * block will be marked as free.
262*4882a593Smuzhiyun  * This function returns a negative error number in case of
263*4882a593Smuzhiyun  * an error, else 0 if the inode is to be deleted or 1 if not.
264*4882a593Smuzhiyun  */
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun int
affs_remove_header(struct dentry * dentry)267*4882a593Smuzhiyun affs_remove_header(struct dentry *dentry)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	struct super_block *sb;
270*4882a593Smuzhiyun 	struct inode *inode, *dir;
271*4882a593Smuzhiyun 	struct buffer_head *bh = NULL;
272*4882a593Smuzhiyun 	int retval;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	dir = d_inode(dentry->d_parent);
275*4882a593Smuzhiyun 	sb = dir->i_sb;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	retval = -ENOENT;
278*4882a593Smuzhiyun 	inode = d_inode(dentry);
279*4882a593Smuzhiyun 	if (!inode)
280*4882a593Smuzhiyun 		goto done;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	pr_debug("%s(key=%ld)\n", __func__, inode->i_ino);
283*4882a593Smuzhiyun 	retval = -EIO;
284*4882a593Smuzhiyun 	bh = affs_bread(sb, (u32)(long)dentry->d_fsdata);
285*4882a593Smuzhiyun 	if (!bh)
286*4882a593Smuzhiyun 		goto done;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	affs_lock_link(inode);
289*4882a593Smuzhiyun 	affs_lock_dir(dir);
290*4882a593Smuzhiyun 	switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
291*4882a593Smuzhiyun 	case ST_USERDIR:
292*4882a593Smuzhiyun 		/* if we ever want to support links to dirs
293*4882a593Smuzhiyun 		 * i_hash_lock of the inode must only be
294*4882a593Smuzhiyun 		 * taken after some checks
295*4882a593Smuzhiyun 		 */
296*4882a593Smuzhiyun 		affs_lock_dir(inode);
297*4882a593Smuzhiyun 		retval = affs_empty_dir(inode);
298*4882a593Smuzhiyun 		affs_unlock_dir(inode);
299*4882a593Smuzhiyun 		if (retval)
300*4882a593Smuzhiyun 			goto done_unlock;
301*4882a593Smuzhiyun 		break;
302*4882a593Smuzhiyun 	default:
303*4882a593Smuzhiyun 		break;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	retval = affs_remove_hash(dir, bh);
307*4882a593Smuzhiyun 	if (retval)
308*4882a593Smuzhiyun 		goto done_unlock;
309*4882a593Smuzhiyun 	mark_buffer_dirty_inode(bh, inode);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	affs_unlock_dir(dir);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	if (inode->i_nlink > 1)
314*4882a593Smuzhiyun 		retval = affs_remove_link(dentry);
315*4882a593Smuzhiyun 	else
316*4882a593Smuzhiyun 		clear_nlink(inode);
317*4882a593Smuzhiyun 	affs_unlock_link(inode);
318*4882a593Smuzhiyun 	inode->i_ctime = current_time(inode);
319*4882a593Smuzhiyun 	mark_inode_dirty(inode);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun done:
322*4882a593Smuzhiyun 	affs_brelse(bh);
323*4882a593Smuzhiyun 	return retval;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun done_unlock:
326*4882a593Smuzhiyun 	affs_unlock_dir(dir);
327*4882a593Smuzhiyun 	affs_unlock_link(inode);
328*4882a593Smuzhiyun 	goto done;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun /* Checksum a block, do various consistency checks and optionally return
332*4882a593Smuzhiyun    the blocks type number.  DATA points to the block.  If their pointers
333*4882a593Smuzhiyun    are non-null, *PTYPE and *STYPE are set to the primary and secondary
334*4882a593Smuzhiyun    block types respectively, *HASHSIZE is set to the size of the hashtable
335*4882a593Smuzhiyun    (which lets us calculate the block size).
336*4882a593Smuzhiyun    Returns non-zero if the block is not consistent. */
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun u32
affs_checksum_block(struct super_block * sb,struct buffer_head * bh)339*4882a593Smuzhiyun affs_checksum_block(struct super_block *sb, struct buffer_head *bh)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	__be32 *ptr = (__be32 *)bh->b_data;
342*4882a593Smuzhiyun 	u32 sum;
343*4882a593Smuzhiyun 	int bsize;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	sum = 0;
346*4882a593Smuzhiyun 	for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--)
347*4882a593Smuzhiyun 		sum += be32_to_cpu(*ptr++);
348*4882a593Smuzhiyun 	return sum;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun /*
352*4882a593Smuzhiyun  * Calculate the checksum of a disk block and store it
353*4882a593Smuzhiyun  * at the indicated position.
354*4882a593Smuzhiyun  */
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun void
affs_fix_checksum(struct super_block * sb,struct buffer_head * bh)357*4882a593Smuzhiyun affs_fix_checksum(struct super_block *sb, struct buffer_head *bh)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	int cnt = sb->s_blocksize / sizeof(__be32);
360*4882a593Smuzhiyun 	__be32 *ptr = (__be32 *)bh->b_data;
361*4882a593Smuzhiyun 	u32 checksum;
362*4882a593Smuzhiyun 	__be32 *checksumptr;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	checksumptr = ptr + 5;
365*4882a593Smuzhiyun 	*checksumptr = 0;
366*4882a593Smuzhiyun 	for (checksum = 0; cnt > 0; ptr++, cnt--)
367*4882a593Smuzhiyun 		checksum += be32_to_cpu(*ptr);
368*4882a593Smuzhiyun 	*checksumptr = cpu_to_be32(-checksum);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun void
affs_secs_to_datestamp(time64_t secs,struct affs_date * ds)372*4882a593Smuzhiyun affs_secs_to_datestamp(time64_t secs, struct affs_date *ds)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	u32	 days;
375*4882a593Smuzhiyun 	u32	 minute;
376*4882a593Smuzhiyun 	s32	 rem;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	secs -= sys_tz.tz_minuteswest * 60 + AFFS_EPOCH_DELTA;
379*4882a593Smuzhiyun 	if (secs < 0)
380*4882a593Smuzhiyun 		secs = 0;
381*4882a593Smuzhiyun 	days    = div_s64_rem(secs, 86400, &rem);
382*4882a593Smuzhiyun 	minute  = rem / 60;
383*4882a593Smuzhiyun 	rem    -= minute * 60;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	ds->days = cpu_to_be32(days);
386*4882a593Smuzhiyun 	ds->mins = cpu_to_be32(minute);
387*4882a593Smuzhiyun 	ds->ticks = cpu_to_be32(rem * 50);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun umode_t
affs_prot_to_mode(u32 prot)391*4882a593Smuzhiyun affs_prot_to_mode(u32 prot)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	umode_t mode = 0;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (!(prot & FIBF_NOWRITE))
396*4882a593Smuzhiyun 		mode |= 0200;
397*4882a593Smuzhiyun 	if (!(prot & FIBF_NOREAD))
398*4882a593Smuzhiyun 		mode |= 0400;
399*4882a593Smuzhiyun 	if (!(prot & FIBF_NOEXECUTE))
400*4882a593Smuzhiyun 		mode |= 0100;
401*4882a593Smuzhiyun 	if (prot & FIBF_GRP_WRITE)
402*4882a593Smuzhiyun 		mode |= 0020;
403*4882a593Smuzhiyun 	if (prot & FIBF_GRP_READ)
404*4882a593Smuzhiyun 		mode |= 0040;
405*4882a593Smuzhiyun 	if (prot & FIBF_GRP_EXECUTE)
406*4882a593Smuzhiyun 		mode |= 0010;
407*4882a593Smuzhiyun 	if (prot & FIBF_OTR_WRITE)
408*4882a593Smuzhiyun 		mode |= 0002;
409*4882a593Smuzhiyun 	if (prot & FIBF_OTR_READ)
410*4882a593Smuzhiyun 		mode |= 0004;
411*4882a593Smuzhiyun 	if (prot & FIBF_OTR_EXECUTE)
412*4882a593Smuzhiyun 		mode |= 0001;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	return mode;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun void
affs_mode_to_prot(struct inode * inode)418*4882a593Smuzhiyun affs_mode_to_prot(struct inode *inode)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	u32 prot = AFFS_I(inode)->i_protect;
421*4882a593Smuzhiyun 	umode_t mode = inode->i_mode;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	/*
424*4882a593Smuzhiyun 	 * First, clear all RWED bits for owner, group, other.
425*4882a593Smuzhiyun 	 * Then, recalculate them afresh.
426*4882a593Smuzhiyun 	 *
427*4882a593Smuzhiyun 	 * We'll always clear the delete-inhibit bit for the owner, as that is
428*4882a593Smuzhiyun 	 * the classic single-user mode AmigaOS protection bit and we need to
429*4882a593Smuzhiyun 	 * stay compatible with all scenarios.
430*4882a593Smuzhiyun 	 *
431*4882a593Smuzhiyun 	 * Since multi-user AmigaOS is an extension, we'll only set the
432*4882a593Smuzhiyun 	 * delete-allow bit if any of the other bits in the same user class
433*4882a593Smuzhiyun 	 * (group/other) are used.
434*4882a593Smuzhiyun 	 */
435*4882a593Smuzhiyun 	prot &= ~(FIBF_NOEXECUTE | FIBF_NOREAD
436*4882a593Smuzhiyun 		  | FIBF_NOWRITE | FIBF_NODELETE
437*4882a593Smuzhiyun 		  | FIBF_GRP_EXECUTE | FIBF_GRP_READ
438*4882a593Smuzhiyun 		  | FIBF_GRP_WRITE   | FIBF_GRP_DELETE
439*4882a593Smuzhiyun 		  | FIBF_OTR_EXECUTE | FIBF_OTR_READ
440*4882a593Smuzhiyun 		  | FIBF_OTR_WRITE   | FIBF_OTR_DELETE);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	/* Classic single-user AmigaOS flags. These are inverted. */
443*4882a593Smuzhiyun 	if (!(mode & 0100))
444*4882a593Smuzhiyun 		prot |= FIBF_NOEXECUTE;
445*4882a593Smuzhiyun 	if (!(mode & 0400))
446*4882a593Smuzhiyun 		prot |= FIBF_NOREAD;
447*4882a593Smuzhiyun 	if (!(mode & 0200))
448*4882a593Smuzhiyun 		prot |= FIBF_NOWRITE;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	/* Multi-user extended flags. Not inverted. */
451*4882a593Smuzhiyun 	if (mode & 0010)
452*4882a593Smuzhiyun 		prot |= FIBF_GRP_EXECUTE;
453*4882a593Smuzhiyun 	if (mode & 0040)
454*4882a593Smuzhiyun 		prot |= FIBF_GRP_READ;
455*4882a593Smuzhiyun 	if (mode & 0020)
456*4882a593Smuzhiyun 		prot |= FIBF_GRP_WRITE;
457*4882a593Smuzhiyun 	if (mode & 0070)
458*4882a593Smuzhiyun 		prot |= FIBF_GRP_DELETE;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	if (mode & 0001)
461*4882a593Smuzhiyun 		prot |= FIBF_OTR_EXECUTE;
462*4882a593Smuzhiyun 	if (mode & 0004)
463*4882a593Smuzhiyun 		prot |= FIBF_OTR_READ;
464*4882a593Smuzhiyun 	if (mode & 0002)
465*4882a593Smuzhiyun 		prot |= FIBF_OTR_WRITE;
466*4882a593Smuzhiyun 	if (mode & 0007)
467*4882a593Smuzhiyun 		prot |= FIBF_OTR_DELETE;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	AFFS_I(inode)->i_protect = prot;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun void
affs_error(struct super_block * sb,const char * function,const char * fmt,...)473*4882a593Smuzhiyun affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct va_format vaf;
476*4882a593Smuzhiyun 	va_list args;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	va_start(args, fmt);
479*4882a593Smuzhiyun 	vaf.fmt = fmt;
480*4882a593Smuzhiyun 	vaf.va = &args;
481*4882a593Smuzhiyun 	pr_crit("error (device %s): %s(): %pV\n", sb->s_id, function, &vaf);
482*4882a593Smuzhiyun 	if (!sb_rdonly(sb))
483*4882a593Smuzhiyun 		pr_warn("Remounting filesystem read-only\n");
484*4882a593Smuzhiyun 	sb->s_flags |= SB_RDONLY;
485*4882a593Smuzhiyun 	va_end(args);
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun void
affs_warning(struct super_block * sb,const char * function,const char * fmt,...)489*4882a593Smuzhiyun affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	struct va_format vaf;
492*4882a593Smuzhiyun 	va_list args;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	va_start(args, fmt);
495*4882a593Smuzhiyun 	vaf.fmt = fmt;
496*4882a593Smuzhiyun 	vaf.va = &args;
497*4882a593Smuzhiyun 	pr_warn("(device %s): %s(): %pV\n", sb->s_id, function, &vaf);
498*4882a593Smuzhiyun 	va_end(args);
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun bool
affs_nofilenametruncate(const struct dentry * dentry)502*4882a593Smuzhiyun affs_nofilenametruncate(const struct dentry *dentry)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun 	return affs_test_opt(AFFS_SB(dentry->d_sb)->s_flags, SF_NO_TRUNCATE);
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun /* Check if the name is valid for a affs object. */
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun int
affs_check_name(const unsigned char * name,int len,bool notruncate)510*4882a593Smuzhiyun affs_check_name(const unsigned char *name, int len, bool notruncate)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	int	 i;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (len > AFFSNAMEMAX) {
515*4882a593Smuzhiyun 		if (notruncate)
516*4882a593Smuzhiyun 			return -ENAMETOOLONG;
517*4882a593Smuzhiyun 		len = AFFSNAMEMAX;
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
520*4882a593Smuzhiyun 		if (name[i] < ' ' || name[i] == ':'
521*4882a593Smuzhiyun 		    || (name[i] > 0x7e && name[i] < 0xa0))
522*4882a593Smuzhiyun 			return -EINVAL;
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	return 0;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun /* This function copies name to bstr, with at most 30
529*4882a593Smuzhiyun  * characters length. The bstr will be prepended by
530*4882a593Smuzhiyun  * a length byte.
531*4882a593Smuzhiyun  * NOTE: The name will must be already checked by
532*4882a593Smuzhiyun  *       affs_check_name()!
533*4882a593Smuzhiyun  */
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun int
affs_copy_name(unsigned char * bstr,struct dentry * dentry)536*4882a593Smuzhiyun affs_copy_name(unsigned char *bstr, struct dentry *dentry)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun 	u32 len = min(dentry->d_name.len, AFFSNAMEMAX);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	*bstr++ = len;
541*4882a593Smuzhiyun 	memcpy(bstr, dentry->d_name.name, len);
542*4882a593Smuzhiyun 	return len;
543*4882a593Smuzhiyun }
544