int sysv_add_link(struct dentry *dentry, struct inode *inode) { struct inode *dir = dentry->d_parent->d_inode; const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; struct page *page = NULL; struct sysv_dir_entry * de; unsigned long npages = dir_pages(dir); unsigned long n; char *kaddr; loff_t pos; int err; /* We take care of directory expansion in the same loop */ for (n = 0; n <= npages; n++) { page = dir_get_page(dir, n); err = PTR_ERR(page); if (IS_ERR(page)) goto out; kaddr = (char*)page_address(page); de = (struct sysv_dir_entry *)kaddr; kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; while ((char *)de <= kaddr) { if (!de->inode) goto got_it; err = -EEXIST; if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) goto out_page; de++; } dir_put_page(page); } BUG(); return -EINVAL; got_it: pos = page_offset(page) + (char*)de - (char*)page_address(page); lock_page(page); err = __sysv_write_begin(NULL, page->mapping, pos, SYSV_DIRSIZE, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) goto out_unlock; memcpy (de->name, name, namelen); memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2); de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); out_page: dir_put_page(page); out: return err; out_unlock: unlock_page(page); goto out_page; }
/* * ok, we cannot use strncmp, as the name is not in our data space. [Now it is!] * Thus we'll have to use sysv_match. No big problem. Match also makes * some sanity tests. * * NOTE! unlike strncmp, sysv_match returns 1 for success, 0 for failure. */ static int sysv_match(int len, const char * name, struct sysv_dir_entry * de) { if (!de->inode || len > SYSV_NAMELEN) return 0; /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) return 1; return namecompare(len, SYSV_NAMELEN, name, de->name); }
int sysv_add_link(struct dentry *dentry, struct inode *inode) { struct inode *dir = dentry->d_parent->d_inode; const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; struct page *page = NULL; struct sysv_dir_entry * de; unsigned long npages = dir_pages(dir); unsigned long n; char *kaddr; unsigned from, to; int err; /* We take care of directory expansion in the same loop */ for (n = 0; n <= npages; n++) { page = dir_get_page(dir, n); err = PTR_ERR(page); if (IS_ERR(page)) goto out; kaddr = (char*)page_address(page); de = (struct sysv_dir_entry *)kaddr; kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; while ((char *)de <= kaddr) { if (!de->inode) goto got_it; err = -EEXIST; if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) goto out_page; de++; } dir_put_page(page); } BUG(); return -EINVAL; got_it: from = (char*)de - (char*)page_address(page); to = from + SYSV_DIRSIZE; lock_page(page); err = page->mapping->a_ops->prepare_write(NULL, page, from, to); if (err) goto out_unlock; memcpy (de->name, name, namelen); memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2); de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino); err = dir_commit_chunk(page, from, to); dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); out_unlock: UnlockPage(page); out_page: dir_put_page(page); out: return err; }
/* * ok, we cannot use strncmp, as the name is not in our data space. * Thus we'll have to use minix_match. No big problem. Match also makes * some sanity tests. * * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure. * * Note2: bh must already be mapped! */ static int elksfs_match(size_t len, char *name, struct buffer_head *bh, loff_t *offset, register struct elksfs_sb_info *info) { register struct elksfs_dir_entry *de; de = (struct elksfs_dir_entry *) (bh->b_data + *offset); *offset += info->s_dirsize; if (!de->inode || (unsigned long int) len > info->s_namelen) return 0; /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ if (!len && (de->name[0] == '.') && (de->name[1] == '\0')) return 1; return namecompare(len, (size_t) info->s_namelen, name, de->name); }
/* * ok, we cannot use strncmp, as the name is not in our data space. * Thus we'll have to use minix_match. No big problem. Match also makes * some sanity tests. * * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure. * * Note2: bh must already be mapped! */ static int minix_match(size_t len, char *name, struct buffer_head *bh, loff_t offset, register struct minix_sb_info *info) { register struct minix_dir_entry *de; de = (struct minix_dir_entry *) (bh->b_data + offset); if (!de->inode || len > info->s_namelen) { return 0; } /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ if (!len && (de->name[0] == '.') && (de->name[1] == '\0')) { return 1; } return namecompare(len, info->s_namelen, name, de->name); }
/* * sysv_find_entry() * * finds an entry in the specified directory with the wanted name. It * returns the cache buffer in which the entry was found, and the entry * itself (as a parameter - res_dir). It does NOT read the inode of the * entry - you'll have to do that yourself if you want to. */ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page) { const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; struct inode * dir = dentry->d_parent->d_inode; unsigned long start, n; unsigned long npages = dir_pages(dir); struct page *page = NULL; struct sysv_dir_entry *de; *res_page = NULL; start = SYSV_I(dir)->i_dir_start_lookup; if (start >= npages) start = 0; n = start; do { char *kaddr; page = dir_get_page(dir, n); if (!IS_ERR(page)) { kaddr = (char*)page_address(page); de = (struct sysv_dir_entry *) kaddr; kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; for ( ; (char *) de <= kaddr ; de++) { if (!de->inode) continue; if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) goto found; } dir_put_page(page); } if (++n >= npages) n = 0; } while (n != start); return NULL; found: SYSV_I(dir)->i_dir_start_lookup = n; *res_page = page; return de; }
/* * minix_find_entry() * * finds an entry in the specified directory with the wanted name. It * returns the cache buffer in which the entry was found, and the entry * itself (as a parameter - res_dir). It does NOT read the inode of the * entry - you'll have to do that yourself if you want to. */ static struct buffer_head * minix_find_entry(struct inode * dir, const char * name, int namelen, struct minix_dir_entry ** res_dir) { unsigned long block, offset; struct buffer_head * bh; struct minix_sb_info * info; struct minix_dir_entry *de; *res_dir = NULL; if (!dir || !dir->i_sb) return NULL; info = &dir->i_sb->u.minix_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE return NULL; #else namelen = info->s_namelen; #endif } bh = NULL; block = offset = 0; while (block*BLOCK_SIZE+offset < dir->i_size) { if (!bh) { bh = minix_bread(dir,block,0); if (!bh) { block++; continue; } } de = (struct minix_dir_entry *) (bh->b_data + offset); offset += info->s_dirsize; if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) { *res_dir = de; return bh; } if (offset < bh->b_size) continue; brelse(bh); bh = NULL; offset = 0; block++; } brelse(bh); return NULL; }
static int elksfs_add_entry(register struct inode *dir, char *name, size_t namelen, struct buffer_head **res_buf, struct elksfs_dir_entry **res_dir) { struct buffer_head *bh; struct elksfs_dir_entry *de; struct elksfs_sb_info *info; unsigned long int i; block_t block; loff_t offset; *res_buf = NULL; *res_dir = NULL; if (!dir || !dir->i_sb) return -ENOENT; info = &dir->i_sb->u.elksfs_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE return -ENAMETOOLONG; #else namelen = info->s_namelen; #endif } if (!namelen) return -ENOENT; bh = NULL; block = 0; offset = 0; while (1) { if (!bh) { bh = elksfs_bread(dir, block, 1); if (!bh) return -ENOSPC; } map_buffer(bh); de = (struct elksfs_dir_entry *) (bh->b_data + offset); offset += info->s_dirsize; if (block * 1024 + offset > dir->i_size) { de->inode = 0; dir->i_size = block * 1024 + offset; dir->i_dirt = 1; } if (de->inode) { if (namecompare(namelen, (size_t) info->s_namelen, name, de->name)) { debug2("ELKSFSadd_entry: file %t==%s (already exists)\n", name, de->name); unmap_brelse(bh); return -EEXIST; } } else { dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_dirt = 1; for (i = 0; i < info->s_namelen; i++) de->name[i] = (i < namelen) ? (char) get_fs_byte((unsigned char *) name + i) : 0; #ifdef BLOAT_FS dir->i_version = ++event; #endif unmap_buffer(bh); mark_buffer_dirty(bh, 1); *res_dir = de; break; } if (offset < 1024) continue; printk("elksfs_add_entry may need another unmap_buffer :)\n"); brelse(bh); bh = NULL; offset = 0; block++; } *res_buf = bh; return 0; }
static int minix_add_entry(register struct inode *dir, char *name, size_t namelen, ino_t ino) { unsigned short block; loff_t offset; register struct buffer_head *bh; struct minix_dir_entry *de; struct minix_sb_info *info; if (!dir || !dir->i_sb) return -ENOENT; info = &dir->i_sb->u.minix_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE return -ENAMETOOLONG; #else namelen = info->s_namelen; #endif } if (!namelen) return -ENOENT; bh = NULL; block = 0; offset = 0L; while (1) { if (!bh) { bh = minix_bread(dir, block, 1); if (!bh) return -ENOSPC; map_buffer(bh); } de = (struct minix_dir_entry *) (bh->b_data + offset); offset += info->s_dirsize; if (block * 1024L + offset > dir->i_size) { de->inode = 0; dir->i_size = block * 1024L + offset; dir->i_dirt = 1; } if (de->inode) { if (namecompare(namelen, info->s_namelen, name, de->name)) { debug2("MINIXadd_entry: file %t==%s (already exists)\n", name, de->name); unmap_brelse(bh); return -EEXIST; } } else { size_t i; dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_dirt = 1; memcpy_fromfs(de->name, name, namelen); if((i = info->s_namelen - namelen) > 0) memset(de->name + namelen, 0, i); #ifdef BLOAT_FS dir->i_version = ++event; #endif de->inode = ino; mark_buffer_dirty(bh, 1); unmap_brelse(bh); break; } if (offset >= BLOCK_SIZE) { unmap_brelse(bh); bh = NULL; offset = 0; block++; } } return 0; }
/* * sysv_add_entry() * * adds a file entry to the specified directory, returning a possible * error value if it fails. * * NOTE!! The inode part of 'de' is left at 0 - which means you * may not sleep between calling this and putting something into * the entry, as someone else might have used it while you slept. */ static int sysv_add_entry(struct inode * dir, const char * name, int namelen, struct buffer_head ** res_buf, struct sysv_dir_entry ** res_dir) { struct super_block * sb; int i; unsigned long pos, block, offset; /* pos = block * block_size + offset */ struct buffer_head * bh; struct sysv_dir_entry * de; *res_buf = NULL; *res_dir = NULL; sb = dir->i_sb; if (namelen > SYSV_NAMELEN) { if (sb->sv_truncate) namelen = SYSV_NAMELEN; else return -ENAMETOOLONG; } if (!namelen) return -ENOENT; bh = NULL; pos = block = offset = 0; while (1) { if (!bh) { bh = sysv_file_bread(dir, block, 1); if (!bh) return -ENOSPC; } de = (struct sysv_dir_entry *) (bh->b_data + offset); pos += SYSV_DIRSIZE; offset += SYSV_DIRSIZE; if (pos > dir->i_size) { de->inode = 0; dir->i_size = pos; mark_inode_dirty(dir); } if (de->inode) { if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) { brelse(bh); return -EEXIST; } } else { dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); for (i = 0; i < SYSV_NAMELEN ; i++) de->name[i] = (i < namelen) ? name[i] : 0; mark_buffer_dirty(bh); *res_dir = de; break; } if (offset < sb->sv_block_size) continue; brelse(bh); bh = NULL; offset = 0; block++; } *res_buf = bh; return 0; }
/* * minix_add_entry() * * adds a file entry to the specified directory, returning a possible * error value if it fails. * * NOTE!! The inode part of 'de' is left at 0 - which means you * may not sleep between calling this and putting something into * the entry, as someone else might have used it while you slept. */ static int minix_add_entry(struct inode * dir, const char * name, int namelen, struct buffer_head ** res_buf, struct minix_dir_entry ** res_dir) { int i; unsigned long block, offset; struct buffer_head * bh; struct minix_dir_entry * de; struct minix_sb_info * info; *res_buf = NULL; *res_dir = NULL; if (!dir || !dir->i_sb) return -ENOENT; info = &dir->i_sb->u.minix_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE return -ENAMETOOLONG; #else namelen = info->s_namelen; #endif } if (!namelen) return -ENOENT; bh = NULL; block = offset = 0; while (1) { if (!bh) { bh = minix_bread(dir,block,1); if (!bh) return -ENOSPC; } de = (struct minix_dir_entry *) (bh->b_data + offset); offset += info->s_dirsize; if (block*bh->b_size + offset > dir->i_size) { de->inode = 0; dir->i_size = block*bh->b_size + offset; mark_inode_dirty(dir); } if (de->inode) { if (namecompare(namelen, info->s_namelen, name, de->name)) { brelse(bh); return -EEXIST; } } else { dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); for (i = 0; i < info->s_namelen ; i++) de->name[i] = (i < namelen) ? name[i] : 0; dir->i_version = ++event; mark_buffer_dirty(bh, 1); *res_dir = de; break; } if (offset < bh->b_size) continue; brelse(bh); bh = NULL; offset = 0; block++; } *res_buf = bh; return 0; }
static int minix_add_entry(register struct inode *dir, char *name, size_t namelen, struct buffer_head **res_buf, struct minix_dir_entry **res_dir) { unsigned short block; loff_t offset; register struct buffer_head *bh; struct minix_dir_entry *de; struct minix_sb_info *info; *res_buf = NULL; *res_dir = NULL; if (!dir || !dir->i_sb) return -ENOENT; info = &dir->i_sb->u.minix_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE return -ENAMETOOLONG; #else namelen = info->s_namelen; #endif } if (!namelen) return -ENOENT; bh = NULL; block = 0; offset = 0L; while (1) { if (!bh) { bh = minix_bread(dir, block, 1); if (!bh) return -ENOSPC; map_buffer(bh); } de = (struct minix_dir_entry *) (bh->b_data + offset); offset += info->s_dirsize; if (block * 1024L + offset > dir->i_size) { de->inode = 0; dir->i_size = block * 1024L + offset; dir->i_dirt = 1; } if (de->inode) { if (namecompare(namelen, info->s_namelen, name, de->name)) { debug2("MINIXadd_entry: file %t==%s (already exists)\n", name, de->name); unmap_brelse(bh); return -EEXIST; } } else { size_t i; dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_dirt = 1; for (i = 0; i < info->s_namelen; i++) de->name[i] = (i < namelen) ? (char) get_fs_byte(name + i) : '\0'; #ifdef BLOAT_FS dir->i_version = ++event; #endif unmap_buffer(bh); mark_buffer_dirty(bh, 1); *res_dir = de; break; } if (offset < 1024) continue; unmap_brelse(bh); bh = NULL; offset = 0; block++; } *res_buf = bh; return 0; }