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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/hfsplus/inode.c
3
 *
4
 * Copyright (C) 2001
5
 * Brad Boyer (flar@allandria.com)
6
 * (C) 2003 Ardis Technologies <roman@ardistech.com>
7
 *
8
 * Inode handling routines
9
 */
10
 
11
#include <linux/mm.h>
12
#include <linux/fs.h>
13
#include <linux/pagemap.h>
14
#include <linux/version.h>
15
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
16
#include <linux/buffer_head.h>
17
#endif
18
 
19
#include "hfsplus_fs.h"
20
#include "hfsplus_raw.h"
21
 
22
static int hfsplus_readpage(struct file *file, struct page *page)
23
{
24
        //printk("readpage: %lu\n", page->index);
25
        return block_read_full_page(page, hfsplus_get_block);
26
}
27
 
28
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
29
static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
30
{
31
        //printk("writepage: %lu\n", page->index);
32
        return block_write_full_page(page, hfsplus_get_block, wbc);
33
}
34
#else
35
static int hfsplus_writepage(struct page *page)
36
{
37
        //printk("writepage: %lu\n", page->index);
38
        return block_write_full_page(page, hfsplus_get_block);
39
}
40
#endif
41
 
42
static int hfsplus_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
43
{
44
        return cont_prepare_write(page, from, to, hfsplus_get_block,
45
                &HFSPLUS_I(page->mapping->host).mmu_private);
46
}
47
 
48
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
49
static int hfsplus_bmap(struct address_space *mapping, long block)
50
#else
51
static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
52
#endif
53
{
54
        return generic_block_bmap(mapping, block, hfsplus_get_block);
55
}
56
 
57
int hfsplus_releasepage(struct page *page, int mask)
58
{
59
        struct inode *inode = page->mapping->host;
60
        struct super_block *sb = inode->i_sb;
61
        struct hfsplus_btree *tree;
62
        hfsplus_bnode *node;
63
        u32 nidx;
64
        int i, res = 1;
65
 
66
        switch (inode->i_ino) {
67
        case HFSPLUS_EXT_CNID:
68
                tree = HFSPLUS_SB(sb).ext_tree;
69
                break;
70
        case HFSPLUS_CAT_CNID:
71
                tree = HFSPLUS_SB(sb).cat_tree;
72
                break;
73
        case HFSPLUS_ATTR_CNID:
74
                tree = HFSPLUS_SB(sb).attr_tree;
75
                break;
76
        default:
77
                BUG();
78
                return 0;
79
        }
80
        if (tree->node_size >= PAGE_CACHE_SIZE) {
81
                nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
82
                spin_lock(&tree->hash_lock);
83
                node = __hfsplus_find_bnode(tree, nidx);
84
                if (!node)
85
                        ;
86
                else if (atomic_read(&node->refcnt))
87
                        res = 0;
88
                else for (i = 0; i < tree->pages_per_bnode; i++) {
89
                        if (PageActive(node->page[i])) {
90
                                res = 0;
91
                                break;
92
                        }
93
                }
94
                if (res && node) {
95
                        __hfsplus_bnode_remove(node);
96
                        hfsplus_bnode_free(node);
97
                }
98
                spin_unlock(&tree->hash_lock);
99
        } else {
100
                nidx = page->index >> (PAGE_CACHE_SHIFT - tree->node_size_shift);
101
                i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
102
                spin_lock(&tree->hash_lock);
103
                do {
104
                        node = __hfsplus_find_bnode(tree, nidx++);
105
                        if (!node)
106
                                continue;
107
                        if (atomic_read(&node->refcnt)) {
108
                                res = 0;
109
                                break;
110
                        }
111
                        __hfsplus_bnode_remove(node);
112
                        hfsplus_bnode_free(node);
113
                } while (--i);
114
                spin_unlock(&tree->hash_lock);
115
        }
116
        //printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
117
        return res;
118
}
119
 
120
struct address_space_operations hfsplus_btree_aops = {
121
        .readpage       = hfsplus_readpage,
122
        .writepage      = hfsplus_writepage,
123
        .sync_page      = block_sync_page,
124
        .prepare_write  = hfsplus_prepare_write,
125
        .commit_write   = generic_commit_write,
126
        .bmap           = hfsplus_bmap,
127
        .releasepage    = hfsplus_releasepage,
128
};
129
 
130
struct address_space_operations hfsplus_aops = {
131
        .readpage       = hfsplus_readpage,
132
        .writepage      = hfsplus_writepage,
133
        .sync_page      = block_sync_page,
134
        .prepare_write  = hfsplus_prepare_write,
135
        .commit_write   = generic_commit_write,
136
        .bmap           = hfsplus_bmap,
137
};
138
 
139
static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry)
140
{
141
        struct hfsplus_find_data fd;
142
        struct super_block *sb = dir->i_sb;
143
        struct inode *inode = NULL;
144
        int err;
145
 
146
        if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
147
                goto out;
148
 
149
        inode = HFSPLUS_I(dir).rsrc_inode;
150
        if (inode)
151
                goto out;
152
 
153
        inode = new_inode(sb);
154
        if (!inode)
155
                return ERR_PTR(-ENOMEM);
156
 
157
        inode->i_ino = dir->i_ino;
158
        HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC;
159
 
160
        hfsplus_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
161
        err = hfsplus_find_cat(sb, dir->i_ino, &fd);
162
        if (!err)
163
                err = hfsplus_cat_read_inode(inode, &fd);
164
        hfsplus_find_exit(&fd);
165
        if (err) {
166
                iput(inode);
167
                return ERR_PTR(err);
168
        }
169
        HFSPLUS_I(inode).rsrc_inode = dir;
170
        HFSPLUS_I(dir).rsrc_inode = inode;
171
        igrab(dir);
172
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
173
        list_add(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes);
174
#else
175
        hlist_add_head(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes);
176
#endif
177
        mark_inode_dirty(inode);
178
        {
179
        void hfsplus_inode_check(struct super_block *sb);
180
        atomic_inc(&HFSPLUS_SB(sb).inode_cnt);
181
        hfsplus_inode_check(sb);
182
        }
183
out:
184
        d_add(dentry, inode);
185
        return NULL;
186
}
187
 
188
static void hfsplus_get_perms(struct inode *inode, hfsplus_perm *perms, int dir)
189
{
190
        struct super_block *sb = inode->i_sb;
191
        int mode;
192
 
193
        mode = be32_to_cpu(perms->mode) & 0xffff;
194
 
195
        inode->i_uid = be32_to_cpu(perms->owner);
196
        if (!inode->i_uid && !mode)
197
                inode->i_uid = HFSPLUS_SB(sb).uid;
198
 
199
        inode->i_gid = be32_to_cpu(perms->group);
200
        if (!inode->i_gid && !mode)
201
                inode->i_gid = HFSPLUS_SB(sb).gid;
202
 
203
        if (dir) {
204
                mode = mode ? (mode & S_IALLUGO) :
205
                        (S_IRWXUGO & ~(HFSPLUS_SB(sb).umask));
206
                mode |= S_IFDIR;
207
        } else if (!mode)
208
                mode = S_IFREG | ((S_IRUGO|S_IWUGO) &
209
                        ~(HFSPLUS_SB(sb).umask));
210
        inode->i_mode = mode;
211
}
212
 
213
static void hfsplus_set_perms(struct inode *inode, hfsplus_perm *perms)
214
{
215
        perms->mode = cpu_to_be32(inode->i_mode);
216
        perms->owner = cpu_to_be32(inode->i_uid);
217
        perms->group = cpu_to_be32(inode->i_gid);
218
        perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
219
}
220
 
221
static int hfsplus_file_open(struct inode *inode, struct file *file)
222
{
223
        if (HFSPLUS_IS_RSRC(inode))
224
                inode = HFSPLUS_I(inode).rsrc_inode;
225
        if (atomic_read(&file->f_count) != 1)
226
                return 0;
227
        atomic_inc(&HFSPLUS_I(inode).opencnt);
228
        return 0;
229
}
230
 
231
static int hfsplus_file_release(struct inode *inode, struct file *file)
232
{
233
        struct super_block *sb = inode->i_sb;
234
 
235
        if (HFSPLUS_IS_RSRC(inode))
236
                inode = HFSPLUS_I(inode).rsrc_inode;
237
        if (atomic_read(&file->f_count) != 0)
238
                return 0;
239
        if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) {
240
                down(&inode->i_sem);
241
                if (inode->i_flags & S_DEAD) {
242
                        hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL);
243
                        hfsplus_delete_inode(inode);
244
                }
245
                up(&inode->i_sem);
246
        }
247
        return 0;
248
}
249
 
250
extern struct inode_operations hfsplus_dir_inode_operations;
251
extern struct file_operations hfsplus_dir_operations;
252
 
253
struct inode_operations hfsplus_file_inode_operations = {
254
        .lookup         = hfsplus_file_lookup,
255
        .truncate       = hfsplus_truncate,
256
};
257
 
258
struct file_operations hfsplus_file_operations = {
259
        .llseek         = generic_file_llseek,
260
        .read           = generic_file_read,
261
        //.write        = hfsplus_file_write,
262
        .write          = generic_file_write,
263
        .mmap           = generic_file_mmap,
264
        .fsync          = file_fsync,
265
        .open           = hfsplus_file_open,
266
        .release        = hfsplus_file_release,
267
};
268
 
269
struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
270
{
271
        struct inode *inode = new_inode(sb);
272
        if (!inode)
273
                return NULL;
274
 
275
        {
276
        void hfsplus_inode_check(struct super_block *sb);
277
        atomic_inc(&HFSPLUS_SB(sb).inode_cnt);
278
        hfsplus_inode_check(sb);
279
        }
280
        inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
281
        inode->i_mode = mode;
282
        inode->i_uid = current->fsuid;
283
        inode->i_gid = current->fsgid;
284
        inode->i_nlink = 1;
285
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
286
        if (S_ISDIR(inode->i_mode)) {
287
                inode->i_size = 2;
288
                HFSPLUS_SB(sb).folder_count++;
289
                inode->i_op = &hfsplus_dir_inode_operations;
290
                inode->i_fop = &hfsplus_dir_operations;
291
                INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
292
        } else if (S_ISREG(inode->i_mode)) {
293
                HFSPLUS_SB(sb).file_count++;
294
                inode->i_op = &hfsplus_file_inode_operations;
295
                inode->i_fop = &hfsplus_file_operations;
296
                inode->i_mapping->a_ops = &hfsplus_aops;
297
        } else if (S_ISLNK(inode->i_mode)) {
298
                HFSPLUS_SB(sb).file_count++;
299
                inode->i_op = &page_symlink_inode_operations;
300
                inode->i_mapping->a_ops = &hfsplus_aops;
301
        } else
302
                HFSPLUS_SB(sb).file_count++;
303
        insert_inode_hash(inode);
304
        mark_inode_dirty(inode);
305
        sb->s_dirt = 1;
306
 
307
        return inode;
308
}
309
 
310
void hfsplus_delete_inode(struct inode *inode)
311
{
312
        struct super_block *sb = inode->i_sb;
313
 
314
        if (S_ISDIR(inode->i_mode)) {
315
                HFSPLUS_SB(sb).folder_count--;
316
                sb->s_dirt = 1;
317
                return;
318
        }
319
        HFSPLUS_SB(sb).file_count--;
320
        if (S_ISREG(inode->i_mode)) {
321
                if (!inode->i_nlink) {
322
                        inode->i_size = 0;
323
                        hfsplus_truncate(inode);
324
                }
325
        } else if (S_ISLNK(inode->i_mode)) {
326
                inode->i_size = 0;
327
                hfsplus_truncate(inode);
328
        }
329
        sb->s_dirt = 1;
330
}
331
 
332
void hfsplus_inode_read_fork(struct inode *inode, hfsplus_fork_raw *fork)
333
{
334
        u32 count;
335
        int i;
336
 
337
        memcpy(&HFSPLUS_I(inode).extents, &fork->extents,
338
               sizeof(hfsplus_extent_rec));
339
        for (count = 0, i = 0; i < 8; i++)
340
                count += be32_to_cpu(fork->extents[i].block_count);
341
        HFSPLUS_I(inode).extent_blocks = count;
342
        HFSPLUS_I(inode).total_blocks = HFSPLUS_I(inode).alloc_blocks =
343
                be32_to_cpu(fork->total_blocks);
344
        inode->i_size = HFSPLUS_I(inode).mmu_private = be64_to_cpu(fork->total_size);
345
        inode->i_blocks = be32_to_cpu(fork->total_blocks);
346
}
347
 
348
void hfsplus_inode_write_fork(struct inode *inode, hfsplus_fork_raw *fork)
349
{
350
        memcpy(&fork->extents, &HFSPLUS_I(inode).extents,
351
               sizeof(hfsplus_extent_rec));
352
        fork->total_size = cpu_to_be64(inode->i_size);
353
        fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode).alloc_blocks);
354
}
355
 
356
int hfsplus_cat_read_inode(struct inode *inode, struct hfsplus_find_data *fd)
357
{
358
        hfsplus_cat_entry entry;
359
        int res = 0;
360
        u16 type;
361
 
362
        type = hfsplus_bnode_read_u16(fd->bnode, fd->entryoffset);
363
 
364
        HFSPLUS_I(inode).dev = 0;
365
        inode->i_blksize = PAGE_SIZE; /* Doesn't seem to be useful... */
366
        if (type == HFSPLUS_FOLDER) {
367
                hfsplus_cat_folder *folder = &entry.folder;
368
 
369
                if (fd->entrylength < sizeof(hfsplus_cat_folder))
370
                        /* panic? */;
371
                hfsplus_bnode_readbytes(fd->bnode, &entry, fd->entryoffset,
372
                                        sizeof(hfsplus_cat_folder));
373
                memset(&HFSPLUS_I(inode).extents, 0,
374
                       sizeof(hfsplus_extent_rec));
375
                hfsplus_get_perms(inode, &folder->permissions, 1);
376
                inode->i_nlink = 1;
377
                inode->i_size = 2 + be32_to_cpu(folder->valence);
378
                inode->i_atime = hfsp_mt2ut(folder->access_date);
379
                inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
380
                inode->i_ctime = inode->i_mtime;
381
                inode->i_blocks = 0;
382
                inode->i_op = &hfsplus_dir_inode_operations;
383
                inode->i_fop = &hfsplus_dir_operations;
384
                INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
385
        } else if (type == HFSPLUS_FILE) {
386
                hfsplus_cat_file *file = &entry.file;
387
 
388
                if (fd->entrylength < sizeof(hfsplus_cat_file))
389
                        /* panic? */;
390
                hfsplus_bnode_readbytes(fd->bnode, &entry, fd->entryoffset,
391
                                        sizeof(hfsplus_cat_file));
392
 
393
                hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ?
394
                                        &file->data_fork : &file->rsrc_fork);
395
                hfsplus_get_perms(inode, &file->permissions, 0);
396
                inode->i_nlink = 1;
397
                if (S_ISREG(inode->i_mode)) {
398
                        if (file->permissions.dev)
399
                                inode->i_nlink = be32_to_cpu(file->permissions.dev);
400
                        inode->i_op = &hfsplus_file_inode_operations;
401
                        inode->i_fop = &hfsplus_file_operations;
402
                        inode->i_mapping->a_ops = &hfsplus_aops;
403
                } else if (S_ISLNK(inode->i_mode)) {
404
                        inode->i_op = &page_symlink_inode_operations;
405
                        inode->i_mapping->a_ops = &hfsplus_aops;
406
                } else {
407
                        init_special_inode(inode, inode->i_mode,
408
                                           be32_to_cpu(file->permissions.dev));
409
                }
410
                inode->i_atime = hfsp_mt2ut(file->access_date);
411
                inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
412
                inode->i_ctime = inode->i_mtime;
413
        } else {
414
                printk("HFS+-fs: bad catalog entry used to create inode\n");
415
                res = -EIO;
416
        }
417
        return res;
418
}
419
 
420
void hfsplus_cat_write_inode(struct inode *inode)
421
{
422
        struct hfsplus_find_data fd;
423
        hfsplus_cat_entry entry;
424
 
425
        if (HFSPLUS_IS_RSRC(inode)) {
426
                mark_inode_dirty(HFSPLUS_I(inode).rsrc_inode);
427
                return;
428
        }
429
 
430
        if (!inode->i_nlink)
431
                return;
432
 
433
        if (hfsplus_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd))
434
                /* panic? */
435
                return;
436
 
437
        if (hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd))
438
                /* panic? */
439
                goto out;
440
 
441
        if (S_ISDIR(inode->i_mode)) {
442
                hfsplus_cat_folder *folder = &entry.folder;
443
 
444
                if (fd.entrylength < sizeof(hfsplus_cat_folder))
445
                        /* panic? */;
446
                hfsplus_bnode_readbytes(fd.bnode, &entry, fd.entryoffset,
447
                                        sizeof(hfsplus_cat_folder));
448
                /* simple node checks? */
449
                hfsplus_set_perms(inode, &folder->permissions);
450
                folder->access_date = hfsp_ut2mt(inode->i_atime);
451
                folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
452
                folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
453
                folder->valence = cpu_to_be32(inode->i_size - 2);
454
                hfsplus_bnode_writebytes(fd.bnode, &entry, fd.entryoffset,
455
                                         sizeof(hfsplus_cat_folder));
456
        } else {
457
                hfsplus_cat_file *file = &entry.file;
458
 
459
                if (fd.entrylength < sizeof(hfsplus_cat_file))
460
                        /* panic? */;
461
                hfsplus_bnode_readbytes(fd.bnode, &entry, fd.entryoffset,
462
                                        sizeof(hfsplus_cat_file));
463
                hfsplus_inode_write_fork(inode, &file->data_fork);
464
                if (HFSPLUS_I(inode).rsrc_inode)
465
                        hfsplus_inode_write_fork(HFSPLUS_I(inode).rsrc_inode, &file->rsrc_fork);
466
                if (S_ISREG(inode->i_mode))
467
                        HFSPLUS_I(inode).dev = inode->i_nlink;
468
                if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
469
                        HFSPLUS_I(inode).dev = kdev_t_to_nr(inode->i_rdev);
470
                hfsplus_set_perms(inode, &file->permissions);
471
                file->access_date = hfsp_ut2mt(inode->i_atime);
472
                file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
473
                file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
474
                hfsplus_bnode_writebytes(fd.bnode, &entry, fd.entryoffset,
475
                                         sizeof(hfsplus_cat_file));
476
        }
477
out:
478
        hfsplus_find_exit(&fd);
479
}

powered by: WebSVN 2.1.0

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