Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/fs/sysv/dir.c
0004  *
0005  *  minix/dir.c
0006  *  Copyright (C) 1991, 1992  Linus Torvalds
0007  *
0008  *  coh/dir.c
0009  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
0010  *
0011  *  sysv/dir.c
0012  *  Copyright (C) 1993  Bruno Haible
0013  *
0014  *  SystemV/Coherent directory handling functions
0015  */
0016 
0017 #include <linux/pagemap.h>
0018 #include <linux/highmem.h>
0019 #include <linux/swap.h>
0020 #include "sysv.h"
0021 
0022 static int sysv_readdir(struct file *, struct dir_context *);
0023 
0024 const struct file_operations sysv_dir_operations = {
0025     .llseek     = generic_file_llseek,
0026     .read       = generic_read_dir,
0027     .iterate_shared = sysv_readdir,
0028     .fsync      = generic_file_fsync,
0029 };
0030 
0031 static inline void dir_put_page(struct page *page)
0032 {
0033     kunmap(page);
0034     put_page(page);
0035 }
0036 
0037 static int dir_commit_chunk(struct page *page, loff_t pos, unsigned len)
0038 {
0039     struct address_space *mapping = page->mapping;
0040     struct inode *dir = mapping->host;
0041     int err = 0;
0042 
0043     block_write_end(NULL, mapping, pos, len, len, page, NULL);
0044     if (pos+len > dir->i_size) {
0045         i_size_write(dir, pos+len);
0046         mark_inode_dirty(dir);
0047     }
0048     if (IS_DIRSYNC(dir))
0049         err = write_one_page(page);
0050     else
0051         unlock_page(page);
0052     return err;
0053 }
0054 
0055 static struct page * dir_get_page(struct inode *dir, unsigned long n)
0056 {
0057     struct address_space *mapping = dir->i_mapping;
0058     struct page *page = read_mapping_page(mapping, n, NULL);
0059     if (!IS_ERR(page))
0060         kmap(page);
0061     return page;
0062 }
0063 
0064 static int sysv_readdir(struct file *file, struct dir_context *ctx)
0065 {
0066     unsigned long pos = ctx->pos;
0067     struct inode *inode = file_inode(file);
0068     struct super_block *sb = inode->i_sb;
0069     unsigned long npages = dir_pages(inode);
0070     unsigned offset;
0071     unsigned long n;
0072 
0073     ctx->pos = pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
0074     if (pos >= inode->i_size)
0075         return 0;
0076 
0077     offset = pos & ~PAGE_MASK;
0078     n = pos >> PAGE_SHIFT;
0079 
0080     for ( ; n < npages; n++, offset = 0) {
0081         char *kaddr, *limit;
0082         struct sysv_dir_entry *de;
0083         struct page *page = dir_get_page(inode, n);
0084 
0085         if (IS_ERR(page))
0086             continue;
0087         kaddr = (char *)page_address(page);
0088         de = (struct sysv_dir_entry *)(kaddr+offset);
0089         limit = kaddr + PAGE_SIZE - SYSV_DIRSIZE;
0090         for ( ;(char*)de <= limit; de++, ctx->pos += sizeof(*de)) {
0091             char *name = de->name;
0092 
0093             if (!de->inode)
0094                 continue;
0095 
0096             if (!dir_emit(ctx, name, strnlen(name,SYSV_NAMELEN),
0097                     fs16_to_cpu(SYSV_SB(sb), de->inode),
0098                     DT_UNKNOWN)) {
0099                 dir_put_page(page);
0100                 return 0;
0101             }
0102         }
0103         dir_put_page(page);
0104     }
0105     return 0;
0106 }
0107 
0108 /* compare strings: name[0..len-1] (not zero-terminated) and
0109  * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
0110  */
0111 static inline int namecompare(int len, int maxlen,
0112     const char * name, const char * buffer)
0113 {
0114     if (len < maxlen && buffer[len])
0115         return 0;
0116     return !memcmp(name, buffer, len);
0117 }
0118 
0119 /*
0120  *  sysv_find_entry()
0121  *
0122  * finds an entry in the specified directory with the wanted name. It
0123  * returns the cache buffer in which the entry was found, and the entry
0124  * itself (as a parameter - res_dir). It does NOT read the inode of the
0125  * entry - you'll have to do that yourself if you want to.
0126  */
0127 struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page)
0128 {
0129     const char * name = dentry->d_name.name;
0130     int namelen = dentry->d_name.len;
0131     struct inode * dir = d_inode(dentry->d_parent);
0132     unsigned long start, n;
0133     unsigned long npages = dir_pages(dir);
0134     struct page *page = NULL;
0135     struct sysv_dir_entry *de;
0136 
0137     *res_page = NULL;
0138 
0139     start = SYSV_I(dir)->i_dir_start_lookup;
0140     if (start >= npages)
0141         start = 0;
0142     n = start;
0143 
0144     do {
0145         char *kaddr;
0146         page = dir_get_page(dir, n);
0147         if (!IS_ERR(page)) {
0148             kaddr = (char*)page_address(page);
0149             de = (struct sysv_dir_entry *) kaddr;
0150             kaddr += PAGE_SIZE - SYSV_DIRSIZE;
0151             for ( ; (char *) de <= kaddr ; de++) {
0152                 if (!de->inode)
0153                     continue;
0154                 if (namecompare(namelen, SYSV_NAMELEN,
0155                             name, de->name))
0156                     goto found;
0157             }
0158             dir_put_page(page);
0159         }
0160 
0161         if (++n >= npages)
0162             n = 0;
0163     } while (n != start);
0164 
0165     return NULL;
0166 
0167 found:
0168     SYSV_I(dir)->i_dir_start_lookup = n;
0169     *res_page = page;
0170     return de;
0171 }
0172 
0173 int sysv_add_link(struct dentry *dentry, struct inode *inode)
0174 {
0175     struct inode *dir = d_inode(dentry->d_parent);
0176     const char * name = dentry->d_name.name;
0177     int namelen = dentry->d_name.len;
0178     struct page *page = NULL;
0179     struct sysv_dir_entry * de;
0180     unsigned long npages = dir_pages(dir);
0181     unsigned long n;
0182     char *kaddr;
0183     loff_t pos;
0184     int err;
0185 
0186     /* We take care of directory expansion in the same loop */
0187     for (n = 0; n <= npages; n++) {
0188         page = dir_get_page(dir, n);
0189         err = PTR_ERR(page);
0190         if (IS_ERR(page))
0191             goto out;
0192         kaddr = (char*)page_address(page);
0193         de = (struct sysv_dir_entry *)kaddr;
0194         kaddr += PAGE_SIZE - SYSV_DIRSIZE;
0195         while ((char *)de <= kaddr) {
0196             if (!de->inode)
0197                 goto got_it;
0198             err = -EEXIST;
0199             if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) 
0200                 goto out_page;
0201             de++;
0202         }
0203         dir_put_page(page);
0204     }
0205     BUG();
0206     return -EINVAL;
0207 
0208 got_it:
0209     pos = page_offset(page) +
0210             (char*)de - (char*)page_address(page);
0211     lock_page(page);
0212     err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
0213     if (err)
0214         goto out_unlock;
0215     memcpy (de->name, name, namelen);
0216     memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
0217     de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
0218     err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
0219     dir->i_mtime = dir->i_ctime = current_time(dir);
0220     mark_inode_dirty(dir);
0221 out_page:
0222     dir_put_page(page);
0223 out:
0224     return err;
0225 out_unlock:
0226     unlock_page(page);
0227     goto out_page;
0228 }
0229 
0230 int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
0231 {
0232     struct inode *inode = page->mapping->host;
0233     char *kaddr = (char*)page_address(page);
0234     loff_t pos = page_offset(page) + (char *)de - kaddr;
0235     int err;
0236 
0237     lock_page(page);
0238     err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
0239     BUG_ON(err);
0240     de->inode = 0;
0241     err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
0242     dir_put_page(page);
0243     inode->i_ctime = inode->i_mtime = current_time(inode);
0244     mark_inode_dirty(inode);
0245     return err;
0246 }
0247 
0248 int sysv_make_empty(struct inode *inode, struct inode *dir)
0249 {
0250     struct page *page = grab_cache_page(inode->i_mapping, 0);
0251     struct sysv_dir_entry * de;
0252     char *base;
0253     int err;
0254 
0255     if (!page)
0256         return -ENOMEM;
0257     err = sysv_prepare_chunk(page, 0, 2 * SYSV_DIRSIZE);
0258     if (err) {
0259         unlock_page(page);
0260         goto fail;
0261     }
0262     kmap(page);
0263 
0264     base = (char*)page_address(page);
0265     memset(base, 0, PAGE_SIZE);
0266 
0267     de = (struct sysv_dir_entry *) base;
0268     de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
0269     strcpy(de->name,".");
0270     de++;
0271     de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), dir->i_ino);
0272     strcpy(de->name,"..");
0273 
0274     kunmap(page);
0275     err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE);
0276 fail:
0277     put_page(page);
0278     return err;
0279 }
0280 
0281 /*
0282  * routine to check that the specified directory is empty (for rmdir)
0283  */
0284 int sysv_empty_dir(struct inode * inode)
0285 {
0286     struct super_block *sb = inode->i_sb;
0287     struct page *page = NULL;
0288     unsigned long i, npages = dir_pages(inode);
0289 
0290     for (i = 0; i < npages; i++) {
0291         char *kaddr;
0292         struct sysv_dir_entry * de;
0293         page = dir_get_page(inode, i);
0294 
0295         if (IS_ERR(page))
0296             continue;
0297 
0298         kaddr = (char *)page_address(page);
0299         de = (struct sysv_dir_entry *)kaddr;
0300         kaddr += PAGE_SIZE-SYSV_DIRSIZE;
0301 
0302         for ( ;(char *)de <= kaddr; de++) {
0303             if (!de->inode)
0304                 continue;
0305             /* check for . and .. */
0306             if (de->name[0] != '.')
0307                 goto not_empty;
0308             if (!de->name[1]) {
0309                 if (de->inode == cpu_to_fs16(SYSV_SB(sb),
0310                             inode->i_ino))
0311                     continue;
0312                 goto not_empty;
0313             }
0314             if (de->name[1] != '.' || de->name[2])
0315                 goto not_empty;
0316         }
0317         dir_put_page(page);
0318     }
0319     return 1;
0320 
0321 not_empty:
0322     dir_put_page(page);
0323     return 0;
0324 }
0325 
0326 /* Releases the page */
0327 void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
0328     struct inode *inode)
0329 {
0330     struct inode *dir = page->mapping->host;
0331     loff_t pos = page_offset(page) +
0332             (char *)de-(char*)page_address(page);
0333     int err;
0334 
0335     lock_page(page);
0336     err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
0337     BUG_ON(err);
0338     de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
0339     err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
0340     dir_put_page(page);
0341     dir->i_mtime = dir->i_ctime = current_time(dir);
0342     mark_inode_dirty(dir);
0343 }
0344 
0345 struct sysv_dir_entry * sysv_dotdot (struct inode *dir, struct page **p)
0346 {
0347     struct page *page = dir_get_page(dir, 0);
0348     struct sysv_dir_entry *de = NULL;
0349 
0350     if (!IS_ERR(page)) {
0351         de = (struct sysv_dir_entry*) page_address(page) + 1;
0352         *p = page;
0353     }
0354     return de;
0355 }
0356 
0357 ino_t sysv_inode_by_name(struct dentry *dentry)
0358 {
0359     struct page *page;
0360     struct sysv_dir_entry *de = sysv_find_entry (dentry, &page);
0361     ino_t res = 0;
0362     
0363     if (de) {
0364         res = fs16_to_cpu(SYSV_SB(dentry->d_sb), de->inode);
0365         dir_put_page(page);
0366     }
0367     return res;
0368 }