Skip to contentSkip to conversation

Add AFFS NLS support

PATCH New Vladimir 'φ-coder/phcoder' Serbinenko 1 participant 1 message May 13, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Add AFFS NLS support

AFFS almost always uses latin1. However usual iocharset by now is UTF-8. So NLS support is required.

fs/affs/Kconfig +8 -0
index cfad9af..93ab9d4b 100644
@@ -19,3 +19,11 @@ config AFFS_FS
 
 	  To compile this file system support as a module, choose M here: the
 	  module will be called affs.  If unsure, say N.
+
+config AFFS_DEFAULT_CODEPAGE
+	string "Default codepage for AFFS"
+	depends on AFFS_FS
+	default "iso8859-1"
+	help
+	  This option should be set to the codepage of your AFFS filesystems.
+	  It can be overridden with the "codepage" mount option.
fs/affs/affs.h +14 -2
index fc1d4ca..7bf696d 100644
@@ -12,6 +12,8 @@
  */
 /*#define AFFS_NO_TRUNCATE */
 
+#define AFFS_MAXNAME 30
+
 /* Ugly macros make the code more pretty. */
 
 #define GET_END_PTR(st,p,sz)		 ((st *)((char *)(p)+((sz)-sizeof(st))))
@@ -107,6 +109,10 @@ struct affs_sb_info {
 	u32 s_bmap_bits;		/* # of bits in one bitmap blocks */
 	u32 s_last_bmap;
 	struct buffer_head *s_bmap_bh;
+	char *iocharset;
+	char *codepage;
+	struct nls_table *nls_io;
+	struct nls_table *nls_disk;
 	char *s_prefix;			/* Prefix for volumes and assigns. */
 	char s_volume[32];		/* Volume prefix for absolute symlinks. */
 	spinlock_t symlink_lock;	/* protects the previous two */
@@ -142,8 +148,9 @@ extern umode_t	prot_to_mode(u32 prot);
 extern void	mode_to_prot(struct inode *inode);
 extern void	affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
 extern void	affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
-extern int	affs_check_name(const unsigned char *name, int len);
-extern int	affs_copy_name(unsigned char *bstr, struct dentry *dentry);
+extern int	affs_check_name(const unsigned char *name, unsigned int len);
+extern int	affs_copy_name(struct super_block *sb, unsigned char *bstr,
+			       struct dentry *dentry);
 
 /* bitmap. c */
 
@@ -165,8 +172,13 @@ extern int	affs_link(struct dentry *olddentry, struct inode *dir,
 			  struct dentry *dentry);
 extern int	affs_symlink(struct inode *dir, struct dentry *dentry,
 			     const char *symname);
+extern int      affs_read_symlink(struct inode *inode,
+				  char *link);
 extern int	affs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			    struct inode *new_dir, struct dentry *new_dentry);
+extern size_t   affs_translate(u8 *to, const u8 *from, struct nls_table *nls_to,
+			       struct nls_table *nls_from, size_t limit,
+			       size_t from_len);
 
 /* inode.c */
 
fs/affs/amigaffs.c +3 -19
index 52a6407..08f39ee 100644
@@ -477,15 +477,15 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
 /* Check if the name is valid for a affs object. */
 
 int
-affs_check_name(const unsigned char *name, int len)
+affs_check_name(const unsigned char *name, unsigned int len)
 {
 	int	 i;
 
-	if (len > 30)
+	if (len > AFFS_MAXNAME)
 #ifdef AFFS_NO_TRUNCATE
 		return -ENAMETOOLONG;
 #else
-		len = 30;
+		len = AFFS_MAXNAME;
 #endif
 
 	for (i = 0; i < len; i++) {
@@ -497,19 +497,3 @@ affs_check_name(const unsigned char *name, int len)
 	return 0;
 }
 
-/* This function copies name to bstr, with at most 30
- * characters length. The bstr will be prepended by
- * a length byte.
- * NOTE: The name will must be already checked by
- *       affs_check_name()!
- */
-
-int
-affs_copy_name(unsigned char *bstr, struct dentry *dentry)
-{
-	int len = min(dentry->d_name.len, 30u);
-
-	*bstr++ = len;
-	memcpy(bstr, dentry->d_name.name, len);
-	return len;
-}
fs/affs/dir.c +18 -2
index 8ca8f3a..81da2ec 100644
@@ -55,6 +55,8 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 	u32			 ino;
 	int			 stored;
 	int			 res;
+	struct nls_table *nls_io = AFFS_SB(sb)->nls_io;
+	struct nls_table *nls_disk = AFFS_SB(sb)->nls_disk;
 
 	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
 
@@ -122,17 +124,31 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 		f_pos = (hash_pos << 16) + 2;
 inside:
 		do {
+			/* AFFS names are at most 30 characters and are all in
+			   BMP. So at most 90 characters resulting translation
+			   assuming UTF-8 as iocharset. Then comes paranoia.
+			   In worst-case scenario filenames get truncated but
+			   no overflow occurs.
+			*/
+			char buf[200];
+			size_t translatedlen;
 			fh_bh = affs_bread(sb, ino);
 			if (!fh_bh) {
 				affs_error(sb, "readdir","Cannot read block %d", ino);
 				goto readdir_done;
 			}
 
-			namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
+			namelen = min(((u8 *)AFFS_TAIL(sb, fh_bh)->name)[0],
+				      (u8)AFFS_MAXNAME);
 			name = AFFS_TAIL(sb, fh_bh)->name + 1;
+			translatedlen = affs_translate(buf, name,
+						       nls_io, nls_disk,
+						       sizeof(buf),
+						       namelen);
 			pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
 				 namelen, name, ino, hash_pos, f_pos);
-			if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
+			if (filldir(dirent, buf, translatedlen, f_pos, ino,
+				    DT_UNKNOWN) < 0)
 				goto readdir_done;
 			stored++;
 			f_pos++;
fs/affs/inode.c +7 -1
index 88a4b0b..2a88f7a 100644
@@ -143,11 +143,17 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
 		inode->i_fop = &affs_file_operations;
 		break;
 	case ST_SOFTLINK:
+	{
+		int s;
 		inode->i_mode |= S_IFLNK;
 		inode->i_op = &affs_symlink_inode_operations;
 		inode->i_data.a_ops = &affs_symlink_aops;
+		s = affs_read_symlink(inode, 0);
+
+		inode->i_size = s >= 0 ? s : 0;
 		break;
 	}
+	}
 
 	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec
 		       = (be32_to_cpu(tail->change.days) * (24 * 60 * 60) +
@@ -375,7 +381,7 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
 
 	AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
 	AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
-	affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
+	affs_copy_name(sb, AFFS_TAIL(sb, bh)->name, dentry);
 	AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
 	AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
 
fs/affs/namei.c +171 -34

326 lines not on this page · raw message

fs/affs/super.c +100 -8

189 lines not on this page · raw message

fs/affs/symlink.c +82 -17

135 lines not on this page · raw message