2 * linux/fs/affs/amigaffs.c
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
6 * (C) 1993 Ray Burr - Amiga FFS filesystem.
8 * Please send bug reports to: hjw@zvw.de
13 #include <linux/stat.h>
14 #include <linux/sched.h>
15 #include <linux/affs_fs.h>
16 #include <linux/string.h>
17 #include <linux/locks.h>
19 #include <linux/amigaffs.h>
21 extern struct timezone sys_tz;
23 static char ErrorBuffer[256];
26 * Functions for accessing Amiga-FFS structures.
29 /* Set *NAME to point to the file name in a file header block in memory
30 pointed to by FH_DATA. The length of the name is returned. */
33 affs_get_file_name(int bsize, void *fh_data, unsigned char **name)
35 struct file_end *file_end;
37 file_end = GET_END_PTR(struct file_end, fh_data, bsize);
38 if (file_end->file_name[0] == 0
39 || file_end->file_name[0] > 30) {
40 printk(KERN_WARNING "AFFS: bad filename (length=%d chars)\n",
41 file_end->file_name[0]);
42 *name = "***BAD_FILE***";
45 *name = (unsigned char *)&file_end->file_name[1];
46 return file_end->file_name[0];
49 /* Insert a header block (file) into the directory (next).
50 * This routine assumes that the caller has the superblock locked.
54 affs_insert_hash(unsigned long next, struct buffer_head *file, struct inode *inode)
56 struct buffer_head *bh;
60 offset = affs_hash_name(FILE_END(file->b_data,inode)->file_name+1,
61 FILE_END(file->b_data,inode)->file_name[0],
62 AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
63 ino = be32_to_cpu(((struct dir_front *)file->b_data)->own_key);
65 pr_debug("AFFS: insert_hash(dir_ino=%lu,ino=%d)\n",next,ino);
67 FILE_END(file->b_data,inode)->parent = cpu_to_be32(next);
70 if (!(bh = affs_bread(inode->i_dev,next,AFFS_I2BSIZE(inode))))
72 next = be32_to_cpu(((s32 *)bh->b_data)[offset]);
73 if (!next || next > ino)
75 offset = AFFS_I2BSIZE(inode) / 4 - 4;
79 DIR_END(file->b_data,inode)->hash_chain = cpu_to_be32(next);
80 ((s32 *)bh->b_data)[offset] = cpu_to_be32(ino);
81 affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
82 mark_buffer_dirty(bh);
87 /* Remove a header block from its hash table (directory).
88 * 'inode' may be any inode on the partition, it's only
89 * used for calculating the block size and superblock
94 affs_remove_hash(struct buffer_head *dbh, struct inode *inode)
102 struct buffer_head *bh;
104 ownkey = be32_to_cpu(((struct dir_front *)dbh->b_data)->own_key);
105 key = be32_to_cpu(FILE_END(dbh->b_data,inode)->parent);
106 offset = affs_hash_name(FILE_END(dbh->b_data,inode)->file_name+1,
107 FILE_END(dbh->b_data,inode)->file_name[0],
108 AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6;
109 pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n",key,ownkey,offset-6);
112 lock_super(inode->i_sb);
114 if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
118 if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)
119 || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
120 stype != ST_LINKFILE && stype != ST_LINKDIR &&
121 stype != ST_ROOT && stype != ST_SOFTLINK)) {
122 affs_error(inode->i_sb,"affs_remove_hash",
123 "Bad block in hash chain (key=%d, ptype=%d, stype=%d, ownkey=%d)",
124 key,ptype,stype,ownkey);
129 key = be32_to_cpu(((s32 *)bh->b_data)[offset]);
131 ((s32 *)bh->b_data)[offset] = FILE_END(dbh->b_data,inode)->hash_chain;
132 affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
133 mark_buffer_dirty(bh);
139 offset = AFFS_I2BSIZE(inode) / 4 - 4;
141 unlock_super(inode->i_sb);
146 /* Remove header from link chain */
149 affs_remove_link(struct buffer_head *dbh, struct inode *inode)
156 struct buffer_head *bh;
158 ownkey = be32_to_cpu((DIR_FRONT(dbh)->own_key));
159 key = be32_to_cpu(FILE_END(dbh->b_data,inode)->original);
162 pr_debug("AFFS: remove_link(link=%d, original=%d)\n",ownkey,key);
164 lock_super(inode->i_sb);
166 if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
170 if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)) {
171 affs_error(inode->i_sb,"affs_remove_link","Checksum error (block %d)",key);
176 key = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
178 FILE_END(bh->b_data,inode)->link_chain =
179 FILE_END(dbh->b_data,inode)->link_chain;
180 affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
181 mark_buffer_dirty(bh);
188 unlock_super(inode->i_sb);
193 /* Remove a filesystem object. If the object to be removed has
194 * links to it, one of the links must be changed to inherit
195 * the file or directory. As above, any inode will do.
196 * The buffer will not be freed. If the header is a link, the
197 * block will be marked as free.
198 * This function returns a negative error number in case of
199 * an error, else 0 if the inode is to be deleted or 1 if not.
203 affs_remove_header(struct buffer_head *bh, struct inode *inode)
205 struct buffer_head *link_bh;
207 unsigned long link_ino;
208 unsigned long orig_ino;
209 unsigned int dir_ino;
212 pr_debug("AFFS: remove_header(key=%ld)\n",be32_to_cpu(DIR_FRONT(bh)->own_key));
214 /* Mark directory as changed. We do this before anything else,
215 * as it must be done anyway and doesn't hurt even if an
216 * error occurs later.
218 dir = iget(inode->i_sb,be32_to_cpu(FILE_END(bh->b_data,inode)->parent));
221 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
223 mark_inode_dirty(dir);
226 orig_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->original);
227 if (orig_ino) { /* This is just a link. Nothing much to do. */
228 pr_debug("AFFS: Removing link.\n");
229 if ((error = affs_remove_link(bh,inode)))
231 if ((error = affs_remove_hash(bh,inode)))
233 affs_free_block(inode->i_sb,be32_to_cpu(DIR_FRONT(bh)->own_key));
237 link_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain);
238 if (link_ino) { /* This is the complicated case. Yuck. */
239 pr_debug("AFFS: Removing original with links to it.\n");
240 /* Unlink the object and its first link from their directories. */
241 if ((error = affs_remove_hash(bh,inode)))
243 if (!(link_bh = affs_bread(inode->i_dev,link_ino,AFFS_I2BSIZE(inode))))
245 if ((error = affs_remove_hash(link_bh,inode))) {
246 affs_brelse(link_bh);
249 /* Fix link chain. */
250 if ((error = affs_remove_link(link_bh,inode))) {
251 affs_brelse(link_bh);
254 /* Rename link to object. */
255 memcpy(FILE_END(bh->b_data,inode)->file_name,
256 FILE_END(link_bh->b_data,inode)->file_name,32);
257 /* Insert object into dir the link was in. */
258 dir_ino = be32_to_cpu(FILE_END(link_bh->b_data,inode)->parent);
259 if ((error = affs_insert_hash(dir_ino,bh,inode))) {
260 affs_brelse(link_bh);
263 affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
264 mark_buffer_dirty(bh);
265 affs_brelse(link_bh);
266 affs_free_block(inode->i_sb,link_ino);
267 /* Mark the link's parent dir as changed, too. */
268 if (!(dir = iget(inode->i_sb,dir_ino)))
270 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
272 mark_inode_dirty(dir);
276 /* Plain file/dir. This is the simplest case. */
277 pr_debug("AFFS: Removing plain file/dir.\n");
278 if ((error = affs_remove_hash(bh,inode)))
284 /* Checksum a block, do various consistency checks and optionally return
285 the blocks type number. DATA points to the block. If their pointers
286 are non-null, *PTYPE and *STYPE are set to the primary and secondary
287 block types respectively, *HASHSIZE is set to the size of the hashtable
288 (which lets us calculate the block size).
289 Returns non-zero if the block is not consistent. */
292 affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype)
299 *ptype = be32_to_cpu(((s32 *)data)[0]);
301 *stype = be32_to_cpu(((s32 *)data)[bsize - 1]);
306 sum += be32_to_cpu(*p++);
311 * Calculate the checksum of a disk block and store it
312 * at the indicated position.
316 affs_fix_checksum(int bsize, void *data, int cspos)
321 cs = affs_checksum_block(bsize,data,NULL,NULL);
322 ocs = be32_to_cpu(((u32 *)data)[cspos]);
324 ((u32 *)data)[cspos] = be32_to_cpu(ocs);
328 secs_to_datestamp(time_t secs, struct DateStamp *ds)
333 secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60);
337 secs -= days * 86400;
341 ds->ds_Days = be32_to_cpu(days);
342 ds->ds_Minute = be32_to_cpu(minute);
343 ds->ds_Tick = be32_to_cpu(secs * 50);
347 prot_to_mode(u32 prot)
351 if (AFFS_UMAYWRITE(prot))
353 if (AFFS_UMAYREAD(prot))
355 if (AFFS_UMAYEXECUTE(prot))
357 if (AFFS_GMAYWRITE(prot))
359 if (AFFS_GMAYREAD(prot))
361 if (AFFS_GMAYEXECUTE(prot))
363 if (AFFS_OMAYWRITE(prot))
365 if (AFFS_OMAYREAD(prot))
367 if (AFFS_OMAYEXECUTE(prot))
374 mode_to_prot(int mode)
383 prot |= FIBF_WRITE | FIBF_DELETE;
385 prot |= FIBF_GRP_READ;
387 prot |= FIBF_GRP_WRITE;
389 prot |= FIBF_OTR_READ;
391 prot |= FIBF_OTR_WRITE;
397 affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
402 vsprintf(ErrorBuffer,fmt,args);
405 printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev),
406 function,ErrorBuffer);
407 if (!(sb->s_flags & MS_RDONLY))
408 printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
409 sb->s_flags |= MS_RDONLY;
410 sb->u.affs_sb.s_flags |= SF_READONLY; /* Don't allow to remount rw */
414 affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
419 vsprintf(ErrorBuffer,fmt,args);
422 printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n",kdevname(sb->s_dev),
423 function,ErrorBuffer);
426 /* Check if the name is valid for a affs object. */
429 affs_check_name(const unsigned char *name, int len)
434 #ifdef AFFS_NO_TRUNCATE
435 return -ENAMETOOLONG;
440 for (i = 0; i < len; i++) {
441 if (name[i] < ' ' || name[i] == ':'
442 || (name[i] > 0x7e && name[i] < 0xa0))
449 /* This function copies name to bstr, with at most 30
450 * characters length. The bstr will be prepended by
452 * NOTE: The name will must be already checked by
457 affs_copy_name(unsigned char *bstr, const unsigned char *name)
461 for (len = 0; len < 30; len++) {
462 bstr[len + 1] = name[len];
463 if (name[len] == '\0')