linux/fs/sysv/dir.c
<<
>>
Prefs
   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
  21static int sysv_readdir(struct file *, struct dir_context *);
  22
  23const 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
  30static inline void dir_put_page(struct page *page)
  31{
  32        kunmap(page);
  33        put_page(page);
  34}
  35
  36static 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
  54static 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
  63static 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 */
 110static 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 */
 126struct 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
 166found:
 167        SYSV_I(dir)->i_dir_start_lookup = n;
 168        *res_page = page;
 169        return de;
 170}
 171
 172int 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
 207got_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);
 220out_page:
 221        dir_put_page(page);
 222out:
 223        return err;
 224out_unlock:
 225        unlock_page(page);
 226        goto out_page;
 227}
 228
 229int 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
 247int 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);
 275fail:
 276        put_page(page);
 277        return err;
 278}
 279
 280/*
 281 * routine to check that the specified directory is empty (for rmdir)
 282 */
 283int 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
 320not_empty:
 321        dir_put_page(page);
 322        return 0;
 323}
 324
 325/* Releases the page */
 326void 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
 344struct 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
 356ino_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