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