Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *  linux/fs/affs/namei.c
  4 *
  5 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  6 *
  7 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  8 *
  9 *  (C) 1991  Linus Torvalds - minix filesystem
 10 */
 11
 12#include "affs.h"
 13#include <linux/exportfs.h>
 14
 15typedef int (*toupper_t)(int);
 16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 17/* Simple toupper() for DOS\1 */
 18
 19static int
 20affs_toupper(int ch)
 21{
 22	return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
 23}
 24
 25/* International toupper() for DOS\3 ("international") */
 26
 27static int
 28affs_intl_toupper(int ch)
 29{
 30	return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
 31		&& ch <= 0xFE && ch != 0xF7) ?
 32		ch - ('a' - 'A') : ch;
 33}
 34
 35static inline toupper_t
 36affs_get_toupper(struct super_block *sb)
 37{
 38	return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ?
 39	       affs_intl_toupper : affs_toupper;
 40}
 41
 42/*
 43 * Note: the dentry argument is the parent dentry.
 44 */
 45static inline int
 46__affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
 47{
 48	const u8 *name = qstr->name;
 49	unsigned long hash;
 50	int retval;
 51	u32 len;
 52
 53	retval = affs_check_name(qstr->name, qstr->len, notruncate);
 54	if (retval)
 55		return retval;
 56
 57	hash = init_name_hash(dentry);
 58	len = min(qstr->len, AFFSNAMEMAX);
 59	for (; len > 0; name++, len--)
 
 
 
 
 60		hash = partial_name_hash(toupper(*name), hash);
 61	qstr->hash = end_name_hash(hash);
 62
 63	return 0;
 64}
 65
 66static int
 67affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 
 68{
 69	return __affs_hash_dentry(dentry, qstr, affs_toupper,
 70				  affs_nofilenametruncate(dentry));
 71
 72}
 73
 74static int
 75affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 
 76{
 77	return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
 78				  affs_nofilenametruncate(dentry));
 79
 80}
 81
 82static inline int __affs_compare_dentry(unsigned int len,
 83		const char *str, const struct qstr *name, toupper_t toupper,
 84		bool notruncate)
 85{
 86	const u8 *aname = str;
 87	const u8 *bname = name->name;
 88
 89	/*
 90	 * 'str' is the name of an already existing dentry, so the name
 91	 * must be valid. 'name' must be validated first.
 92	 */
 93
 94	if (affs_check_name(name->name, name->len, notruncate))
 95		return 1;
 96
 97	/*
 98	 * If the names are longer than the allowed 30 chars,
 99	 * the excess is ignored, so their length may differ.
100	 */
101	if (len >= AFFSNAMEMAX) {
102		if (name->len < AFFSNAMEMAX)
103			return 1;
104		len = AFFSNAMEMAX;
105	} else if (len != name->len)
106		return 1;
107
108	for (; len > 0; len--)
109		if (toupper(*aname++) != toupper(*bname++))
110			return 1;
111
112	return 0;
113}
114
115static int
116affs_compare_dentry(const struct dentry *dentry,
 
117		unsigned int len, const char *str, const struct qstr *name)
118{
119
120	return __affs_compare_dentry(len, str, name, affs_toupper,
121				     affs_nofilenametruncate(dentry));
122}
123
124static int
125affs_intl_compare_dentry(const struct dentry *dentry,
 
126		unsigned int len, const char *str, const struct qstr *name)
127{
128	return __affs_compare_dentry(len, str, name, affs_intl_toupper,
129				     affs_nofilenametruncate(dentry));
130
131}
132
133/*
134 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
135 */
136
137static inline int
138affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
139{
140	const u8 *name = dentry->d_name.name;
141	int len = dentry->d_name.len;
142
143	if (len >= AFFSNAMEMAX) {
144		if (*name2 < AFFSNAMEMAX)
145			return 0;
146		len = AFFSNAMEMAX;
147	} else if (len != *name2)
148		return 0;
149
150	for (name2++; len > 0; len--)
151		if (toupper(*name++) != toupper(*name2++))
152			return 0;
153	return 1;
154}
155
156int
157affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
158{
159	toupper_t toupper = affs_get_toupper(sb);
160	u32 hash;
161
162	hash = len = min(len, AFFSNAMEMAX);
163	for (; len > 0; len--)
164		hash = (hash * 13 + toupper(*name++)) & 0x7ff;
165
166	return hash % AFFS_SB(sb)->s_hashsize;
167}
168
169static struct buffer_head *
170affs_find_entry(struct inode *dir, struct dentry *dentry)
171{
172	struct super_block *sb = dir->i_sb;
173	struct buffer_head *bh;
174	toupper_t toupper = affs_get_toupper(sb);
175	u32 key;
176
177	pr_debug("%s(\"%pd\")\n", __func__, dentry);
178
179	bh = affs_bread(sb, dir->i_ino);
180	if (!bh)
181		return ERR_PTR(-EIO);
182
183	key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
184
185	for (;;) {
186		affs_brelse(bh);
187		if (key == 0)
188			return NULL;
189		bh = affs_bread(sb, key);
190		if (!bh)
191			return ERR_PTR(-EIO);
192		if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
193			return bh;
194		key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
195	}
196}
197
198struct dentry *
199affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
200{
201	struct super_block *sb = dir->i_sb;
202	struct buffer_head *bh;
203	struct inode *inode = NULL;
204	struct dentry *res;
205
206	pr_debug("%s(\"%pd\")\n", __func__, dentry);
207
208	affs_lock_dir(dir);
209	bh = affs_find_entry(dir, dentry);
210	if (IS_ERR(bh)) {
211		affs_unlock_dir(dir);
212		return ERR_CAST(bh);
213	}
214	if (bh) {
215		u32 ino = bh->b_blocknr;
216
217		/* store the real header ino in d_fsdata for faster lookups */
218		dentry->d_fsdata = (void *)(long)ino;
219		switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
220		//link to dirs disabled
221		//case ST_LINKDIR:
222		case ST_LINKFILE:
223			ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
224		}
225		affs_brelse(bh);
226		inode = affs_iget(sb, ino);
 
 
227	}
228	res = d_splice_alias(inode, dentry);
229	if (!IS_ERR_OR_NULL(res))
230		res->d_fsdata = dentry->d_fsdata;
231	affs_unlock_dir(dir);
232	return res;
233}
234
235int
236affs_unlink(struct inode *dir, struct dentry *dentry)
237{
238	pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
239		 d_inode(dentry)->i_ino, dentry);
 
240
241	return affs_remove_header(dentry);
242}
243
244int
245affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
246{
247	struct super_block *sb = dir->i_sb;
248	struct inode	*inode;
249	int		 error;
250
251	pr_debug("%s(%lu,\"%pd\",0%ho)\n",
252		 __func__, dir->i_ino, dentry, mode);
253
254	inode = affs_new_inode(dir);
255	if (!inode)
256		return -ENOSPC;
257
258	inode->i_mode = mode;
259	affs_mode_to_prot(inode);
260	mark_inode_dirty(inode);
261
262	inode->i_op = &affs_file_inode_operations;
263	inode->i_fop = &affs_file_operations;
264	inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ?
265				  &affs_aops_ofs : &affs_aops;
266	error = affs_add_entry(dir, inode, dentry, ST_FILE);
267	if (error) {
268		clear_nlink(inode);
269		iput(inode);
270		return error;
271	}
272	return 0;
273}
274
275int
276affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
277{
278	struct inode		*inode;
279	int			 error;
280
281	pr_debug("%s(%lu,\"%pd\",0%ho)\n",
282		 __func__, dir->i_ino, dentry, mode);
283
284	inode = affs_new_inode(dir);
285	if (!inode)
286		return -ENOSPC;
287
288	inode->i_mode = S_IFDIR | mode;
289	affs_mode_to_prot(inode);
290
291	inode->i_op = &affs_dir_inode_operations;
292	inode->i_fop = &affs_dir_operations;
293
294	error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
295	if (error) {
296		clear_nlink(inode);
297		mark_inode_dirty(inode);
298		iput(inode);
299		return error;
300	}
301	return 0;
302}
303
304int
305affs_rmdir(struct inode *dir, struct dentry *dentry)
306{
307	pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
308		 d_inode(dentry)->i_ino, dentry);
 
309
310	return affs_remove_header(dentry);
311}
312
313int
314affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
315{
316	struct super_block	*sb = dir->i_sb;
317	struct buffer_head	*bh;
318	struct inode		*inode;
319	char			*p;
320	int			 i, maxlen, error;
321	char			 c, lc;
322
323	pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
324		 __func__, dir->i_ino, dentry, symname);
325
326	maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
327	inode  = affs_new_inode(dir);
328	if (!inode)
329		return -ENOSPC;
330
331	inode->i_op = &affs_symlink_inode_operations;
332	inode_nohighmem(inode);
333	inode->i_data.a_ops = &affs_symlink_aops;
334	inode->i_mode = S_IFLNK | 0777;
335	affs_mode_to_prot(inode);
336
337	error = -EIO;
338	bh = affs_bread(sb, inode->i_ino);
339	if (!bh)
340		goto err;
341	i  = 0;
342	p  = (char *)AFFS_HEAD(bh)->table;
343	lc = '/';
344	if (*symname == '/') {
345		struct affs_sb_info *sbi = AFFS_SB(sb);
346		while (*symname == '/')
347			symname++;
348		spin_lock(&sbi->symlink_lock);
349		while (sbi->s_volume[i])	/* Cannot overflow */
350			*p++ = sbi->s_volume[i++];
351		spin_unlock(&sbi->symlink_lock);
352	}
353	while (i < maxlen && (c = *symname++)) {
354		if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
355			*p++ = '/';
356			i++;
357			symname += 2;
358			lc = '/';
359		} else if (c == '.' && lc == '/' && *symname == '/') {
360			symname++;
361			lc = '/';
362		} else {
363			*p++ = c;
364			lc   = c;
365			i++;
366		}
367		if (lc == '/')
368			while (*symname == '/')
369				symname++;
370	}
371	*p = 0;
372	inode->i_size = i + 1;
373	mark_buffer_dirty_inode(bh, inode);
374	affs_brelse(bh);
375	mark_inode_dirty(inode);
376
377	error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
378	if (error)
379		goto err;
380
381	return 0;
382
383err:
384	clear_nlink(inode);
385	mark_inode_dirty(inode);
386	iput(inode);
387	return error;
388}
389
390int
391affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
392{
393	struct inode *inode = d_inode(old_dentry);
394
395	pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
396		 dentry);
397
398	return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
399}
400
401static int
402affs_rename(struct inode *old_dir, struct dentry *old_dentry,
403	    struct inode *new_dir, struct dentry *new_dentry)
404{
405	struct super_block *sb = old_dir->i_sb;
406	struct buffer_head *bh = NULL;
407	int retval;
408
409	retval = affs_check_name(new_dentry->d_name.name,
410				 new_dentry->d_name.len,
411				 affs_nofilenametruncate(old_dentry));
412
 
413	if (retval)
414		return retval;
415
416	/* Unlink destination if it already exists */
417	if (d_really_is_positive(new_dentry)) {
418		retval = affs_remove_header(new_dentry);
419		if (retval)
420			return retval;
421	}
422
423	bh = affs_bread(sb, d_inode(old_dentry)->i_ino);
424	if (!bh)
425		return -EIO;
426
427	/* Remove header from its parent directory. */
428	affs_lock_dir(old_dir);
429	retval = affs_remove_hash(old_dir, bh);
430	affs_unlock_dir(old_dir);
431	if (retval)
432		goto done;
433
434	/* And insert it into the new directory with the new name. */
435	affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
436	affs_fix_checksum(sb, bh);
437	affs_lock_dir(new_dir);
438	retval = affs_insert_hash(new_dir, bh);
439	affs_unlock_dir(new_dir);
440	/* TODO: move it back to old_dir, if error? */
441
442done:
443	mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
444	affs_brelse(bh);
445	return retval;
446}
447
448static int
449affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
450	     struct inode *new_dir, struct dentry *new_dentry)
451{
452
453	struct super_block *sb = old_dir->i_sb;
454	struct buffer_head *bh_old = NULL;
455	struct buffer_head *bh_new = NULL;
456	int retval;
457
458	bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino);
459	if (!bh_old)
460		return -EIO;
461
462	bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino);
463	if (!bh_new)
464		return -EIO;
465
466	/* Remove old header from its parent directory. */
467	affs_lock_dir(old_dir);
468	retval = affs_remove_hash(old_dir, bh_old);
469	affs_unlock_dir(old_dir);
470	if (retval)
471		goto done;
472
473	/* Remove new header from its parent directory. */
474	affs_lock_dir(new_dir);
475	retval = affs_remove_hash(new_dir, bh_new);
476	affs_unlock_dir(new_dir);
477	if (retval)
478		goto done;
479
480	/* Insert old into the new directory with the new name. */
481	affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry);
482	affs_fix_checksum(sb, bh_old);
483	affs_lock_dir(new_dir);
484	retval = affs_insert_hash(new_dir, bh_old);
485	affs_unlock_dir(new_dir);
486
487	/* Insert new into the old directory with the old name. */
488	affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry);
489	affs_fix_checksum(sb, bh_new);
490	affs_lock_dir(old_dir);
491	retval = affs_insert_hash(old_dir, bh_new);
492	affs_unlock_dir(old_dir);
493done:
494	mark_buffer_dirty_inode(bh_old, new_dir);
495	mark_buffer_dirty_inode(bh_new, old_dir);
496	affs_brelse(bh_old);
497	affs_brelse(bh_new);
498	return retval;
499}
500
501int affs_rename2(struct inode *old_dir, struct dentry *old_dentry,
502			struct inode *new_dir, struct dentry *new_dentry,
503			unsigned int flags)
504{
505
506	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
507		return -EINVAL;
508
509	pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
510		 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
511
512	if (flags & RENAME_EXCHANGE)
513		return affs_xrename(old_dir, old_dentry, new_dir, new_dentry);
514
515	return affs_rename(old_dir, old_dentry, new_dir, new_dentry);
516}
517
518static struct dentry *affs_get_parent(struct dentry *child)
519{
520	struct inode *parent;
521	struct buffer_head *bh;
522
523	bh = affs_bread(child->d_sb, d_inode(child)->i_ino);
524	if (!bh)
525		return ERR_PTR(-EIO);
526
527	parent = affs_iget(child->d_sb,
528			   be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent));
529	brelse(bh);
530	if (IS_ERR(parent))
531		return ERR_CAST(parent);
532
533	return d_obtain_alias(parent);
534}
535
536static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino,
537					u32 generation)
538{
539	struct inode *inode;
540
541	if (!affs_validblock(sb, ino))
542		return ERR_PTR(-ESTALE);
543
544	inode = affs_iget(sb, ino);
545	if (IS_ERR(inode))
546		return ERR_CAST(inode);
547
548	return inode;
549}
550
551static struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid,
552					int fh_len, int fh_type)
553{
554	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
555				    affs_nfs_get_inode);
556}
557
558static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
559					int fh_len, int fh_type)
560{
561	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
562				    affs_nfs_get_inode);
563}
564
565const struct export_operations affs_export_ops = {
566	.fh_to_dentry = affs_fh_to_dentry,
567	.fh_to_parent = affs_fh_to_parent,
568	.get_parent = affs_get_parent,
569};
570
571const struct dentry_operations affs_dentry_operations = {
572	.d_hash		= affs_hash_dentry,
573	.d_compare	= affs_compare_dentry,
574};
575
576const struct dentry_operations affs_intl_dentry_operations = {
577	.d_hash		= affs_intl_hash_dentry,
578	.d_compare	= affs_intl_compare_dentry,
579};
v3.5.6
 
  1/*
  2 *  linux/fs/affs/namei.c
  3 *
  4 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  5 *
  6 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  7 *
  8 *  (C) 1991  Linus Torvalds - minix filesystem
  9 */
 10
 11#include "affs.h"
 
 12
 13typedef int (*toupper_t)(int);
 14
 15static int	 affs_toupper(int ch);
 16static int	 affs_hash_dentry(const struct dentry *,
 17		const struct inode *, struct qstr *);
 18static int       affs_compare_dentry(const struct dentry *parent,
 19		const struct inode *pinode,
 20		const struct dentry *dentry, const struct inode *inode,
 21		unsigned int len, const char *str, const struct qstr *name);
 22static int	 affs_intl_toupper(int ch);
 23static int	 affs_intl_hash_dentry(const struct dentry *,
 24		const struct inode *, struct qstr *);
 25static int       affs_intl_compare_dentry(const struct dentry *parent,
 26		const struct inode *pinode,
 27		const struct dentry *dentry, const struct inode *inode,
 28		unsigned int len, const char *str, const struct qstr *name);
 29
 30const struct dentry_operations affs_dentry_operations = {
 31	.d_hash		= affs_hash_dentry,
 32	.d_compare	= affs_compare_dentry,
 33};
 34
 35const struct dentry_operations affs_intl_dentry_operations = {
 36	.d_hash		= affs_intl_hash_dentry,
 37	.d_compare	= affs_intl_compare_dentry,
 38};
 39
 40
 41/* Simple toupper() for DOS\1 */
 42
 43static int
 44affs_toupper(int ch)
 45{
 46	return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
 47}
 48
 49/* International toupper() for DOS\3 ("international") */
 50
 51static int
 52affs_intl_toupper(int ch)
 53{
 54	return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
 55		&& ch <= 0xFE && ch != 0xF7) ?
 56		ch - ('a' - 'A') : ch;
 57}
 58
 59static inline toupper_t
 60affs_get_toupper(struct super_block *sb)
 61{
 62	return AFFS_SB(sb)->s_flags & SF_INTL ? affs_intl_toupper : affs_toupper;
 
 63}
 64
 65/*
 66 * Note: the dentry argument is the parent dentry.
 67 */
 68static inline int
 69__affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
 70{
 71	const u8 *name = qstr->name;
 72	unsigned long hash;
 73	int i;
 
 
 
 
 
 74
 75	i = affs_check_name(qstr->name, qstr->len);
 76	if (i)
 77		return i;
 78
 79	hash = init_name_hash();
 80	i = min(qstr->len, 30u);
 81	for (; i > 0; name++, i--)
 82		hash = partial_name_hash(toupper(*name), hash);
 83	qstr->hash = end_name_hash(hash);
 84
 85	return 0;
 86}
 87
 88static int
 89affs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
 90		struct qstr *qstr)
 91{
 92	return __affs_hash_dentry(qstr, affs_toupper);
 
 
 93}
 
 94static int
 95affs_intl_hash_dentry(const struct dentry *dentry, const struct inode *inode,
 96		struct qstr *qstr)
 97{
 98	return __affs_hash_dentry(qstr, affs_intl_toupper);
 
 
 99}
100
101static inline int __affs_compare_dentry(unsigned int len,
102		const char *str, const struct qstr *name, toupper_t toupper)
 
103{
104	const u8 *aname = str;
105	const u8 *bname = name->name;
106
107	/*
108	 * 'str' is the name of an already existing dentry, so the name
109	 * must be valid. 'name' must be validated first.
110	 */
111
112	if (affs_check_name(name->name, name->len))
113		return 1;
114
115	/*
116	 * If the names are longer than the allowed 30 chars,
117	 * the excess is ignored, so their length may differ.
118	 */
119	if (len >= 30) {
120		if (name->len < 30)
121			return 1;
122		len = 30;
123	} else if (len != name->len)
124		return 1;
125
126	for (; len > 0; len--)
127		if (toupper(*aname++) != toupper(*bname++))
128			return 1;
129
130	return 0;
131}
132
133static int
134affs_compare_dentry(const struct dentry *parent, const struct inode *pinode,
135		const struct dentry *dentry, const struct inode *inode,
136		unsigned int len, const char *str, const struct qstr *name)
137{
138	return __affs_compare_dentry(len, str, name, affs_toupper);
 
 
139}
 
140static int
141affs_intl_compare_dentry(const struct dentry *parent,const struct inode *pinode,
142		const struct dentry *dentry, const struct inode *inode,
143		unsigned int len, const char *str, const struct qstr *name)
144{
145	return __affs_compare_dentry(len, str, name, affs_intl_toupper);
 
 
146}
147
148/*
149 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
150 */
151
152static inline int
153affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
154{
155	const u8 *name = dentry->d_name.name;
156	int len = dentry->d_name.len;
157
158	if (len >= 30) {
159		if (*name2 < 30)
160			return 0;
161		len = 30;
162	} else if (len != *name2)
163		return 0;
164
165	for (name2++; len > 0; len--)
166		if (toupper(*name++) != toupper(*name2++))
167			return 0;
168	return 1;
169}
170
171int
172affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
173{
174	toupper_t toupper = affs_get_toupper(sb);
175	int hash;
176
177	hash = len = min(len, 30u);
178	for (; len > 0; len--)
179		hash = (hash * 13 + toupper(*name++)) & 0x7ff;
180
181	return hash % AFFS_SB(sb)->s_hashsize;
182}
183
184static struct buffer_head *
185affs_find_entry(struct inode *dir, struct dentry *dentry)
186{
187	struct super_block *sb = dir->i_sb;
188	struct buffer_head *bh;
189	toupper_t toupper = affs_get_toupper(sb);
190	u32 key;
191
192	pr_debug("AFFS: find_entry(\"%.*s\")\n", (int)dentry->d_name.len, dentry->d_name.name);
193
194	bh = affs_bread(sb, dir->i_ino);
195	if (!bh)
196		return ERR_PTR(-EIO);
197
198	key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
199
200	for (;;) {
201		affs_brelse(bh);
202		if (key == 0)
203			return NULL;
204		bh = affs_bread(sb, key);
205		if (!bh)
206			return ERR_PTR(-EIO);
207		if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
208			return bh;
209		key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
210	}
211}
212
213struct dentry *
214affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
215{
216	struct super_block *sb = dir->i_sb;
217	struct buffer_head *bh;
218	struct inode *inode = NULL;
 
219
220	pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
221
222	affs_lock_dir(dir);
223	bh = affs_find_entry(dir, dentry);
224	affs_unlock_dir(dir);
225	if (IS_ERR(bh))
226		return ERR_CAST(bh);
 
227	if (bh) {
228		u32 ino = bh->b_blocknr;
229
230		/* store the real header ino in d_fsdata for faster lookups */
231		dentry->d_fsdata = (void *)(long)ino;
232		switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
233		//link to dirs disabled
234		//case ST_LINKDIR:
235		case ST_LINKFILE:
236			ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
237		}
238		affs_brelse(bh);
239		inode = affs_iget(sb, ino);
240		if (IS_ERR(inode))
241			return ERR_CAST(inode);
242	}
243	d_add(dentry, inode);
244	return NULL;
 
 
 
245}
246
247int
248affs_unlink(struct inode *dir, struct dentry *dentry)
249{
250	pr_debug("AFFS: unlink(dir=%d, %lu \"%.*s\")\n", (u32)dir->i_ino,
251		 dentry->d_inode->i_ino,
252		 (int)dentry->d_name.len, dentry->d_name.name);
253
254	return affs_remove_header(dentry);
255}
256
257int
258affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
259{
260	struct super_block *sb = dir->i_sb;
261	struct inode	*inode;
262	int		 error;
263
264	pr_debug("AFFS: create(%lu,\"%.*s\",0%ho)\n",dir->i_ino,(int)dentry->d_name.len,
265		 dentry->d_name.name,mode);
266
267	inode = affs_new_inode(dir);
268	if (!inode)
269		return -ENOSPC;
270
271	inode->i_mode = mode;
272	mode_to_prot(inode);
273	mark_inode_dirty(inode);
274
275	inode->i_op = &affs_file_inode_operations;
276	inode->i_fop = &affs_file_operations;
277	inode->i_mapping->a_ops = (AFFS_SB(sb)->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
 
278	error = affs_add_entry(dir, inode, dentry, ST_FILE);
279	if (error) {
280		clear_nlink(inode);
281		iput(inode);
282		return error;
283	}
284	return 0;
285}
286
287int
288affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
289{
290	struct inode		*inode;
291	int			 error;
292
293	pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%ho)\n",dir->i_ino,
294		 (int)dentry->d_name.len,dentry->d_name.name,mode);
295
296	inode = affs_new_inode(dir);
297	if (!inode)
298		return -ENOSPC;
299
300	inode->i_mode = S_IFDIR | mode;
301	mode_to_prot(inode);
302
303	inode->i_op = &affs_dir_inode_operations;
304	inode->i_fop = &affs_dir_operations;
305
306	error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
307	if (error) {
308		clear_nlink(inode);
309		mark_inode_dirty(inode);
310		iput(inode);
311		return error;
312	}
313	return 0;
314}
315
316int
317affs_rmdir(struct inode *dir, struct dentry *dentry)
318{
319	pr_debug("AFFS: rmdir(dir=%u, %lu \"%.*s\")\n", (u32)dir->i_ino,
320		 dentry->d_inode->i_ino,
321		 (int)dentry->d_name.len, dentry->d_name.name);
322
323	return affs_remove_header(dentry);
324}
325
326int
327affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
328{
329	struct super_block	*sb = dir->i_sb;
330	struct buffer_head	*bh;
331	struct inode		*inode;
332	char			*p;
333	int			 i, maxlen, error;
334	char			 c, lc;
335
336	pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
337		 (int)dentry->d_name.len,dentry->d_name.name,symname);
338
339	maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
340	inode  = affs_new_inode(dir);
341	if (!inode)
342		return -ENOSPC;
343
344	inode->i_op = &affs_symlink_inode_operations;
 
345	inode->i_data.a_ops = &affs_symlink_aops;
346	inode->i_mode = S_IFLNK | 0777;
347	mode_to_prot(inode);
348
349	error = -EIO;
350	bh = affs_bread(sb, inode->i_ino);
351	if (!bh)
352		goto err;
353	i  = 0;
354	p  = (char *)AFFS_HEAD(bh)->table;
355	lc = '/';
356	if (*symname == '/') {
357		struct affs_sb_info *sbi = AFFS_SB(sb);
358		while (*symname == '/')
359			symname++;
360		spin_lock(&sbi->symlink_lock);
361		while (sbi->s_volume[i])	/* Cannot overflow */
362			*p++ = sbi->s_volume[i++];
363		spin_unlock(&sbi->symlink_lock);
364	}
365	while (i < maxlen && (c = *symname++)) {
366		if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
367			*p++ = '/';
368			i++;
369			symname += 2;
370			lc = '/';
371		} else if (c == '.' && lc == '/' && *symname == '/') {
372			symname++;
373			lc = '/';
374		} else {
375			*p++ = c;
376			lc   = c;
377			i++;
378		}
379		if (lc == '/')
380			while (*symname == '/')
381				symname++;
382	}
383	*p = 0;
 
384	mark_buffer_dirty_inode(bh, inode);
385	affs_brelse(bh);
386	mark_inode_dirty(inode);
387
388	error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
389	if (error)
390		goto err;
391
392	return 0;
393
394err:
395	clear_nlink(inode);
396	mark_inode_dirty(inode);
397	iput(inode);
398	return error;
399}
400
401int
402affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
403{
404	struct inode *inode = old_dentry->d_inode;
405
406	pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino,
407		 (int)dentry->d_name.len,dentry->d_name.name);
408
409	return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
410}
411
412int
413affs_rename(struct inode *old_dir, struct dentry *old_dentry,
414	    struct inode *new_dir, struct dentry *new_dentry)
415{
416	struct super_block *sb = old_dir->i_sb;
417	struct buffer_head *bh = NULL;
418	int retval;
419
420	pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
421		 (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
422		 (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
423
424	retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len);
425	if (retval)
426		return retval;
427
428	/* Unlink destination if it already exists */
429	if (new_dentry->d_inode) {
430		retval = affs_remove_header(new_dentry);
431		if (retval)
432			return retval;
433	}
434
435	bh = affs_bread(sb, old_dentry->d_inode->i_ino);
436	if (!bh)
437		return -EIO;
438
439	/* Remove header from its parent directory. */
440	affs_lock_dir(old_dir);
441	retval = affs_remove_hash(old_dir, bh);
442	affs_unlock_dir(old_dir);
443	if (retval)
444		goto done;
445
446	/* And insert it into the new directory with the new name. */
447	affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
448	affs_fix_checksum(sb, bh);
449	affs_lock_dir(new_dir);
450	retval = affs_insert_hash(new_dir, bh);
451	affs_unlock_dir(new_dir);
452	/* TODO: move it back to old_dir, if error? */
453
454done:
455	mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
456	affs_brelse(bh);
457	return retval;
458}