at v2.6.21 385 lines 9.1 kB view raw
1/* 2 * linux/fs/sysv/dir.c 3 * 4 * minix/dir.c 5 * Copyright (C) 1991, 1992 Linus Torvalds 6 * 7 * coh/dir.c 8 * Copyright (C) 1993 Pascal Haible, Bruno Haible 9 * 10 * sysv/dir.c 11 * Copyright (C) 1993 Bruno Haible 12 * 13 * SystemV/Coherent directory handling functions 14 */ 15 16#include <linux/pagemap.h> 17#include <linux/highmem.h> 18#include <linux/smp_lock.h> 19#include "sysv.h" 20 21static int sysv_readdir(struct file *, void *, filldir_t); 22 23const struct file_operations sysv_dir_operations = { 24 .read = generic_read_dir, 25 .readdir = sysv_readdir, 26 .fsync = sysv_sync_file, 27}; 28 29static inline void dir_put_page(struct page *page) 30{ 31 kunmap(page); 32 page_cache_release(page); 33} 34 35static inline unsigned long dir_pages(struct inode *inode) 36{ 37 return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; 38} 39 40static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) 41{ 42 struct inode *dir = (struct inode *)page->mapping->host; 43 int err = 0; 44 45 page->mapping->a_ops->commit_write(NULL, page, from, to); 46 if (IS_DIRSYNC(dir)) 47 err = write_one_page(page, 1); 48 else 49 unlock_page(page); 50 return err; 51} 52 53static struct page * dir_get_page(struct inode *dir, unsigned long n) 54{ 55 struct address_space *mapping = dir->i_mapping; 56 struct page *page = read_mapping_page(mapping, n, NULL); 57 if (!IS_ERR(page)) { 58 wait_on_page_locked(page); 59 kmap(page); 60 if (!PageUptodate(page)) 61 goto fail; 62 } 63 return page; 64 65fail: 66 dir_put_page(page); 67 return ERR_PTR(-EIO); 68} 69 70static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) 71{ 72 unsigned long pos = filp->f_pos; 73 struct inode *inode = filp->f_path.dentry->d_inode; 74 struct super_block *sb = inode->i_sb; 75 unsigned offset = pos & ~PAGE_CACHE_MASK; 76 unsigned long n = pos >> PAGE_CACHE_SHIFT; 77 unsigned long npages = dir_pages(inode); 78 79 lock_kernel(); 80 81 pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1); 82 if (pos >= inode->i_size) 83 goto done; 84 85 for ( ; n < npages; n++, offset = 0) { 86 char *kaddr, *limit; 87 struct sysv_dir_entry *de; 88 struct page *page = dir_get_page(inode, n); 89 90 if (IS_ERR(page)) 91 continue; 92 kaddr = (char *)page_address(page); 93 de = (struct sysv_dir_entry *)(kaddr+offset); 94 limit = kaddr + PAGE_CACHE_SIZE - SYSV_DIRSIZE; 95 for ( ;(char*)de <= limit; de++) { 96 char *name = de->name; 97 int over; 98 99 if (!de->inode) 100 continue; 101 102 offset = (char *)de - kaddr; 103 104 over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN), 105 ((loff_t)n<<PAGE_CACHE_SHIFT) | offset, 106 fs16_to_cpu(SYSV_SB(sb), de->inode), 107 DT_UNKNOWN); 108 if (over) { 109 dir_put_page(page); 110 goto done; 111 } 112 } 113 dir_put_page(page); 114 } 115 116done: 117 filp->f_pos = ((loff_t)n << PAGE_CACHE_SHIFT) | offset; 118 unlock_kernel(); 119 return 0; 120} 121 122/* compare strings: name[0..len-1] (not zero-terminated) and 123 * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1]) 124 */ 125static inline int namecompare(int len, int maxlen, 126 const char * name, const char * buffer) 127{ 128 if (len < maxlen && buffer[len]) 129 return 0; 130 return !memcmp(name, buffer, len); 131} 132 133/* 134 * sysv_find_entry() 135 * 136 * finds an entry in the specified directory with the wanted name. It 137 * returns the cache buffer in which the entry was found, and the entry 138 * itself (as a parameter - res_dir). It does NOT read the inode of the 139 * entry - you'll have to do that yourself if you want to. 140 */ 141struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page) 142{ 143 const char * name = dentry->d_name.name; 144 int namelen = dentry->d_name.len; 145 struct inode * dir = dentry->d_parent->d_inode; 146 unsigned long start, n; 147 unsigned long npages = dir_pages(dir); 148 struct page *page = NULL; 149 struct sysv_dir_entry *de; 150 151 *res_page = NULL; 152 153 start = SYSV_I(dir)->i_dir_start_lookup; 154 if (start >= npages) 155 start = 0; 156 n = start; 157 158 do { 159 char *kaddr; 160 page = dir_get_page(dir, n); 161 if (!IS_ERR(page)) { 162 kaddr = (char*)page_address(page); 163 de = (struct sysv_dir_entry *) kaddr; 164 kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; 165 for ( ; (char *) de <= kaddr ; de++) { 166 if (!de->inode) 167 continue; 168 if (namecompare(namelen, SYSV_NAMELEN, 169 name, de->name)) 170 goto found; 171 } 172 } 173 dir_put_page(page); 174 175 if (++n >= npages) 176 n = 0; 177 } while (n != start); 178 179 return NULL; 180 181found: 182 SYSV_I(dir)->i_dir_start_lookup = n; 183 *res_page = page; 184 return de; 185} 186 187int sysv_add_link(struct dentry *dentry, struct inode *inode) 188{ 189 struct inode *dir = dentry->d_parent->d_inode; 190 const char * name = dentry->d_name.name; 191 int namelen = dentry->d_name.len; 192 struct page *page = NULL; 193 struct sysv_dir_entry * de; 194 unsigned long npages = dir_pages(dir); 195 unsigned long n; 196 char *kaddr; 197 unsigned from, to; 198 int err; 199 200 /* We take care of directory expansion in the same loop */ 201 for (n = 0; n <= npages; n++) { 202 page = dir_get_page(dir, n); 203 err = PTR_ERR(page); 204 if (IS_ERR(page)) 205 goto out; 206 kaddr = (char*)page_address(page); 207 de = (struct sysv_dir_entry *)kaddr; 208 kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; 209 while ((char *)de <= kaddr) { 210 if (!de->inode) 211 goto got_it; 212 err = -EEXIST; 213 if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) 214 goto out_page; 215 de++; 216 } 217 dir_put_page(page); 218 } 219 BUG(); 220 return -EINVAL; 221 222got_it: 223 from = (char*)de - (char*)page_address(page); 224 to = from + SYSV_DIRSIZE; 225 lock_page(page); 226 err = page->mapping->a_ops->prepare_write(NULL, page, from, to); 227 if (err) 228 goto out_unlock; 229 memcpy (de->name, name, namelen); 230 memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2); 231 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); 232 err = dir_commit_chunk(page, from, to); 233 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 234 mark_inode_dirty(dir); 235out_page: 236 dir_put_page(page); 237out: 238 return err; 239out_unlock: 240 unlock_page(page); 241 goto out_page; 242} 243 244int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page) 245{ 246 struct address_space *mapping = page->mapping; 247 struct inode *inode = (struct inode*)mapping->host; 248 char *kaddr = (char*)page_address(page); 249 unsigned from = (char*)de - kaddr; 250 unsigned to = from + SYSV_DIRSIZE; 251 int err; 252 253 lock_page(page); 254 err = mapping->a_ops->prepare_write(NULL, page, from, to); 255 BUG_ON(err); 256 de->inode = 0; 257 err = dir_commit_chunk(page, from, to); 258 dir_put_page(page); 259 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; 260 mark_inode_dirty(inode); 261 return err; 262} 263 264int sysv_make_empty(struct inode *inode, struct inode *dir) 265{ 266 struct address_space *mapping = inode->i_mapping; 267 struct page *page = grab_cache_page(mapping, 0); 268 struct sysv_dir_entry * de; 269 char *base; 270 int err; 271 272 if (!page) 273 return -ENOMEM; 274 kmap(page); 275 err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * SYSV_DIRSIZE); 276 if (err) { 277 unlock_page(page); 278 goto fail; 279 } 280 281 base = (char*)page_address(page); 282 memset(base, 0, PAGE_CACHE_SIZE); 283 284 de = (struct sysv_dir_entry *) base; 285 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); 286 strcpy(de->name,"."); 287 de++; 288 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), dir->i_ino); 289 strcpy(de->name,".."); 290 291 err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE); 292fail: 293 kunmap(page); 294 page_cache_release(page); 295 return err; 296} 297 298/* 299 * routine to check that the specified directory is empty (for rmdir) 300 */ 301int sysv_empty_dir(struct inode * inode) 302{ 303 struct super_block *sb = inode->i_sb; 304 struct page *page = NULL; 305 unsigned long i, npages = dir_pages(inode); 306 307 for (i = 0; i < npages; i++) { 308 char *kaddr; 309 struct sysv_dir_entry * de; 310 page = dir_get_page(inode, i); 311 312 if (IS_ERR(page)) 313 continue; 314 315 kaddr = (char *)page_address(page); 316 de = (struct sysv_dir_entry *)kaddr; 317 kaddr += PAGE_CACHE_SIZE-SYSV_DIRSIZE; 318 319 for ( ;(char *)de <= kaddr; de++) { 320 if (!de->inode) 321 continue; 322 /* check for . and .. */ 323 if (de->name[0] != '.') 324 goto not_empty; 325 if (!de->name[1]) { 326 if (de->inode == cpu_to_fs16(SYSV_SB(sb), 327 inode->i_ino)) 328 continue; 329 goto not_empty; 330 } 331 if (de->name[1] != '.' || de->name[2]) 332 goto not_empty; 333 } 334 dir_put_page(page); 335 } 336 return 1; 337 338not_empty: 339 dir_put_page(page); 340 return 0; 341} 342 343/* Releases the page */ 344void sysv_set_link(struct sysv_dir_entry *de, struct page *page, 345 struct inode *inode) 346{ 347 struct inode *dir = (struct inode*)page->mapping->host; 348 unsigned from = (char *)de-(char*)page_address(page); 349 unsigned to = from + SYSV_DIRSIZE; 350 int err; 351 352 lock_page(page); 353 err = page->mapping->a_ops->prepare_write(NULL, page, from, to); 354 BUG_ON(err); 355 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); 356 err = dir_commit_chunk(page, from, to); 357 dir_put_page(page); 358 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 359 mark_inode_dirty(dir); 360} 361 362struct sysv_dir_entry * sysv_dotdot (struct inode *dir, struct page **p) 363{ 364 struct page *page = dir_get_page(dir, 0); 365 struct sysv_dir_entry *de = NULL; 366 367 if (!IS_ERR(page)) { 368 de = (struct sysv_dir_entry*) page_address(page) + 1; 369 *p = page; 370 } 371 return de; 372} 373 374ino_t sysv_inode_by_name(struct dentry *dentry) 375{ 376 struct page *page; 377 struct sysv_dir_entry *de = sysv_find_entry (dentry, &page); 378 ino_t res = 0; 379 380 if (de) { 381 res = fs16_to_cpu(SYSV_SB(dentry->d_sb), de->inode); 382 dir_put_page(page); 383 } 384 return res; 385}