11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/hfsplus/brec.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 51da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 61da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Handle individual btree records 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include "hfsplus_fs.h" 121da177e4SLinus Torvalds #include "hfsplus_raw.h" 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd); 151da177e4SLinus Torvalds static int hfs_brec_update_parent(struct hfs_find_data *fd); 161da177e4SLinus Torvalds static int hfs_btree_inc_height(struct hfs_btree *); 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds /* Get the length and offset of the given record in the given node */ 191da177e4SLinus Torvalds u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off) 201da177e4SLinus Torvalds { 211da177e4SLinus Torvalds __be16 retval[2]; 221da177e4SLinus Torvalds u16 dataoff; 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds dataoff = node->tree->node_size - (rec + 2) * 2; 251da177e4SLinus Torvalds hfs_bnode_read(node, retval, dataoff, 4); 261da177e4SLinus Torvalds *off = be16_to_cpu(retval[1]); 271da177e4SLinus Torvalds return be16_to_cpu(retval[0]) - *off; 281da177e4SLinus Torvalds } 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* Get the length of the key from a keyed record */ 311da177e4SLinus Torvalds u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec) 321da177e4SLinus Torvalds { 331da177e4SLinus Torvalds u16 retval, recoff; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds if (node->type != HFS_NODE_INDEX && node->type != HFS_NODE_LEAF) 361da177e4SLinus Torvalds return 0; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds if ((node->type == HFS_NODE_INDEX) && 39324ef39aSVyacheslav Dubeyko !(node->tree->attributes & HFS_TREE_VARIDXKEYS) && 40324ef39aSVyacheslav Dubeyko (node->tree->cnid != HFSPLUS_ATTR_CNID)) { 411da177e4SLinus Torvalds retval = node->tree->max_key_len + 2; 421da177e4SLinus Torvalds } else { 432753cc28SAnton Salikhmetov recoff = hfs_bnode_read_u16(node, 442753cc28SAnton Salikhmetov node->tree->node_size - (rec + 1) * 2); 451da177e4SLinus Torvalds if (!recoff) 461da177e4SLinus Torvalds return 0; 47aac4e419SNaohiro Aota if (recoff > node->tree->node_size - 2) { 48d6142673SJoe Perches pr_err("recoff %d too large\n", recoff); 49aac4e419SNaohiro Aota return 0; 50aac4e419SNaohiro Aota } 5113571a69SChristoph Hellwig 521da177e4SLinus Torvalds retval = hfs_bnode_read_u16(node, recoff) + 2; 539250f925SEric Sandeen if (retval > node->tree->max_key_len + 2) { 54d6142673SJoe Perches pr_err("keylen %d too large\n", 559250f925SEric Sandeen retval); 569250f925SEric Sandeen retval = 0; 579250f925SEric Sandeen } 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds return retval; 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len) 631da177e4SLinus Torvalds { 641da177e4SLinus Torvalds struct hfs_btree *tree; 651da177e4SLinus Torvalds struct hfs_bnode *node, *new_node; 661da177e4SLinus Torvalds int size, key_len, rec; 671da177e4SLinus Torvalds int data_off, end_off; 681da177e4SLinus Torvalds int idx_rec_off, data_rec_off, end_rec_off; 691da177e4SLinus Torvalds __be32 cnid; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds tree = fd->tree; 721da177e4SLinus Torvalds if (!fd->bnode) { 731da177e4SLinus Torvalds if (!tree->root) 741da177e4SLinus Torvalds hfs_btree_inc_height(tree); 751da177e4SLinus Torvalds fd->bnode = hfs_bnode_find(tree, tree->leaf_head); 761da177e4SLinus Torvalds if (IS_ERR(fd->bnode)) 771da177e4SLinus Torvalds return PTR_ERR(fd->bnode); 781da177e4SLinus Torvalds fd->record = -1; 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds new_node = NULL; 811da177e4SLinus Torvalds key_len = be16_to_cpu(fd->search_key->key_len) + 2; 821da177e4SLinus Torvalds again: 831da177e4SLinus Torvalds /* new record idx and complete record size */ 841da177e4SLinus Torvalds rec = fd->record + 1; 851da177e4SLinus Torvalds size = key_len + entry_len; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds node = fd->bnode; 881da177e4SLinus Torvalds hfs_bnode_dump(node); 891da177e4SLinus Torvalds /* get last offset */ 901da177e4SLinus Torvalds end_rec_off = tree->node_size - (node->num_recs + 1) * 2; 911da177e4SLinus Torvalds end_off = hfs_bnode_read_u16(node, end_rec_off); 921da177e4SLinus Torvalds end_rec_off -= 2; 93c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", 942753cc28SAnton Salikhmetov rec, size, end_off, end_rec_off); 951da177e4SLinus Torvalds if (size > end_rec_off - end_off) { 961da177e4SLinus Torvalds if (new_node) 971da177e4SLinus Torvalds panic("not enough room!\n"); 981da177e4SLinus Torvalds new_node = hfs_bnode_split(fd); 991da177e4SLinus Torvalds if (IS_ERR(new_node)) 1001da177e4SLinus Torvalds return PTR_ERR(new_node); 1011da177e4SLinus Torvalds goto again; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds if (node->type == HFS_NODE_LEAF) { 1041da177e4SLinus Torvalds tree->leaf_count++; 1051da177e4SLinus Torvalds mark_inode_dirty(tree->inode); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds node->num_recs++; 1081da177e4SLinus Torvalds /* write new last offset */ 1092753cc28SAnton Salikhmetov hfs_bnode_write_u16(node, 1102753cc28SAnton Salikhmetov offsetof(struct hfs_bnode_desc, num_recs), 1112753cc28SAnton Salikhmetov node->num_recs); 1121da177e4SLinus Torvalds hfs_bnode_write_u16(node, end_rec_off, end_off + size); 1131da177e4SLinus Torvalds data_off = end_off; 1141da177e4SLinus Torvalds data_rec_off = end_rec_off + 2; 1151da177e4SLinus Torvalds idx_rec_off = tree->node_size - (rec + 1) * 2; 1161da177e4SLinus Torvalds if (idx_rec_off == data_rec_off) 1171da177e4SLinus Torvalds goto skip; 1181da177e4SLinus Torvalds /* move all following entries */ 1191da177e4SLinus Torvalds do { 1201da177e4SLinus Torvalds data_off = hfs_bnode_read_u16(node, data_rec_off + 2); 1211da177e4SLinus Torvalds hfs_bnode_write_u16(node, data_rec_off, data_off + size); 1221da177e4SLinus Torvalds data_rec_off += 2; 1231da177e4SLinus Torvalds } while (data_rec_off < idx_rec_off); 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* move data away */ 1261da177e4SLinus Torvalds hfs_bnode_move(node, data_off + size, data_off, 1271da177e4SLinus Torvalds end_off - data_off); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds skip: 1301da177e4SLinus Torvalds hfs_bnode_write(node, fd->search_key, data_off, key_len); 1311da177e4SLinus Torvalds hfs_bnode_write(node, entry, data_off + key_len, entry_len); 1321da177e4SLinus Torvalds hfs_bnode_dump(node); 1331da177e4SLinus Torvalds 13498cf21c6SSergei Antonov /* 13598cf21c6SSergei Antonov * update parent key if we inserted a key 13698cf21c6SSergei Antonov * at the start of the node and it is not the new node 1371da177e4SLinus Torvalds */ 13898cf21c6SSergei Antonov if (!rec && new_node != node) { 13998cf21c6SSergei Antonov hfs_bnode_read_key(node, fd->search_key, data_off + size); 1401da177e4SLinus Torvalds hfs_brec_update_parent(fd); 14198cf21c6SSergei Antonov } 1421da177e4SLinus Torvalds 14398cf21c6SSergei Antonov if (new_node) { 1441da177e4SLinus Torvalds hfs_bnode_put(fd->bnode); 1451da177e4SLinus Torvalds if (!new_node->parent) { 1461da177e4SLinus Torvalds hfs_btree_inc_height(tree); 1471da177e4SLinus Torvalds new_node->parent = tree->root; 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds fd->bnode = hfs_bnode_find(tree, new_node->parent); 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* create index data entry */ 1521da177e4SLinus Torvalds cnid = cpu_to_be32(new_node->this); 1531da177e4SLinus Torvalds entry = &cnid; 1541da177e4SLinus Torvalds entry_len = sizeof(cnid); 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* get index key */ 1571da177e4SLinus Torvalds hfs_bnode_read_key(new_node, fd->search_key, 14); 158324ef39aSVyacheslav Dubeyko __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds hfs_bnode_put(new_node); 1611da177e4SLinus Torvalds new_node = NULL; 1621da177e4SLinus Torvalds 163324ef39aSVyacheslav Dubeyko if ((tree->attributes & HFS_TREE_VARIDXKEYS) || 164324ef39aSVyacheslav Dubeyko (tree->cnid == HFSPLUS_ATTR_CNID)) 1651da177e4SLinus Torvalds key_len = be16_to_cpu(fd->search_key->key_len) + 2; 1661da177e4SLinus Torvalds else { 1672753cc28SAnton Salikhmetov fd->search_key->key_len = 1682753cc28SAnton Salikhmetov cpu_to_be16(tree->max_key_len); 1691da177e4SLinus Torvalds key_len = tree->max_key_len + 2; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds goto again; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds return 0; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds int hfs_brec_remove(struct hfs_find_data *fd) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds struct hfs_btree *tree; 1801da177e4SLinus Torvalds struct hfs_bnode *node, *parent; 1811da177e4SLinus Torvalds int end_off, rec_off, data_off, size; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds tree = fd->tree; 1841da177e4SLinus Torvalds node = fd->bnode; 1851da177e4SLinus Torvalds again: 1861da177e4SLinus Torvalds rec_off = tree->node_size - (fd->record + 2) * 2; 1871da177e4SLinus Torvalds end_off = tree->node_size - (node->num_recs + 1) * 2; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds if (node->type == HFS_NODE_LEAF) { 1901da177e4SLinus Torvalds tree->leaf_count--; 1911da177e4SLinus Torvalds mark_inode_dirty(tree->inode); 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds hfs_bnode_dump(node); 194c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n", 1952753cc28SAnton Salikhmetov fd->record, fd->keylength + fd->entrylength); 1961da177e4SLinus Torvalds if (!--node->num_recs) { 1971da177e4SLinus Torvalds hfs_bnode_unlink(node); 1981da177e4SLinus Torvalds if (!node->parent) 1991da177e4SLinus Torvalds return 0; 2001da177e4SLinus Torvalds parent = hfs_bnode_find(tree, node->parent); 2011da177e4SLinus Torvalds if (IS_ERR(parent)) 2021da177e4SLinus Torvalds return PTR_ERR(parent); 2031da177e4SLinus Torvalds hfs_bnode_put(node); 2041da177e4SLinus Torvalds node = fd->bnode = parent; 2051da177e4SLinus Torvalds 206324ef39aSVyacheslav Dubeyko __hfs_brec_find(node, fd, hfs_find_rec_by_key); 2071da177e4SLinus Torvalds goto again; 2081da177e4SLinus Torvalds } 2092753cc28SAnton Salikhmetov hfs_bnode_write_u16(node, 2102753cc28SAnton Salikhmetov offsetof(struct hfs_bnode_desc, num_recs), 2112753cc28SAnton Salikhmetov node->num_recs); 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds if (rec_off == end_off) 2141da177e4SLinus Torvalds goto skip; 2151da177e4SLinus Torvalds size = fd->keylength + fd->entrylength; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds do { 2181da177e4SLinus Torvalds data_off = hfs_bnode_read_u16(node, rec_off); 2191da177e4SLinus Torvalds hfs_bnode_write_u16(node, rec_off + 2, data_off - size); 2201da177e4SLinus Torvalds rec_off -= 2; 2211da177e4SLinus Torvalds } while (rec_off >= end_off); 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /* fill hole */ 2241da177e4SLinus Torvalds hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size, 2251da177e4SLinus Torvalds data_off - fd->keyoffset - size); 2261da177e4SLinus Torvalds skip: 2271da177e4SLinus Torvalds hfs_bnode_dump(node); 2281da177e4SLinus Torvalds if (!fd->record) 2291da177e4SLinus Torvalds hfs_brec_update_parent(fd); 2301da177e4SLinus Torvalds return 0; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) 2341da177e4SLinus Torvalds { 2351da177e4SLinus Torvalds struct hfs_btree *tree; 236b6b41424SAl Viro struct hfs_bnode *node, *new_node, *next_node; 2371da177e4SLinus Torvalds struct hfs_bnode_desc node_desc; 2381da177e4SLinus Torvalds int num_recs, new_rec_off, new_off, old_rec_off; 2391da177e4SLinus Torvalds int data_start, data_end, size; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds tree = fd->tree; 2421da177e4SLinus Torvalds node = fd->bnode; 2431da177e4SLinus Torvalds new_node = hfs_bmap_alloc(tree); 2441da177e4SLinus Torvalds if (IS_ERR(new_node)) 2451da177e4SLinus Torvalds return new_node; 2461da177e4SLinus Torvalds hfs_bnode_get(node); 247c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n", 2481da177e4SLinus Torvalds node->this, new_node->this, node->next); 2491da177e4SLinus Torvalds new_node->next = node->next; 2501da177e4SLinus Torvalds new_node->prev = node->this; 2511da177e4SLinus Torvalds new_node->parent = node->parent; 2521da177e4SLinus Torvalds new_node->type = node->type; 2531da177e4SLinus Torvalds new_node->height = node->height; 2541da177e4SLinus Torvalds 255b6b41424SAl Viro if (node->next) 256b6b41424SAl Viro next_node = hfs_bnode_find(tree, node->next); 257b6b41424SAl Viro else 258b6b41424SAl Viro next_node = NULL; 259b6b41424SAl Viro 260b6b41424SAl Viro if (IS_ERR(next_node)) { 261b6b41424SAl Viro hfs_bnode_put(node); 262b6b41424SAl Viro hfs_bnode_put(new_node); 263b6b41424SAl Viro return next_node; 264b6b41424SAl Viro } 265b6b41424SAl Viro 2661da177e4SLinus Torvalds size = tree->node_size / 2 - node->num_recs * 2 - 14; 2671da177e4SLinus Torvalds old_rec_off = tree->node_size - 4; 2681da177e4SLinus Torvalds num_recs = 1; 2691da177e4SLinus Torvalds for (;;) { 2701da177e4SLinus Torvalds data_start = hfs_bnode_read_u16(node, old_rec_off); 2711da177e4SLinus Torvalds if (data_start > size) 2721da177e4SLinus Torvalds break; 2731da177e4SLinus Torvalds old_rec_off -= 2; 2741da177e4SLinus Torvalds if (++num_recs < node->num_recs) 2751da177e4SLinus Torvalds continue; 2761da177e4SLinus Torvalds /* panic? */ 2771da177e4SLinus Torvalds hfs_bnode_put(node); 2781da177e4SLinus Torvalds hfs_bnode_put(new_node); 279b6b41424SAl Viro if (next_node) 280b6b41424SAl Viro hfs_bnode_put(next_node); 2811da177e4SLinus Torvalds return ERR_PTR(-ENOSPC); 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds if (fd->record + 1 < num_recs) { 2851da177e4SLinus Torvalds /* new record is in the lower half, 2861da177e4SLinus Torvalds * so leave some more space there 2871da177e4SLinus Torvalds */ 2881da177e4SLinus Torvalds old_rec_off += 2; 2891da177e4SLinus Torvalds num_recs--; 2901da177e4SLinus Torvalds data_start = hfs_bnode_read_u16(node, old_rec_off); 2911da177e4SLinus Torvalds } else { 2921da177e4SLinus Torvalds hfs_bnode_put(node); 2931da177e4SLinus Torvalds hfs_bnode_get(new_node); 2941da177e4SLinus Torvalds fd->bnode = new_node; 2951da177e4SLinus Torvalds fd->record -= num_recs; 2961da177e4SLinus Torvalds fd->keyoffset -= data_start - 14; 2971da177e4SLinus Torvalds fd->entryoffset -= data_start - 14; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds new_node->num_recs = node->num_recs - num_recs; 3001da177e4SLinus Torvalds node->num_recs = num_recs; 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds new_rec_off = tree->node_size - 2; 3031da177e4SLinus Torvalds new_off = 14; 3041da177e4SLinus Torvalds size = data_start - new_off; 3051da177e4SLinus Torvalds num_recs = new_node->num_recs; 3061da177e4SLinus Torvalds data_end = data_start; 3071da177e4SLinus Torvalds while (num_recs) { 3081da177e4SLinus Torvalds hfs_bnode_write_u16(new_node, new_rec_off, new_off); 3091da177e4SLinus Torvalds old_rec_off -= 2; 3101da177e4SLinus Torvalds new_rec_off -= 2; 3111da177e4SLinus Torvalds data_end = hfs_bnode_read_u16(node, old_rec_off); 3121da177e4SLinus Torvalds new_off = data_end - size; 3131da177e4SLinus Torvalds num_recs--; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds hfs_bnode_write_u16(new_node, new_rec_off, new_off); 3161da177e4SLinus Torvalds hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* update new bnode header */ 3191da177e4SLinus Torvalds node_desc.next = cpu_to_be32(new_node->next); 3201da177e4SLinus Torvalds node_desc.prev = cpu_to_be32(new_node->prev); 3211da177e4SLinus Torvalds node_desc.type = new_node->type; 3221da177e4SLinus Torvalds node_desc.height = new_node->height; 3231da177e4SLinus Torvalds node_desc.num_recs = cpu_to_be16(new_node->num_recs); 3241da177e4SLinus Torvalds node_desc.reserved = 0; 3251da177e4SLinus Torvalds hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc)); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* update previous bnode header */ 3281da177e4SLinus Torvalds node->next = new_node->this; 3291da177e4SLinus Torvalds hfs_bnode_read(node, &node_desc, 0, sizeof(node_desc)); 3301da177e4SLinus Torvalds node_desc.next = cpu_to_be32(node->next); 3311da177e4SLinus Torvalds node_desc.num_recs = cpu_to_be16(node->num_recs); 3321da177e4SLinus Torvalds hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc)); 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds /* update next bnode header */ 335b6b41424SAl Viro if (next_node) { 3361da177e4SLinus Torvalds next_node->prev = new_node->this; 3371da177e4SLinus Torvalds hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc)); 3381da177e4SLinus Torvalds node_desc.prev = cpu_to_be32(next_node->prev); 3391da177e4SLinus Torvalds hfs_bnode_write(next_node, &node_desc, 0, sizeof(node_desc)); 3401da177e4SLinus Torvalds hfs_bnode_put(next_node); 3411da177e4SLinus Torvalds } else if (node->this == tree->leaf_tail) { 3421da177e4SLinus Torvalds /* if there is no next node, this might be the new tail */ 3431da177e4SLinus Torvalds tree->leaf_tail = new_node->this; 3441da177e4SLinus Torvalds mark_inode_dirty(tree->inode); 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds hfs_bnode_dump(node); 3481da177e4SLinus Torvalds hfs_bnode_dump(new_node); 3491da177e4SLinus Torvalds hfs_bnode_put(node); 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds return new_node; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds static int hfs_brec_update_parent(struct hfs_find_data *fd) 3551da177e4SLinus Torvalds { 3561da177e4SLinus Torvalds struct hfs_btree *tree; 3571da177e4SLinus Torvalds struct hfs_bnode *node, *new_node, *parent; 3581da177e4SLinus Torvalds int newkeylen, diff; 3591da177e4SLinus Torvalds int rec, rec_off, end_rec_off; 3601da177e4SLinus Torvalds int start_off, end_off; 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds tree = fd->tree; 3631da177e4SLinus Torvalds node = fd->bnode; 3641da177e4SLinus Torvalds new_node = NULL; 3651da177e4SLinus Torvalds if (!node->parent) 3661da177e4SLinus Torvalds return 0; 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds again: 3691da177e4SLinus Torvalds parent = hfs_bnode_find(tree, node->parent); 3701da177e4SLinus Torvalds if (IS_ERR(parent)) 3711da177e4SLinus Torvalds return PTR_ERR(parent); 372324ef39aSVyacheslav Dubeyko __hfs_brec_find(parent, fd, hfs_find_rec_by_key); 37398cf21c6SSergei Antonov if (fd->record < 0) 37498cf21c6SSergei Antonov return -ENOENT; 3751da177e4SLinus Torvalds hfs_bnode_dump(parent); 3761da177e4SLinus Torvalds rec = fd->record; 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /* size difference between old and new key */ 379324ef39aSVyacheslav Dubeyko if ((tree->attributes & HFS_TREE_VARIDXKEYS) || 380324ef39aSVyacheslav Dubeyko (tree->cnid == HFSPLUS_ATTR_CNID)) 3811da177e4SLinus Torvalds newkeylen = hfs_bnode_read_u16(node, 14) + 2; 3821da177e4SLinus Torvalds else 3831da177e4SLinus Torvalds fd->keylength = newkeylen = tree->max_key_len + 2; 384c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n", 3852753cc28SAnton Salikhmetov rec, fd->keylength, newkeylen); 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds rec_off = tree->node_size - (rec + 2) * 2; 3881da177e4SLinus Torvalds end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; 3891da177e4SLinus Torvalds diff = newkeylen - fd->keylength; 3901da177e4SLinus Torvalds if (!diff) 3911da177e4SLinus Torvalds goto skip; 3921da177e4SLinus Torvalds if (diff > 0) { 3931da177e4SLinus Torvalds end_off = hfs_bnode_read_u16(parent, end_rec_off); 3941da177e4SLinus Torvalds if (end_rec_off - end_off < diff) { 3951da177e4SLinus Torvalds 396c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "splitting index node\n"); 3971da177e4SLinus Torvalds fd->bnode = parent; 3981da177e4SLinus Torvalds new_node = hfs_bnode_split(fd); 3991da177e4SLinus Torvalds if (IS_ERR(new_node)) 4001da177e4SLinus Torvalds return PTR_ERR(new_node); 4011da177e4SLinus Torvalds parent = fd->bnode; 4021da177e4SLinus Torvalds rec = fd->record; 4031da177e4SLinus Torvalds rec_off = tree->node_size - (rec + 2) * 2; 4042753cc28SAnton Salikhmetov end_rec_off = tree->node_size - 4052753cc28SAnton Salikhmetov (parent->num_recs + 1) * 2; 4061da177e4SLinus Torvalds } 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds end_off = start_off = hfs_bnode_read_u16(parent, rec_off); 4101da177e4SLinus Torvalds hfs_bnode_write_u16(parent, rec_off, start_off + diff); 4111da177e4SLinus Torvalds start_off -= 4; /* move previous cnid too */ 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds while (rec_off > end_rec_off) { 4141da177e4SLinus Torvalds rec_off -= 2; 4151da177e4SLinus Torvalds end_off = hfs_bnode_read_u16(parent, rec_off); 4161da177e4SLinus Torvalds hfs_bnode_write_u16(parent, rec_off, end_off + diff); 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds hfs_bnode_move(parent, start_off + diff, start_off, 4191da177e4SLinus Torvalds end_off - start_off); 4201da177e4SLinus Torvalds skip: 4211da177e4SLinus Torvalds hfs_bnode_copy(parent, fd->keyoffset, node, 14, newkeylen); 4221da177e4SLinus Torvalds hfs_bnode_dump(parent); 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds hfs_bnode_put(node); 4251da177e4SLinus Torvalds node = parent; 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds if (new_node) { 4281da177e4SLinus Torvalds __be32 cnid; 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds fd->bnode = hfs_bnode_find(tree, new_node->parent); 4311da177e4SLinus Torvalds /* create index key and entry */ 4321da177e4SLinus Torvalds hfs_bnode_read_key(new_node, fd->search_key, 14); 4331da177e4SLinus Torvalds cnid = cpu_to_be32(new_node->this); 4341da177e4SLinus Torvalds 435324ef39aSVyacheslav Dubeyko __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); 4361da177e4SLinus Torvalds hfs_brec_insert(fd, &cnid, sizeof(cnid)); 4371da177e4SLinus Torvalds hfs_bnode_put(fd->bnode); 4381da177e4SLinus Torvalds hfs_bnode_put(new_node); 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds if (!rec) { 4411da177e4SLinus Torvalds if (new_node == node) 4421da177e4SLinus Torvalds goto out; 4431da177e4SLinus Torvalds /* restore search_key */ 4441da177e4SLinus Torvalds hfs_bnode_read_key(node, fd->search_key, 14); 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds if (!rec && node->parent) 4491da177e4SLinus Torvalds goto again; 4501da177e4SLinus Torvalds out: 4511da177e4SLinus Torvalds fd->bnode = node; 4521da177e4SLinus Torvalds return 0; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds static int hfs_btree_inc_height(struct hfs_btree *tree) 4561da177e4SLinus Torvalds { 4571da177e4SLinus Torvalds struct hfs_bnode *node, *new_node; 4581da177e4SLinus Torvalds struct hfs_bnode_desc node_desc; 4591da177e4SLinus Torvalds int key_size, rec; 4601da177e4SLinus Torvalds __be32 cnid; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds node = NULL; 4631da177e4SLinus Torvalds if (tree->root) { 4641da177e4SLinus Torvalds node = hfs_bnode_find(tree, tree->root); 4651da177e4SLinus Torvalds if (IS_ERR(node)) 4661da177e4SLinus Torvalds return PTR_ERR(node); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds new_node = hfs_bmap_alloc(tree); 4691da177e4SLinus Torvalds if (IS_ERR(new_node)) { 4701da177e4SLinus Torvalds hfs_bnode_put(node); 4711da177e4SLinus Torvalds return PTR_ERR(new_node); 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds tree->root = new_node->this; 4751da177e4SLinus Torvalds if (!tree->depth) { 4761da177e4SLinus Torvalds tree->leaf_head = tree->leaf_tail = new_node->this; 4771da177e4SLinus Torvalds new_node->type = HFS_NODE_LEAF; 4781da177e4SLinus Torvalds new_node->num_recs = 0; 4791da177e4SLinus Torvalds } else { 4801da177e4SLinus Torvalds new_node->type = HFS_NODE_INDEX; 4811da177e4SLinus Torvalds new_node->num_recs = 1; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds new_node->parent = 0; 4841da177e4SLinus Torvalds new_node->next = 0; 4851da177e4SLinus Torvalds new_node->prev = 0; 4861da177e4SLinus Torvalds new_node->height = ++tree->depth; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds node_desc.next = cpu_to_be32(new_node->next); 4891da177e4SLinus Torvalds node_desc.prev = cpu_to_be32(new_node->prev); 4901da177e4SLinus Torvalds node_desc.type = new_node->type; 4911da177e4SLinus Torvalds node_desc.height = new_node->height; 4921da177e4SLinus Torvalds node_desc.num_recs = cpu_to_be16(new_node->num_recs); 4931da177e4SLinus Torvalds node_desc.reserved = 0; 4941da177e4SLinus Torvalds hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc)); 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds rec = tree->node_size - 2; 4971da177e4SLinus Torvalds hfs_bnode_write_u16(new_node, rec, 14); 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds if (node) { 5001da177e4SLinus Torvalds /* insert old root idx into new root */ 5011da177e4SLinus Torvalds node->parent = tree->root; 5021da177e4SLinus Torvalds if (node->type == HFS_NODE_LEAF || 503324ef39aSVyacheslav Dubeyko tree->attributes & HFS_TREE_VARIDXKEYS || 504324ef39aSVyacheslav Dubeyko tree->cnid == HFSPLUS_ATTR_CNID) 5051da177e4SLinus Torvalds key_size = hfs_bnode_read_u16(node, 14) + 2; 5061da177e4SLinus Torvalds else 5071da177e4SLinus Torvalds key_size = tree->max_key_len + 2; 5081da177e4SLinus Torvalds hfs_bnode_copy(new_node, 14, node, 14, key_size); 5091da177e4SLinus Torvalds 510324ef39aSVyacheslav Dubeyko if (!(tree->attributes & HFS_TREE_VARIDXKEYS) && 511324ef39aSVyacheslav Dubeyko (tree->cnid != HFSPLUS_ATTR_CNID)) { 5121da177e4SLinus Torvalds key_size = tree->max_key_len + 2; 5131da177e4SLinus Torvalds hfs_bnode_write_u16(new_node, 14, tree->max_key_len); 5141da177e4SLinus Torvalds } 5151da177e4SLinus Torvalds cnid = cpu_to_be32(node->this); 5161da177e4SLinus Torvalds hfs_bnode_write(new_node, &cnid, 14 + key_size, 4); 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds rec -= 2; 5191da177e4SLinus Torvalds hfs_bnode_write_u16(new_node, rec, 14 + key_size + 4); 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds hfs_bnode_put(node); 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds hfs_bnode_put(new_node); 5241da177e4SLinus Torvalds mark_inode_dirty(tree->inode); 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds return 0; 5271da177e4SLinus Torvalds } 528