OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [sysv/] [dir.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.