📄 emd.c
字号:
* call umsdos_writeentry(). * * To delete an entry, you find it, zero out the entry (memset) * and call umsdos_writeentry(). * * All this to say that umsdos_writeentry must be called after this * function since it relies on the f_pos field of info. * * Note: the caller must hold a lock on the parent directory. *//* #Specification: EMD file structure * The EMD file uses a fairly simple layout. It is made of records * (UMSDOS_REC_SIZE == 64). When a name can't be written in a single * record, multiple contiguous records are allocated. */static int umsdos_find (struct dentry *demd, struct umsdos_info *info){ struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; struct inode *emd_dir; int ret = -ENOENT; struct { off_t posok; /* Position available to store the entry */ off_t one; /* One empty position -> maybe <- large enough */ } empty; int found = 0; int empty_size = 0; struct address_space *mapping; filler_t *readpage; struct page *page = NULL; int index = -1; int offs = PAGE_CACHE_SIZE,max_offs = PAGE_CACHE_SIZE; char *p = NULL; loff_t pos = 0; /* make sure there's an EMD file ... */ ret = -ENOENT; emd_dir = demd->d_inode; if (!emd_dir) goto out_dput; mapping = emd_dir->i_mapping; readpage = (filler_t*)mapping->a_ops->readpage; empty.posok = emd_dir->i_size; while (1) { struct umsdos_dirent *rentry; int entry_size; if (offs >= max_offs) { if (page) { kunmap(page); page_cache_release(page); page = NULL; } if (pos >= emd_dir->i_size) { info->f_pos = empty.posok; break; } if (++index == (emd_dir->i_size>>PAGE_CACHE_SHIFT)) max_offs = emd_dir->i_size & ~PAGE_CACHE_MASK; offs -= PAGE_CACHE_SIZE; page = read_cache_page(mapping,index,readpage,NULL); if (IS_ERR(page)) goto sync_fail; wait_on_page(page); if (!Page_Uptodate(page)) goto async_fail; p = kmap(page); } rentry = (struct umsdos_dirent *)(p+offs); if (rentry->name_len == 0) { /* We are looking for an empty section at least */ /* as large as recsize. */ if (entry->name_len == 0) { info->f_pos = pos; ret = 0; break; } offs += UMSDOS_REC_SIZE; pos += UMSDOS_REC_SIZE; if (found) continue; if (!empty_size) empty.one = pos-UMSDOS_REC_SIZE; empty_size += UMSDOS_REC_SIZE; if (empty_size == recsize) { /* Here is a large enough section. */ empty.posok = empty.one; found = 1; } continue; } entry_size = umsdos_evalrecsize(rentry->name_len); if (entry_size > PAGE_CACHE_SIZE) goto async_fail; empty_size = 0; if (entry->name_len != rentry->name_len) goto skip_it; if (entry_size + offs > PAGE_CACHE_SIZE) { /* Sucker spans the page boundary */ int len = (p+PAGE_CACHE_SIZE)-rentry->name; struct page *next_page; char *q; next_page = read_cache_page(mapping,index+1,readpage,NULL); if (IS_ERR(next_page)) { page_cache_release(page); page = next_page; goto sync_fail; } wait_on_page(next_page); if (!Page_Uptodate(next_page)) { page_cache_release(page); page = next_page; goto async_fail; } q = kmap(next_page); if (memcmp(entry->name, rentry->name, len) || memcmp(entry->name+len, q, entry->name_len-len)) { kunmap(next_page); page_cache_release(next_page); goto skip_it; } kunmap(next_page); page_cache_release(next_page); } else if (memcmp (entry->name, rentry->name, entry->name_len)) goto skip_it; info->f_pos = pos; copy_entry(entry, rentry); ret = 0; break;skip_it: offs+=entry_size; pos+=entry_size; } if (page) { kunmap(page); page_cache_release(page); } umsdos_manglename (info);out_dput: dput(demd); return ret;async_fail: page_cache_release(page); page = ERR_PTR(-EIO);sync_fail: return PTR_ERR(page);}/* * Add a new entry in the EMD file. * Return 0 if OK or a negative error code. * Return -EEXIST if the entry already exists. * * Complete the information missing in info. * * N.B. What if the EMD file doesn't exist? */int umsdos_newentry (struct dentry *parent, struct umsdos_info *info){ int err, ret = -EEXIST; struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out; err = umsdos_find (demd, info); if (err && err == -ENOENT) { ret = umsdos_writeentry (parent, info, 0); Printk (("umsdos_writeentry EMD ret = %d\n", ret)); }out: return ret;}/* * Create a new hidden link. * Return 0 if OK, an error code if not. *//* #Specification: hard link / hidden name * When a hard link is created, the original file is renamed * to a hidden name. The name is "..LINKNNN" where NNN is a * number define from the entry offset in the EMD file. */int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info){ int ret; struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out; umsdos_parse ("..LINK", 6, info); info->entry.name_len = 0; ret = umsdos_find (demd, info); if (ret == -ENOENT || ret == 0) { info->entry.name_len = sprintf (info->entry.name, "..LINK%ld", info->f_pos); ret = 0; }out: return ret;}/* * Remove an entry from the EMD file. * Return 0 if OK, a negative error code otherwise. * * Complete the information missing in info. */int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir){ int ret; struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out; ret = umsdos_find (demd, info); if (ret) goto out; if (info->entry.name_len == 0) goto out; if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) { if (S_ISDIR (info->entry.mode)) { ret = -EISDIR; } else { ret = -ENOTDIR; } goto out; } ret = umsdos_writeentry (parent, info, 1);out: return ret;}/* * Verify that an EMD directory is empty. * Return: * 0 if not empty, * 1 if empty (except for EMD file), * 2 if empty or no EMD file. */int umsdos_isempty (struct dentry *dentry){ struct dentry *demd; int ret = 2; loff_t pos = 0; demd = umsdos_get_emd_dentry(dentry); if (IS_ERR(demd)) goto out; /* If the EMD file does not exist, it is certainly empty. :-) */ if (!demd->d_inode) goto out_dput; ret = 1; while (pos < demd->d_inode->i_size) { struct umsdos_dirent entry; if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) { ret = 0; break; } if (entry.name_len != 0) { ret = 0; break; } }out_dput: dput(demd);out: return ret;}/* * Locate an entry in a EMD directory. * Return 0 if OK, error code if not, generally -ENOENT. * * expect argument: * 0: anything * 1: file * 2: directory */int umsdos_findentry (struct dentry *parent, struct umsdos_info *info, int expect){ int ret; struct dentry *demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out; ret = umsdos_find (demd, info); if (ret) goto out; switch (expect) { case 1: if (S_ISDIR (info->entry.mode)) ret = -EISDIR; break; case 2: if (!S_ISDIR (info->entry.mode)) ret = -ENOTDIR; }out: Printk (("umsdos_findentry: returning %d\n", ret)); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -