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