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