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