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