linux-old/fs/hfsplus/catalog.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/hfsplus/catalog.c
   3 *
   4 * Copyright (C) 2001
   5 * Brad Boyer (flar@allandria.com)
   6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
   7 *
   8 * Handling of catalog records
   9 */
  10
  11#include <linux/sched.h>
  12
  13#include "hfsplus_fs.h"
  14#include "hfsplus_raw.h"
  15
  16int hfsplus_cmp_cat_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2)
  17{
  18        u32 k1p, k2p;
  19
  20        k1p = k1->cat.parent;
  21        k2p = k2->cat.parent;
  22        if (k1p != k2p)
  23                return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1;
  24
  25        return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name);
  26}
  27
  28void hfsplus_fill_cat_key(hfsplus_btree_key *key, u32 parent,
  29                          struct qstr *str)
  30{
  31        int len;
  32
  33        key->cat.parent = cpu_to_be32(parent);
  34        if (str) {
  35                hfsplus_asc2uni(&key->cat.name, str->name, str->len);
  36                len = be16_to_cpu(key->cat.name.length);
  37        } else
  38                len = key->cat.name.length = 0;
  39        key->key_len = cpu_to_be16(6 + 2 * len);
  40}
  41
  42static void hfsplus_fill_cat_key_uni(hfsplus_btree_key *key, u32 parent,
  43                                     hfsplus_unistr *name)
  44{
  45        int ustrlen;
  46
  47        ustrlen = be16_to_cpu(name->length);
  48        key->cat.parent = cpu_to_be32(parent);
  49        key->cat.name.length = cpu_to_be16(ustrlen);
  50        ustrlen *= 2;
  51        memcpy(key->cat.name.unicode, name->unicode, ustrlen);
  52        key->key_len = cpu_to_be16(6 + ustrlen);
  53}
  54
  55static void hfsplus_set_perms(struct inode *inode, hfsplus_perm *perms)
  56{
  57        perms->mode = cpu_to_be32(inode->i_mode);
  58        perms->owner = cpu_to_be32(inode->i_uid);
  59        perms->group = cpu_to_be32(inode->i_gid);
  60}
  61
  62static int hfsplus_fill_cat_entry(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode)
  63{
  64        if (S_ISDIR(inode->i_mode)) {
  65                hfsplus_cat_folder *folder;
  66
  67                folder = &entry->folder;
  68                memset(folder, 0, sizeof(*folder));
  69                folder->type = cpu_to_be16(HFSPLUS_FOLDER);
  70                folder->id = cpu_to_be32(inode->i_ino);
  71                folder->create_date = folder->content_mod_date = 
  72                        folder->attribute_mod_date = folder->access_date = 
  73                        hfsp_now2mt();
  74                hfsplus_set_perms(inode, &folder->permissions);
  75                if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir)
  76                        /* invisible and namelocked */
  77                        folder->user_info.frFlags = cpu_to_be16(0x5000);
  78                return sizeof(*folder);
  79        } else {
  80                hfsplus_cat_file *file;
  81
  82                file = &entry->file;
  83                memset(file, 0, sizeof(*file));
  84                file->type = cpu_to_be16(HFSPLUS_FILE);
  85                file->id = cpu_to_be32(cnid);
  86                file->create_date = file->content_mod_date =
  87                        file->attribute_mod_date = file->access_date =
  88                        hfsp_now2mt();
  89                if (cnid == inode->i_ino) {
  90                        hfsplus_set_perms(inode, &file->permissions);
  91                        file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type);
  92                        file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator);
  93                } else {
  94                        file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE);
  95                        file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR);
  96                        file->user_info.fdFlags = cpu_to_be16(0x100);
  97                        file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev);
  98                }
  99                return sizeof(*file);
 100        }
 101}
 102
 103static int hfsplus_fill_cat_thread(hfsplus_cat_entry *entry, int type,
 104                                   u32 parentid, struct qstr *str)
 105{
 106        entry->type = cpu_to_be16(type);
 107        entry->thread.reserved = 0;
 108        entry->thread.parentID = cpu_to_be32(parentid);
 109        hfsplus_asc2uni(&entry->thread.nodeName, str->name, str->len);
 110        return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2;
 111}
 112
 113/* Try to get a catalog entry for given catalog id */
 114int hfsplus_find_cat(struct super_block *sb, unsigned long cnid,
 115                     struct hfsplus_find_data *fd)
 116{
 117        hfsplus_cat_entry tmp;
 118        int err;
 119        u16 type;
 120
 121        hfsplus_fill_cat_key(fd->search_key, cnid, NULL);
 122        err = hfsplus_btree_find_entry(fd, &tmp, sizeof(hfsplus_cat_entry));
 123        if (err)
 124                return err;
 125
 126        type = be16_to_cpu(tmp.type);
 127        if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) {
 128                printk("HFS+-fs: Found bad thread record in catalog\n");
 129                return -EIO;
 130        }
 131
 132        hfsplus_fill_cat_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID),
 133                                 &tmp.thread.nodeName);
 134        return hfsplus_btree_find(fd);
 135}
 136
 137int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
 138{
 139        struct hfsplus_find_data fd;
 140        struct super_block *sb;
 141        hfsplus_cat_entry entry;
 142        int entry_size;
 143        int err;
 144
 145        dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
 146        sb = dir->i_sb;
 147        hfsplus_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
 148
 149        hfsplus_fill_cat_key(fd.search_key, cnid, NULL);
 150        entry_size = hfsplus_fill_cat_thread(&entry, S_ISDIR(inode->i_mode) ?
 151                        HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
 152                        dir->i_ino, str);
 153        err = hfsplus_btree_find(&fd);
 154        if (err != -ENOENT) {
 155                if (!err)
 156                        err = -EEXIST;
 157                goto out;
 158        }
 159        err = hfsplus_bnode_insert_rec(&fd, &entry, entry_size);
 160        if (err)
 161                goto out;
 162
 163        hfsplus_fill_cat_key(fd.search_key, dir->i_ino, str);
 164        entry_size = hfsplus_fill_cat_entry(&entry, cnid, inode);
 165        err = hfsplus_btree_find(&fd);
 166        if (err != -ENOENT) {
 167                /* panic? */
 168                if (!err)
 169                        err = -EEXIST;
 170                goto out;
 171        }
 172        err = hfsplus_bnode_insert_rec(&fd, &entry, entry_size);
 173        if (!err) {
 174                dir->i_size++;
 175                mark_inode_dirty(dir);
 176        }
 177out:
 178        hfsplus_find_exit(&fd);
 179
 180        return err;
 181}
 182
 183int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
 184{
 185        struct super_block *sb;
 186        struct hfsplus_find_data fd;
 187        hfsplus_fork_raw fork;
 188        struct list_head *pos;
 189        int err, off;
 190        u16 type;
 191
 192        dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
 193        sb = dir->i_sb;
 194        hfsplus_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
 195
 196        if (!str) {
 197                int len;
 198
 199                hfsplus_fill_cat_key(fd.search_key, cnid, NULL);
 200                err = hfsplus_btree_find(&fd);
 201                if (err)
 202                        goto out;
 203
 204                off = fd.entryoffset + offsetof(hfsplus_cat_thread, nodeName);
 205                fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
 206                hfsplus_bnode_readbytes(fd.bnode, &fd.search_key->cat.name.length, off, 2);
 207                len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
 208                hfsplus_bnode_readbytes(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len);
 209                fd.search_key->key_len = cpu_to_be16(6 + len);
 210        } else
 211                hfsplus_fill_cat_key(fd.search_key, dir->i_ino, str);
 212
 213        err = hfsplus_btree_find(&fd);
 214        if (err)
 215                goto out;
 216
 217        type = hfsplus_bnode_read_u16(fd.bnode, fd.entryoffset);
 218        if (type == HFSPLUS_FILE) {
 219#if 0
 220                off = fd.entryoffset + offsetof(hfsplus_cat_file, data_fork);
 221                hfsplus_bnode_readbytes(fd.bnode, &fork, off, sizeof(fork));
 222                hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA);
 223#endif
 224
 225                off = fd.entryoffset + offsetof(hfsplus_cat_file, rsrc_fork);
 226                hfsplus_bnode_readbytes(fd.bnode, &fork, off, sizeof(fork));
 227                hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
 228        }
 229
 230        list_for_each(pos, &HFSPLUS_I(dir).open_dir_list) {
 231                struct hfsplus_readdir_data *rd =
 232                        list_entry(pos, struct hfsplus_readdir_data, list);
 233                if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
 234                        rd->file->f_pos--;
 235        }
 236
 237        err = hfsplus_bnode_remove_rec(&fd);
 238        if (err)
 239                goto out;
 240
 241        hfsplus_fill_cat_key(fd.search_key, cnid, NULL);
 242        err = hfsplus_btree_find(&fd);
 243        if (err)
 244                goto out;
 245
 246        err = hfsplus_bnode_remove_rec(&fd);
 247        if (err) 
 248                goto out;
 249
 250        dir->i_size--;
 251        mark_inode_dirty(dir);
 252out:
 253        hfsplus_find_exit(&fd);
 254
 255        return err;
 256}
 257
 258int hfsplus_rename_cat(u32 cnid,
 259                       struct inode *src_dir, struct qstr *src_name,
 260                       struct inode *dst_dir, struct qstr *dst_name)
 261{
 262        struct super_block *sb;
 263        struct hfsplus_find_data src_fd, dst_fd;
 264        hfsplus_cat_entry entry;
 265        int entry_size, type;
 266        int err = 0;
 267
 268        dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
 269                dst_dir->i_ino, dst_name->name);
 270        sb = src_dir->i_sb;
 271        hfsplus_find_init(HFSPLUS_SB(sb).cat_tree, &src_fd);
 272        dst_fd = src_fd;
 273
 274        /* find the old dir entry and read the data */
 275        hfsplus_fill_cat_key(src_fd.search_key, src_dir->i_ino, src_name);
 276        err = hfsplus_btree_find(&src_fd);
 277        if (err)
 278                goto out;
 279                
 280        hfsplus_bnode_readbytes(src_fd.bnode, &entry, src_fd.entryoffset,
 281                                src_fd.entrylength);
 282
 283        /* create new dir entry with the data from the old entry */
 284        hfsplus_fill_cat_key(dst_fd.search_key, dst_dir->i_ino, dst_name);
 285        err = hfsplus_btree_find(&dst_fd);
 286        if (err != -ENOENT) {
 287                if (!err)
 288                        err = -EEXIST;
 289                goto out;
 290        }
 291
 292        err = hfsplus_bnode_insert_rec(&dst_fd, &entry, src_fd.entrylength);
 293        if (err)
 294                goto out;
 295        dst_dir->i_size++;
 296        mark_inode_dirty(dst_dir);
 297
 298        /* finally remove the old entry */
 299        hfsplus_fill_cat_key(src_fd.search_key, src_dir->i_ino, src_name);
 300        err = hfsplus_btree_find(&src_fd);
 301        if (err)
 302                goto out;
 303        err = hfsplus_bnode_remove_rec(&src_fd);
 304        if (err)
 305                goto out;
 306        src_dir->i_size--;
 307        mark_inode_dirty(src_dir);
 308
 309        /* remove old thread entry */
 310        hfsplus_fill_cat_key(src_fd.search_key, cnid, NULL);
 311        err = hfsplus_btree_find(&src_fd);
 312        if (err)
 313                goto out;
 314        type = hfsplus_bnode_read_u16(src_fd.bnode, src_fd.entryoffset);
 315        err = hfsplus_bnode_remove_rec(&src_fd);
 316        if (err)
 317                goto out;
 318
 319        /* create new thread entry */
 320        hfsplus_fill_cat_key(dst_fd.search_key, cnid, NULL);
 321        entry_size = hfsplus_fill_cat_thread(&entry, type, dst_dir->i_ino, dst_name);
 322        err = hfsplus_btree_find(&dst_fd);
 323        if (err != -ENOENT) {
 324                if (!err)
 325                        err = -EEXIST;
 326                goto out;
 327        }
 328        err = hfsplus_bnode_insert_rec(&dst_fd, &entry, entry_size);
 329out:
 330        hfsplus_put_bnode(dst_fd.bnode);
 331        hfsplus_find_exit(&src_fd);
 332        return err;
 333}
 334
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.