?? namei.c
字號:
/* * linux/fs/affs/namei.c * * (c) 1996 Hans-Joachim Widmaier - Rewritten * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * * (C) 1991 Linus Torvalds - minix filesystem */#include <linux/sched.h>#include <linux/affs_fs.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/locks.h>#include <linux/amigaffs.h>#include <asm/segment.h>#include <linux/errno.h>/* Simple toupper() for DOS\1 */static inline unsigned intaffs_toupper(unsigned int ch){ return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;}/* International toupper() for DOS\3 */static inline unsigned intaffs_intl_toupper(unsigned int ch){ return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0 && ch <= 0xFE && ch != 0xF7) ? ch - ('a' - 'A') : ch;}/* * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure. */static intaffs_match(const char *name, int len, const char *compare, int dlen, int intl){ if (!compare) return 0; if (len > 30) len = 30; if (dlen > 30) dlen = 30; /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ if (!len && dlen == 1 && compare[0] == '.') return 1; if (dlen != len) return 0; if (intl) { while (dlen--) { if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF)) return 0; name++; compare++; } } else { while (dlen--) { if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF)) return 0; name++; compare++; } } return 1;}intaffs_hash_name(const char *name, int len, int intl, int hashsize){ unsigned int i, x; if (len > 30) len = 30; x = len; for (i = 0; i < len; i++) if (intl) x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff; else x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff; return x % hashsize;}static struct buffer_head *affs_find_entry(struct inode *dir, const char *name, int namelen, unsigned long *ino){ struct buffer_head *bh; int intl; int key; pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name); intl = AFFS_I2FSTYPE(dir); bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); if (!bh) return NULL; if (affs_match(name,namelen,".",1,intl)) { *ino = dir->i_ino; return bh; } if (affs_match(name,namelen,"..",2,intl)) { *ino = affs_parent_ino(dir); return bh; } key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir))); for (;;) { char *cname; int cnamelen; affs_brelse(bh); if (key == 0) { bh = NULL; break; } bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir)); if (!bh) break; cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname); if (affs_match(name,namelen,cname,cnamelen,intl)) break; key = htonl(FILE_END(bh->b_data,dir)->hash_chain); } *ino = key; return bh;}intaffs_lookup(struct inode *dir, const char *name, int len, struct inode **result){ int res; unsigned long ino; struct buffer_head *bh; pr_debug("AFFS: lookup(%.*s)\n",len,name); *result = NULL; if (!dir) return -ENOENT; res = -ENOENT; if (S_ISDIR(dir->i_mode)) { if ((bh = affs_find_entry(dir,name,len,&ino))) { if (FILE_END(bh->b_data,dir)->original) ino = htonl(FILE_END(bh->b_data,dir)->original); affs_brelse(bh); if ((*result = iget(dir->i_sb,ino))) res = 0; else res = -EACCES; } } iput(dir); return res;}intaffs_unlink(struct inode *dir, const char *name, int len){ int retval; struct buffer_head *bh; unsigned long ino; struct inode *inode; pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name); bh = NULL; inode = NULL; retval = -ENOENT; if (!(bh = affs_find_entry(dir,name,len,&ino))) { goto unlink_done; } if (!(inode = iget(dir->i_sb,ino))) { goto unlink_done; } if (S_ISDIR(inode->i_mode)) { retval = -EPERM; goto unlink_done; } if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), AFFS_I2HSIZE(dir)) + 6,ino, FILE_END(bh->b_data,dir)->hash_chain))) goto unlink_done; if ((retval = affs_fixup(bh,inode))) goto unlink_done; inode->i_nlink=0; inode->i_dirt=1; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_version = ++event; dir->i_dirt=1;unlink_done: affs_brelse(bh); iput(inode); iput(dir); return retval;}intaffs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result){ struct inode *inode; int error; pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); *result = NULL; if (!dir || !dir->i_sb) { iput(dir); return -EINVAL; } inode = affs_new_inode(dir); if (!inode) { iput (dir); return -ENOSPC; } inode->i_mode = mode; if (dir->i_sb->u.affs_sb.s_flags & SF_OFS) inode->i_op = &affs_file_inode_operations_ofs; else inode->i_op = &affs_file_inode_operations; error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE); if (error) { iput(dir); inode->i_nlink = 0; inode->i_dirt = 1; iput(inode); return -ENOSPC; } inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); iput(dir); *result = inode; return 0;}intaffs_mkdir(struct inode *dir, const char *name, int len, int mode){ struct inode *inode; struct buffer_head *bh; unsigned long i; int error; pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); if (!dir || !dir->i_sb) { iput(dir); return -EINVAL; } bh = affs_find_entry(dir,name,len,&i); if (bh) { affs_brelse(bh); iput(dir); return -EEXIST; } inode = affs_new_inode(dir); if (!inode) { iput (dir); return -ENOSPC; } inode->i_op = &affs_dir_inode_operations; error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR); if (error) { iput(dir); inode->i_nlink = 0; inode->i_dirt = 1; iput(inode); return error; } inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); iput(dir); iput(inode); return 0;}static intempty_dir(struct buffer_head *bh, int hashsize){ while (--hashsize >= 0) { if (((struct dir_front *)bh->b_data)->hashtable[hashsize]) return 0; } return 1;}intaffs_rmdir(struct inode *dir, const char *name, int len){ int retval; unsigned long ino; struct inode *inode; struct buffer_head *bh; pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name); inode = NULL; retval = -ENOENT; if (!(bh = affs_find_entry(dir,name,len,&ino))) { goto rmdir_done; } if (!(inode = iget(dir->i_sb,ino))) { goto rmdir_done; } retval = -EPERM; if (!fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) goto rmdir_done; if (inode->i_dev != dir->i_dev) goto rmdir_done; if (inode == dir) /* we may not delete ".", but "../dir" is ok */ goto rmdir_done; if (!S_ISDIR(inode->i_mode)) { retval = -ENOTDIR; goto rmdir_done; } if (!empty_dir(bh,AFFS_I2HSIZE(inode))) { retval = -ENOTEMPTY; goto rmdir_done; } if (inode->i_count > 1) { retval = -EBUSY; goto rmdir_done; } if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), AFFS_I2HSIZE(dir)) + 6,ino, FILE_END(bh->b_data,dir)->hash_chain))) goto rmdir_done; if ((retval = affs_fixup(bh,inode))) goto rmdir_done; inode->i_nlink=0; inode->i_dirt=1; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_version = ++event; dir->i_dirt=1;rmdir_done: iput(dir); iput(inode); affs_brelse(bh); return retval;}intaffs_symlink(struct inode *dir, const char *name, int len, const char *symname)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -