18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/hpfs/dnode.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * handling directory dnode tree - adding, deleteing & searching for dirents 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "hpfs_fn.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 158c2ecf20Sopenharmony_ci struct hpfs_dirent *de_end = dnode_end_de(d); 168c2ecf20Sopenharmony_ci int i = 1; 178c2ecf20Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 188c2ecf20Sopenharmony_ci if (de == fde) return ((loff_t) le32_to_cpu(d->self) << 4) | (loff_t)i; 198c2ecf20Sopenharmony_ci i++; 208c2ecf20Sopenharmony_ci } 218c2ecf20Sopenharmony_ci pr_info("%s(): not_found\n", __func__); 228c2ecf20Sopenharmony_ci return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciint hpfs_add_pos(struct inode *inode, loff_t *pos) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); 288c2ecf20Sopenharmony_ci int i = 0; 298c2ecf20Sopenharmony_ci loff_t **ppos; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (hpfs_inode->i_rddir_off) 328c2ecf20Sopenharmony_ci for (; hpfs_inode->i_rddir_off[i]; i++) 338c2ecf20Sopenharmony_ci if (hpfs_inode->i_rddir_off[i] == pos) 348c2ecf20Sopenharmony_ci return 0; 358c2ecf20Sopenharmony_ci if (!(i&0x0f)) { 368c2ecf20Sopenharmony_ci ppos = kmalloc_array(i + 0x11, sizeof(loff_t *), GFP_NOFS); 378c2ecf20Sopenharmony_ci if (!ppos) { 388c2ecf20Sopenharmony_ci pr_err("out of memory for position list\n"); 398c2ecf20Sopenharmony_ci return -ENOMEM; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci if (hpfs_inode->i_rddir_off) { 428c2ecf20Sopenharmony_ci memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t)); 438c2ecf20Sopenharmony_ci kfree(hpfs_inode->i_rddir_off); 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci hpfs_inode->i_rddir_off = ppos; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci hpfs_inode->i_rddir_off[i] = pos; 488c2ecf20Sopenharmony_ci hpfs_inode->i_rddir_off[i + 1] = NULL; 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_civoid hpfs_del_pos(struct inode *inode, loff_t *pos) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); 558c2ecf20Sopenharmony_ci loff_t **i, **j; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!hpfs_inode->i_rddir_off) goto not_f; 588c2ecf20Sopenharmony_ci for (i = hpfs_inode->i_rddir_off; *i; i++) if (*i == pos) goto fnd; 598c2ecf20Sopenharmony_ci goto not_f; 608c2ecf20Sopenharmony_ci fnd: 618c2ecf20Sopenharmony_ci for (j = i + 1; *j; j++) ; 628c2ecf20Sopenharmony_ci *i = *(j - 1); 638c2ecf20Sopenharmony_ci *(j - 1) = NULL; 648c2ecf20Sopenharmony_ci if (j - 1 == hpfs_inode->i_rddir_off) { 658c2ecf20Sopenharmony_ci kfree(hpfs_inode->i_rddir_off); 668c2ecf20Sopenharmony_ci hpfs_inode->i_rddir_off = NULL; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci return; 698c2ecf20Sopenharmony_ci not_f: 708c2ecf20Sopenharmony_ci /*pr_warn("position pointer %p->%08x not found\n", 718c2ecf20Sopenharmony_ci pos, (int)*pos);*/ 728c2ecf20Sopenharmony_ci return; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t), 768c2ecf20Sopenharmony_ci loff_t p1, loff_t p2) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); 798c2ecf20Sopenharmony_ci loff_t **i; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (!hpfs_inode->i_rddir_off) return; 828c2ecf20Sopenharmony_ci for (i = hpfs_inode->i_rddir_off; *i; i++) (*f)(*i, p1, p2); 838c2ecf20Sopenharmony_ci return; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (*p == f) *p = t; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/*void hpfs_hpfs_pos_substd(loff_t *p, loff_t f, loff_t t) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci if ((*p & ~0x3f) == (f & ~0x3f)) *p = (t & ~0x3f) | (*p & 0x3f); 948c2ecf20Sopenharmony_ci}*/ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) { 998c2ecf20Sopenharmony_ci int n = (*p & 0x3f) + c; 1008c2ecf20Sopenharmony_ci if (n > 0x3f) 1018c2ecf20Sopenharmony_ci pr_err("%s(): %08x + %d\n", 1028c2ecf20Sopenharmony_ci __func__, (int)*p, (int)c >> 8); 1038c2ecf20Sopenharmony_ci else 1048c2ecf20Sopenharmony_ci *p = (*p & ~0x3f) | n; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void hpfs_pos_del(loff_t *p, loff_t d, loff_t c) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) { 1118c2ecf20Sopenharmony_ci int n = (*p & 0x3f) - c; 1128c2ecf20Sopenharmony_ci if (n < 1) 1138c2ecf20Sopenharmony_ci pr_err("%s(): %08x - %d\n", 1148c2ecf20Sopenharmony_ci __func__, (int)*p, (int)c >> 8); 1158c2ecf20Sopenharmony_ci else 1168c2ecf20Sopenharmony_ci *p = (*p & ~0x3f) | n; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic struct hpfs_dirent *dnode_pre_last_de(struct dnode *d) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct hpfs_dirent *de, *de_end, *dee = NULL, *deee = NULL; 1238c2ecf20Sopenharmony_ci de_end = dnode_end_de(d); 1248c2ecf20Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 1258c2ecf20Sopenharmony_ci deee = dee; dee = de; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci return deee; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic struct hpfs_dirent *dnode_last_de(struct dnode *d) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct hpfs_dirent *de, *de_end, *dee = NULL; 1338c2ecf20Sopenharmony_ci de_end = dnode_end_de(d); 1348c2ecf20Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 1358c2ecf20Sopenharmony_ci dee = de; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci return dee; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno ptr) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 1438c2ecf20Sopenharmony_ci if (!(de = dnode_last_de(d))) { 1448c2ecf20Sopenharmony_ci hpfs_error(s, "set_last_pointer: empty dnode %08x", le32_to_cpu(d->self)); 1458c2ecf20Sopenharmony_ci return; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) { 1488c2ecf20Sopenharmony_ci if (de->down) { 1498c2ecf20Sopenharmony_ci hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x", 1508c2ecf20Sopenharmony_ci le32_to_cpu(d->self), de_down_pointer(de)); 1518c2ecf20Sopenharmony_ci return; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci if (le16_to_cpu(de->length) != 32) { 1548c2ecf20Sopenharmony_ci hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", le32_to_cpu(d->self)); 1558c2ecf20Sopenharmony_ci return; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci if (ptr) { 1598c2ecf20Sopenharmony_ci le32_add_cpu(&d->first_free, 4); 1608c2ecf20Sopenharmony_ci if (le32_to_cpu(d->first_free) > 2048) { 1618c2ecf20Sopenharmony_ci hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self)); 1628c2ecf20Sopenharmony_ci le32_add_cpu(&d->first_free, -4); 1638c2ecf20Sopenharmony_ci return; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci de->length = cpu_to_le16(36); 1668c2ecf20Sopenharmony_ci de->down = 1; 1678c2ecf20Sopenharmony_ci *(__le32 *)((char *)de + 32) = cpu_to_le32(ptr); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* Add an entry to dnode and don't care if it grows over 2048 bytes */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistruct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, 1748c2ecf20Sopenharmony_ci const unsigned char *name, 1758c2ecf20Sopenharmony_ci unsigned namelen, secno down_ptr) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 1788c2ecf20Sopenharmony_ci struct hpfs_dirent *de_end = dnode_end_de(d); 1798c2ecf20Sopenharmony_ci unsigned d_size = de_size(namelen, down_ptr); 1808c2ecf20Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 1818c2ecf20Sopenharmony_ci int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last); 1828c2ecf20Sopenharmony_ci if (!c) { 1838c2ecf20Sopenharmony_ci hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, le32_to_cpu(d->self)); 1848c2ecf20Sopenharmony_ci return NULL; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci if (c < 0) break; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci memmove((char *)de + d_size, de, (char *)de_end - (char *)de); 1898c2ecf20Sopenharmony_ci memset(de, 0, d_size); 1908c2ecf20Sopenharmony_ci if (down_ptr) { 1918c2ecf20Sopenharmony_ci *(__le32 *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr); 1928c2ecf20Sopenharmony_ci de->down = 1; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci de->length = cpu_to_le16(d_size); 1958c2ecf20Sopenharmony_ci de->not_8x3 = hpfs_is_name_long(name, namelen); 1968c2ecf20Sopenharmony_ci de->namelen = namelen; 1978c2ecf20Sopenharmony_ci memcpy(de->name, name, namelen); 1988c2ecf20Sopenharmony_ci le32_add_cpu(&d->first_free, d_size); 1998c2ecf20Sopenharmony_ci return de; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* Delete dirent and don't care about its subtree */ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void hpfs_delete_de(struct super_block *s, struct dnode *d, 2058c2ecf20Sopenharmony_ci struct hpfs_dirent *de) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci if (de->last) { 2088c2ecf20Sopenharmony_ci hpfs_error(s, "attempt to delete last dirent in dnode %08x", le32_to_cpu(d->self)); 2098c2ecf20Sopenharmony_ci return; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - le16_to_cpu(de->length)); 2128c2ecf20Sopenharmony_ci memmove(de, de_next_de(de), le32_to_cpu(d->first_free) + (char *)d - (char *)de); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void fix_up_ptrs(struct super_block *s, struct dnode *d) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 2188c2ecf20Sopenharmony_ci struct hpfs_dirent *de_end = dnode_end_de(d); 2198c2ecf20Sopenharmony_ci dnode_secno dno = le32_to_cpu(d->self); 2208c2ecf20Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) 2218c2ecf20Sopenharmony_ci if (de->down) { 2228c2ecf20Sopenharmony_ci struct quad_buffer_head qbh; 2238c2ecf20Sopenharmony_ci struct dnode *dd; 2248c2ecf20Sopenharmony_ci if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) { 2258c2ecf20Sopenharmony_ci if (le32_to_cpu(dd->up) != dno || dd->root_dnode) { 2268c2ecf20Sopenharmony_ci dd->up = cpu_to_le32(dno); 2278c2ecf20Sopenharmony_ci dd->root_dnode = 0; 2288c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* Add an entry to dnode and do dnode splitting if required */ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, 2388c2ecf20Sopenharmony_ci const unsigned char *name, unsigned namelen, 2398c2ecf20Sopenharmony_ci struct hpfs_dirent *new_de, dnode_secno down_ptr) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct quad_buffer_head qbh, qbh1, qbh2; 2428c2ecf20Sopenharmony_ci struct dnode *d, *ad, *rd, *nd = NULL; 2438c2ecf20Sopenharmony_ci dnode_secno adno, rdno; 2448c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 2458c2ecf20Sopenharmony_ci struct hpfs_dirent nde; 2468c2ecf20Sopenharmony_ci unsigned char *nname; 2478c2ecf20Sopenharmony_ci int h; 2488c2ecf20Sopenharmony_ci int pos; 2498c2ecf20Sopenharmony_ci struct buffer_head *bh; 2508c2ecf20Sopenharmony_ci struct fnode *fnode; 2518c2ecf20Sopenharmony_ci int c1, c2 = 0; 2528c2ecf20Sopenharmony_ci if (!(nname = kmalloc(256, GFP_NOFS))) { 2538c2ecf20Sopenharmony_ci pr_err("out of memory, can't add to dnode\n"); 2548c2ecf20Sopenharmony_ci return 1; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci go_up: 2578c2ecf20Sopenharmony_ci if (namelen >= 256) { 2588c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "%s(): namelen == %d", __func__, namelen); 2598c2ecf20Sopenharmony_ci kfree(nd); 2608c2ecf20Sopenharmony_ci kfree(nname); 2618c2ecf20Sopenharmony_ci return 1; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) { 2648c2ecf20Sopenharmony_ci kfree(nd); 2658c2ecf20Sopenharmony_ci kfree(nname); 2668c2ecf20Sopenharmony_ci return 1; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci go_up_a: 2698c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 2708c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_to_dnode")) { 2718c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 2728c2ecf20Sopenharmony_ci kfree(nd); 2738c2ecf20Sopenharmony_ci kfree(nname); 2748c2ecf20Sopenharmony_ci return 1; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci if (le32_to_cpu(d->first_free) + de_size(namelen, down_ptr) <= 2048) { 2778c2ecf20Sopenharmony_ci loff_t t; 2788c2ecf20Sopenharmony_ci copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de); 2798c2ecf20Sopenharmony_ci t = get_pos(d, de); 2808c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_ins, t, 1); 2818c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, 4, t); 2828c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, 5, t + 1); 2838c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 2848c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 2858c2ecf20Sopenharmony_ci kfree(nd); 2868c2ecf20Sopenharmony_ci kfree(nname); 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci if (!nd) if (!(nd = kmalloc(0x924, GFP_NOFS))) { 2908c2ecf20Sopenharmony_ci /* 0x924 is a max size of dnode after adding a dirent with 2918c2ecf20Sopenharmony_ci max name length. We alloc this only once. There must 2928c2ecf20Sopenharmony_ci not be any error while splitting dnodes, otherwise the 2938c2ecf20Sopenharmony_ci whole directory, not only file we're adding, would 2948c2ecf20Sopenharmony_ci be lost. */ 2958c2ecf20Sopenharmony_ci pr_err("out of memory for dnode splitting\n"); 2968c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 2978c2ecf20Sopenharmony_ci kfree(nname); 2988c2ecf20Sopenharmony_ci return 1; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci memcpy(nd, d, le32_to_cpu(d->first_free)); 3018c2ecf20Sopenharmony_ci copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de); 3028c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1); 3038c2ecf20Sopenharmony_ci h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10; 3048c2ecf20Sopenharmony_ci if (!(ad = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &adno, &qbh1))) { 3058c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); 3068c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 3078c2ecf20Sopenharmony_ci kfree(nd); 3088c2ecf20Sopenharmony_ci kfree(nname); 3098c2ecf20Sopenharmony_ci return 1; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci i->i_size += 2048; 3128c2ecf20Sopenharmony_ci i->i_blocks += 4; 3138c2ecf20Sopenharmony_ci pos = 1; 3148c2ecf20Sopenharmony_ci for (de = dnode_first_de(nd); (char *)de_next_de(de) - (char *)nd < h; de = de_next_de(de)) { 3158c2ecf20Sopenharmony_ci copy_de(hpfs_add_de(i->i_sb, ad, de->name, de->namelen, de->down ? de_down_pointer(de) : 0), de); 3168c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, ((loff_t)adno << 4) | pos); 3178c2ecf20Sopenharmony_ci pos++; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci copy_de(new_de = &nde, de); 3208c2ecf20Sopenharmony_ci memcpy(nname, de->name, de->namelen); 3218c2ecf20Sopenharmony_ci name = nname; 3228c2ecf20Sopenharmony_ci namelen = de->namelen; 3238c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4); 3248c2ecf20Sopenharmony_ci down_ptr = adno; 3258c2ecf20Sopenharmony_ci set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); 3268c2ecf20Sopenharmony_ci de = de_next_de(de); 3278c2ecf20Sopenharmony_ci memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de); 3288c2ecf20Sopenharmony_ci le32_add_cpu(&nd->first_free, -((char *)de - (char *)nd - 20)); 3298c2ecf20Sopenharmony_ci memcpy(d, nd, le32_to_cpu(nd->first_free)); 3308c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); 3318c2ecf20Sopenharmony_ci fix_up_ptrs(i->i_sb, ad); 3328c2ecf20Sopenharmony_ci if (!d->root_dnode) { 3338c2ecf20Sopenharmony_ci ad->up = d->up; 3348c2ecf20Sopenharmony_ci dno = le32_to_cpu(ad->up); 3358c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 3368c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 3378c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 3388c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 3398c2ecf20Sopenharmony_ci goto go_up; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci if (!(rd = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &rdno, &qbh2))) { 3428c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); 3438c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 3448c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 3458c2ecf20Sopenharmony_ci kfree(nd); 3468c2ecf20Sopenharmony_ci kfree(nname); 3478c2ecf20Sopenharmony_ci return 1; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci i->i_size += 2048; 3508c2ecf20Sopenharmony_ci i->i_blocks += 4; 3518c2ecf20Sopenharmony_ci rd->root_dnode = 1; 3528c2ecf20Sopenharmony_ci rd->up = d->up; 3538c2ecf20Sopenharmony_ci if (!(fnode = hpfs_map_fnode(i->i_sb, le32_to_cpu(d->up), &bh))) { 3548c2ecf20Sopenharmony_ci hpfs_free_dnode(i->i_sb, rdno); 3558c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 3568c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 3578c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh2); 3588c2ecf20Sopenharmony_ci kfree(nd); 3598c2ecf20Sopenharmony_ci kfree(nname); 3608c2ecf20Sopenharmony_ci return 1; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci fnode->u.external[0].disk_secno = cpu_to_le32(rdno); 3638c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 3648c2ecf20Sopenharmony_ci brelse(bh); 3658c2ecf20Sopenharmony_ci hpfs_i(i)->i_dno = rdno; 3668c2ecf20Sopenharmony_ci d->up = ad->up = cpu_to_le32(rdno); 3678c2ecf20Sopenharmony_ci d->root_dnode = ad->root_dnode = 0; 3688c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 3698c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 3708c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 3718c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 3728c2ecf20Sopenharmony_ci qbh = qbh2; 3738c2ecf20Sopenharmony_ci set_last_pointer(i->i_sb, rd, dno); 3748c2ecf20Sopenharmony_ci dno = rdno; 3758c2ecf20Sopenharmony_ci d = rd; 3768c2ecf20Sopenharmony_ci goto go_up_a; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* 3808c2ecf20Sopenharmony_ci * Add an entry to directory btree. 3818c2ecf20Sopenharmony_ci * I hate such crazy directory structure. 3828c2ecf20Sopenharmony_ci * It's easy to read but terrible to write. 3838c2ecf20Sopenharmony_ci * I wrote this directory code 4 times. 3848c2ecf20Sopenharmony_ci * I hope, now it's finally bug-free. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciint hpfs_add_dirent(struct inode *i, 3888c2ecf20Sopenharmony_ci const unsigned char *name, unsigned namelen, 3898c2ecf20Sopenharmony_ci struct hpfs_dirent *new_de) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(i); 3928c2ecf20Sopenharmony_ci struct dnode *d; 3938c2ecf20Sopenharmony_ci struct hpfs_dirent *de, *de_end; 3948c2ecf20Sopenharmony_ci struct quad_buffer_head qbh; 3958c2ecf20Sopenharmony_ci dnode_secno dno; 3968c2ecf20Sopenharmony_ci int c; 3978c2ecf20Sopenharmony_ci int c1, c2 = 0; 3988c2ecf20Sopenharmony_ci dno = hpfs_inode->i_dno; 3998c2ecf20Sopenharmony_ci down: 4008c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 4018c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1; 4028c2ecf20Sopenharmony_ci if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 1; 4038c2ecf20Sopenharmony_ci de_end = dnode_end_de(d); 4048c2ecf20Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 4058c2ecf20Sopenharmony_ci if (!(c = hpfs_compare_names(i->i_sb, name, namelen, de->name, de->namelen, de->last))) { 4068c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4078c2ecf20Sopenharmony_ci return -1; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci if (c < 0) { 4108c2ecf20Sopenharmony_ci if (de->down) { 4118c2ecf20Sopenharmony_ci dno = de_down_pointer(de); 4128c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4138c2ecf20Sopenharmony_ci goto down; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4198c2ecf20Sopenharmony_ci if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) { 4208c2ecf20Sopenharmony_ci c = 1; 4218c2ecf20Sopenharmony_ci goto ret; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0); 4248c2ecf20Sopenharmony_ci ret: 4258c2ecf20Sopenharmony_ci return c; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/* 4298c2ecf20Sopenharmony_ci * Find dirent with higher name in 'from' subtree and move it to 'to' dnode. 4308c2ecf20Sopenharmony_ci * Return the dnode we moved from (to be checked later if it's empty) 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci dnode_secno dno, ddno; 4368c2ecf20Sopenharmony_ci dnode_secno chk_up = to; 4378c2ecf20Sopenharmony_ci struct dnode *dnode; 4388c2ecf20Sopenharmony_ci struct quad_buffer_head qbh; 4398c2ecf20Sopenharmony_ci struct hpfs_dirent *de, *nde; 4408c2ecf20Sopenharmony_ci int a; 4418c2ecf20Sopenharmony_ci loff_t t; 4428c2ecf20Sopenharmony_ci int c1, c2 = 0; 4438c2ecf20Sopenharmony_ci dno = from; 4448c2ecf20Sopenharmony_ci while (1) { 4458c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 4468c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "move_to_top")) 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0; 4498c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) { 4508c2ecf20Sopenharmony_ci if (le32_to_cpu(dnode->up) != chk_up) { 4518c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x", 4528c2ecf20Sopenharmony_ci dno, chk_up, le32_to_cpu(dnode->up)); 4538c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci chk_up = dno; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci if (!(de = dnode_last_de(dnode))) { 4598c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: dnode %08x has no last de", dno); 4608c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci if (!de->down) break; 4648c2ecf20Sopenharmony_ci dno = de_down_pointer(de); 4658c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci while (!(de = dnode_pre_last_de(dnode))) { 4688c2ecf20Sopenharmony_ci dnode_secno up = le32_to_cpu(dnode->up); 4698c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4708c2ecf20Sopenharmony_ci hpfs_free_dnode(i->i_sb, dno); 4718c2ecf20Sopenharmony_ci i->i_size -= 2048; 4728c2ecf20Sopenharmony_ci i->i_blocks -= 4; 4738c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, 5); 4748c2ecf20Sopenharmony_ci if (up == to) return to; 4758c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return 0; 4768c2ecf20Sopenharmony_ci if (dnode->root_dnode) { 4778c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: got to root_dnode while moving from %08x to %08x", from, to); 4788c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci de = dnode_last_de(dnode); 4828c2ecf20Sopenharmony_ci if (!de || !de->down) { 4838c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: dnode %08x doesn't point down to %08x", up, dno); 4848c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci le32_add_cpu(&dnode->first_free, -4); 4888c2ecf20Sopenharmony_ci le16_add_cpu(&de->length, -4); 4898c2ecf20Sopenharmony_ci de->down = 0; 4908c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 4918c2ecf20Sopenharmony_ci dno = up; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci t = get_pos(dnode, de); 4948c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, t, 4); 4958c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, t + 1, 5); 4968c2ecf20Sopenharmony_ci if (!(nde = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) { 4978c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted"); 4988c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci memcpy(nde, de, le16_to_cpu(de->length)); 5028c2ecf20Sopenharmony_ci ddno = de->down ? de_down_pointer(de) : 0; 5038c2ecf20Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de); 5048c2ecf20Sopenharmony_ci set_last_pointer(i->i_sb, dnode, ddno); 5058c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 5068c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 5078c2ecf20Sopenharmony_ci a = hpfs_add_to_dnode(i, to, nde->name, nde->namelen, nde, from); 5088c2ecf20Sopenharmony_ci kfree(nde); 5098c2ecf20Sopenharmony_ci if (a) return 0; 5108c2ecf20Sopenharmony_ci return dno; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/* 5148c2ecf20Sopenharmony_ci * Check if a dnode is empty and delete it from the tree 5158c2ecf20Sopenharmony_ci * (chkdsk doesn't like empty dnodes) 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic void delete_empty_dnode(struct inode *i, dnode_secno dno) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(i); 5218c2ecf20Sopenharmony_ci struct quad_buffer_head qbh; 5228c2ecf20Sopenharmony_ci struct dnode *dnode; 5238c2ecf20Sopenharmony_ci dnode_secno down, up, ndown; 5248c2ecf20Sopenharmony_ci int p; 5258c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 5268c2ecf20Sopenharmony_ci int c1, c2 = 0; 5278c2ecf20Sopenharmony_ci try_it_again: 5288c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return; 5298c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return; 5308c2ecf20Sopenharmony_ci if (le32_to_cpu(dnode->first_free) > 56) goto end; 5318c2ecf20Sopenharmony_ci if (le32_to_cpu(dnode->first_free) == 52 || le32_to_cpu(dnode->first_free) == 56) { 5328c2ecf20Sopenharmony_ci struct hpfs_dirent *de_end; 5338c2ecf20Sopenharmony_ci int root = dnode->root_dnode; 5348c2ecf20Sopenharmony_ci up = le32_to_cpu(dnode->up); 5358c2ecf20Sopenharmony_ci de = dnode_first_de(dnode); 5368c2ecf20Sopenharmony_ci down = de->down ? de_down_pointer(de) : 0; 5378c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) if (root && !down) { 5388c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: root dnode %08x is empty", dno); 5398c2ecf20Sopenharmony_ci goto end; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 5428c2ecf20Sopenharmony_ci hpfs_free_dnode(i->i_sb, dno); 5438c2ecf20Sopenharmony_ci i->i_size -= 2048; 5448c2ecf20Sopenharmony_ci i->i_blocks -= 4; 5458c2ecf20Sopenharmony_ci if (root) { 5468c2ecf20Sopenharmony_ci struct fnode *fnode; 5478c2ecf20Sopenharmony_ci struct buffer_head *bh; 5488c2ecf20Sopenharmony_ci struct dnode *d1; 5498c2ecf20Sopenharmony_ci struct quad_buffer_head qbh1; 5508c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 5518c2ecf20Sopenharmony_ci if (up != i->i_ino) { 5528c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, 5538c2ecf20Sopenharmony_ci "bad pointer to fnode, dnode %08x, pointing to %08x, should be %08lx", 5548c2ecf20Sopenharmony_ci dno, up, 5558c2ecf20Sopenharmony_ci (unsigned long)i->i_ino); 5568c2ecf20Sopenharmony_ci return; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { 5598c2ecf20Sopenharmony_ci d1->up = cpu_to_le32(up); 5608c2ecf20Sopenharmony_ci d1->root_dnode = 1; 5618c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 5628c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) { 5658c2ecf20Sopenharmony_ci fnode->u.external[0].disk_secno = cpu_to_le32(down); 5668c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 5678c2ecf20Sopenharmony_ci brelse(bh); 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci hpfs_inode->i_dno = down; 5708c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12); 5718c2ecf20Sopenharmony_ci return; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return; 5748c2ecf20Sopenharmony_ci p = 1; 5758c2ecf20Sopenharmony_ci de_end = dnode_end_de(dnode); 5768c2ecf20Sopenharmony_ci for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de), p++) 5778c2ecf20Sopenharmony_ci if (de->down) if (de_down_pointer(de) == dno) goto fnd; 5788c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: pointer to dnode %08x not found in dnode %08x", dno, up); 5798c2ecf20Sopenharmony_ci goto end; 5808c2ecf20Sopenharmony_ci fnd: 5818c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p); 5828c2ecf20Sopenharmony_ci if (!down) { 5838c2ecf20Sopenharmony_ci de->down = 0; 5848c2ecf20Sopenharmony_ci le16_add_cpu(&de->length, -4); 5858c2ecf20Sopenharmony_ci le32_add_cpu(&dnode->first_free, -4); 5868c2ecf20Sopenharmony_ci memmove(de_next_de(de), (char *)de_next_de(de) + 4, 5878c2ecf20Sopenharmony_ci (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de)); 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci struct dnode *d1; 5908c2ecf20Sopenharmony_ci struct quad_buffer_head qbh1; 5918c2ecf20Sopenharmony_ci *(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4) = down; 5928c2ecf20Sopenharmony_ci if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { 5938c2ecf20Sopenharmony_ci d1->up = cpu_to_le32(up); 5948c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 5958c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci } else { 5998c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, le32_to_cpu(dnode->first_free)); 6008c2ecf20Sopenharmony_ci goto end; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (!de->last) { 6048c2ecf20Sopenharmony_ci struct hpfs_dirent *de_next = de_next_de(de); 6058c2ecf20Sopenharmony_ci struct hpfs_dirent *de_cp; 6068c2ecf20Sopenharmony_ci struct dnode *d1; 6078c2ecf20Sopenharmony_ci struct quad_buffer_head qbh1; 6088c2ecf20Sopenharmony_ci if (!de_next->down) goto endm; 6098c2ecf20Sopenharmony_ci ndown = de_down_pointer(de_next); 6108c2ecf20Sopenharmony_ci if (!(de_cp = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) { 6118c2ecf20Sopenharmony_ci pr_err("out of memory for dtree balancing\n"); 6128c2ecf20Sopenharmony_ci goto endm; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci memcpy(de_cp, de, le16_to_cpu(de->length)); 6158c2ecf20Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de); 6168c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 6178c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 6188c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4); 6198c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1); 6208c2ecf20Sopenharmony_ci if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) { 6218c2ecf20Sopenharmony_ci d1->up = cpu_to_le32(ndown); 6228c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 6238c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, de_cp->down ? de_down_pointer(de_cp) : 0); 6268c2ecf20Sopenharmony_ci /*pr_info("UP-TO-DNODE: %08x (ndown = %08x, down = %08x, dno = %08x)\n", 6278c2ecf20Sopenharmony_ci up, ndown, down, dno);*/ 6288c2ecf20Sopenharmony_ci dno = up; 6298c2ecf20Sopenharmony_ci kfree(de_cp); 6308c2ecf20Sopenharmony_ci goto try_it_again; 6318c2ecf20Sopenharmony_ci } else { 6328c2ecf20Sopenharmony_ci struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode); 6338c2ecf20Sopenharmony_ci struct hpfs_dirent *de_cp; 6348c2ecf20Sopenharmony_ci struct dnode *d1; 6358c2ecf20Sopenharmony_ci struct quad_buffer_head qbh1; 6368c2ecf20Sopenharmony_ci dnode_secno dlp; 6378c2ecf20Sopenharmony_ci if (!de_prev) { 6388c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: empty dnode %08x", up); 6398c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 6408c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 6418c2ecf20Sopenharmony_ci dno = up; 6428c2ecf20Sopenharmony_ci goto try_it_again; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci if (!de_prev->down) goto endm; 6458c2ecf20Sopenharmony_ci ndown = de_down_pointer(de_prev); 6468c2ecf20Sopenharmony_ci if ((d1 = hpfs_map_dnode(i->i_sb, ndown, &qbh1))) { 6478c2ecf20Sopenharmony_ci struct hpfs_dirent *del = dnode_last_de(d1); 6488c2ecf20Sopenharmony_ci dlp = del->down ? de_down_pointer(del) : 0; 6498c2ecf20Sopenharmony_ci if (!dlp && down) { 6508c2ecf20Sopenharmony_ci if (le32_to_cpu(d1->first_free) > 2044) { 6518c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk >= 2) { 6528c2ecf20Sopenharmony_ci pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n"); 6538c2ecf20Sopenharmony_ci pr_err("terminating balancing operation\n"); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 6568c2ecf20Sopenharmony_ci goto endm; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk >= 2) { 6598c2ecf20Sopenharmony_ci pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n"); 6608c2ecf20Sopenharmony_ci pr_err("goin'on\n"); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci le16_add_cpu(&del->length, 4); 6638c2ecf20Sopenharmony_ci del->down = 1; 6648c2ecf20Sopenharmony_ci le32_add_cpu(&d1->first_free, 4); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci if (dlp && !down) { 6678c2ecf20Sopenharmony_ci le16_add_cpu(&del->length, -4); 6688c2ecf20Sopenharmony_ci del->down = 0; 6698c2ecf20Sopenharmony_ci le32_add_cpu(&d1->first_free, -4); 6708c2ecf20Sopenharmony_ci } else if (down) 6718c2ecf20Sopenharmony_ci *(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down); 6728c2ecf20Sopenharmony_ci } else goto endm; 6738c2ecf20Sopenharmony_ci if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) { 6748c2ecf20Sopenharmony_ci pr_err("out of memory for dtree balancing\n"); 6758c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 6768c2ecf20Sopenharmony_ci goto endm; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 6798c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 6808c2ecf20Sopenharmony_ci memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length)); 6818c2ecf20Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de_prev); 6828c2ecf20Sopenharmony_ci if (!de_prev->down) { 6838c2ecf20Sopenharmony_ci le16_add_cpu(&de_prev->length, 4); 6848c2ecf20Sopenharmony_ci de_prev->down = 1; 6858c2ecf20Sopenharmony_ci le32_add_cpu(&dnode->first_free, 4); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci *(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown); 6888c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 6898c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 6908c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4); 6918c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1)); 6928c2ecf20Sopenharmony_ci if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) { 6938c2ecf20Sopenharmony_ci d1->up = cpu_to_le32(ndown); 6948c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 6958c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh1); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, dlp); 6988c2ecf20Sopenharmony_ci dno = up; 6998c2ecf20Sopenharmony_ci kfree(de_cp); 7008c2ecf20Sopenharmony_ci goto try_it_again; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci endm: 7038c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 7048c2ecf20Sopenharmony_ci end: 7058c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci/* Delete dirent from directory */ 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ciint hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, 7128c2ecf20Sopenharmony_ci struct quad_buffer_head *qbh, int depth) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct dnode *dnode = qbh->data; 7158c2ecf20Sopenharmony_ci dnode_secno down = 0; 7168c2ecf20Sopenharmony_ci loff_t t; 7178c2ecf20Sopenharmony_ci if (de->first || de->last) { 7188c2ecf20Sopenharmony_ci hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno); 7198c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 7208c2ecf20Sopenharmony_ci return 1; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci if (de->down) down = de_down_pointer(de); 7238c2ecf20Sopenharmony_ci if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) { 7248c2ecf20Sopenharmony_ci if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) { 7258c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 7268c2ecf20Sopenharmony_ci return 2; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1); 7308c2ecf20Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de); 7318c2ecf20Sopenharmony_ci hpfs_mark_4buffers_dirty(qbh); 7328c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 7338c2ecf20Sopenharmony_ci if (down) { 7348c2ecf20Sopenharmony_ci dnode_secno a = move_to_top(i, down, dno); 7358c2ecf20Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, 5, t); 7368c2ecf20Sopenharmony_ci if (a) delete_empty_dnode(i, a); 7378c2ecf20Sopenharmony_ci return !a; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci delete_empty_dnode(i, dno); 7408c2ecf20Sopenharmony_ci return 0; 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_civoid hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes, 7448c2ecf20Sopenharmony_ci int *n_subdirs, int *n_items) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct dnode *dnode; 7478c2ecf20Sopenharmony_ci struct quad_buffer_head qbh; 7488c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 7498c2ecf20Sopenharmony_ci dnode_secno ptr, odno = 0; 7508c2ecf20Sopenharmony_ci int c1, c2 = 0; 7518c2ecf20Sopenharmony_ci int d1, d2 = 0; 7528c2ecf20Sopenharmony_ci go_down: 7538c2ecf20Sopenharmony_ci if (n_dnodes) (*n_dnodes)++; 7548c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 7558c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(s, dno, &c1, &c2, "hpfs_count_dnodes #1")) return; 7568c2ecf20Sopenharmony_ci ptr = 0; 7578c2ecf20Sopenharmony_ci go_up: 7588c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return; 7598c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && le32_to_cpu(dnode->up) != odno) 7608c2ecf20Sopenharmony_ci hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, le32_to_cpu(dnode->up)); 7618c2ecf20Sopenharmony_ci de = dnode_first_de(dnode); 7628c2ecf20Sopenharmony_ci if (ptr) while(1) { 7638c2ecf20Sopenharmony_ci if (de->down) if (de_down_pointer(de) == ptr) goto process_de; 7648c2ecf20Sopenharmony_ci if (de->last) { 7658c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 7668c2ecf20Sopenharmony_ci hpfs_error(s, "hpfs_count_dnodes: pointer to dnode %08x not found in dnode %08x, got here from %08x", 7678c2ecf20Sopenharmony_ci ptr, dno, odno); 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci de = de_next_de(de); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci next_de: 7738c2ecf20Sopenharmony_ci if (de->down) { 7748c2ecf20Sopenharmony_ci odno = dno; 7758c2ecf20Sopenharmony_ci dno = de_down_pointer(de); 7768c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 7778c2ecf20Sopenharmony_ci goto go_down; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci process_de: 7808c2ecf20Sopenharmony_ci if (!de->first && !de->last && de->directory && n_subdirs) (*n_subdirs)++; 7818c2ecf20Sopenharmony_ci if (!de->first && !de->last && n_items) (*n_items)++; 7828c2ecf20Sopenharmony_ci if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de; 7838c2ecf20Sopenharmony_ci ptr = dno; 7848c2ecf20Sopenharmony_ci dno = le32_to_cpu(dnode->up); 7858c2ecf20Sopenharmony_ci if (dnode->root_dnode) { 7868c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 7878c2ecf20Sopenharmony_ci return; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 7908c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 7918c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(s, ptr, &d1, &d2, "hpfs_count_dnodes #2")) return; 7928c2ecf20Sopenharmony_ci odno = -1; 7938c2ecf20Sopenharmony_ci goto go_up; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic struct hpfs_dirent *map_nth_dirent(struct super_block *s, dnode_secno dno, int n, 7978c2ecf20Sopenharmony_ci struct quad_buffer_head *qbh, struct dnode **dn) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci int i; 8008c2ecf20Sopenharmony_ci struct hpfs_dirent *de, *de_end; 8018c2ecf20Sopenharmony_ci struct dnode *dnode; 8028c2ecf20Sopenharmony_ci dnode = hpfs_map_dnode(s, dno, qbh); 8038c2ecf20Sopenharmony_ci if (!dnode) return NULL; 8048c2ecf20Sopenharmony_ci if (dn) *dn=dnode; 8058c2ecf20Sopenharmony_ci de = dnode_first_de(dnode); 8068c2ecf20Sopenharmony_ci de_end = dnode_end_de(dnode); 8078c2ecf20Sopenharmony_ci for (i = 1; de < de_end; i++, de = de_next_de(de)) { 8088c2ecf20Sopenharmony_ci if (i == n) { 8098c2ecf20Sopenharmony_ci return de; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci if (de->last) break; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 8148c2ecf20Sopenharmony_ci hpfs_error(s, "map_nth_dirent: n too high; dnode = %08x, requested %08x", dno, n); 8158c2ecf20Sopenharmony_ci return NULL; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cidnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct quad_buffer_head qbh; 8218c2ecf20Sopenharmony_ci dnode_secno d = dno; 8228c2ecf20Sopenharmony_ci dnode_secno up = 0; 8238c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 8248c2ecf20Sopenharmony_ci int c1, c2 = 0; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci again: 8278c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 8288c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(s, d, &c1, &c2, "hpfs_de_as_down_as_possible")) 8298c2ecf20Sopenharmony_ci return d; 8308c2ecf20Sopenharmony_ci if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno; 8318c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 8328c2ecf20Sopenharmony_ci if (up && le32_to_cpu(((struct dnode *)qbh.data)->up) != up) 8338c2ecf20Sopenharmony_ci hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, le32_to_cpu(((struct dnode *)qbh.data)->up)); 8348c2ecf20Sopenharmony_ci if (!de->down) { 8358c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 8368c2ecf20Sopenharmony_ci return d; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci up = d; 8398c2ecf20Sopenharmony_ci d = de_down_pointer(de); 8408c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 8418c2ecf20Sopenharmony_ci goto again; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistruct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp, 8458c2ecf20Sopenharmony_ci struct quad_buffer_head *qbh) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci loff_t pos; 8488c2ecf20Sopenharmony_ci unsigned c; 8498c2ecf20Sopenharmony_ci dnode_secno dno; 8508c2ecf20Sopenharmony_ci struct hpfs_dirent *de, *d; 8518c2ecf20Sopenharmony_ci struct hpfs_dirent *up_de; 8528c2ecf20Sopenharmony_ci struct hpfs_dirent *end_up_de; 8538c2ecf20Sopenharmony_ci struct dnode *dnode; 8548c2ecf20Sopenharmony_ci struct dnode *up_dnode; 8558c2ecf20Sopenharmony_ci struct quad_buffer_head qbh0; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci pos = *posp; 8588c2ecf20Sopenharmony_ci dno = pos >> 6 << 2; 8598c2ecf20Sopenharmony_ci pos &= 077; 8608c2ecf20Sopenharmony_ci if (!(de = map_nth_dirent(inode->i_sb, dno, pos, qbh, &dnode))) 8618c2ecf20Sopenharmony_ci goto bail; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Going to the next dirent */ 8648c2ecf20Sopenharmony_ci if ((d = de_next_de(de)) < dnode_end_de(dnode)) { 8658c2ecf20Sopenharmony_ci if (!(++*posp & 077)) { 8668c2ecf20Sopenharmony_ci hpfs_error(inode->i_sb, 8678c2ecf20Sopenharmony_ci "map_pos_dirent: pos crossed dnode boundary; pos = %08llx", 8688c2ecf20Sopenharmony_ci (unsigned long long)*posp); 8698c2ecf20Sopenharmony_ci goto bail; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci /* We're going down the tree */ 8728c2ecf20Sopenharmony_ci if (d->down) { 8738c2ecf20Sopenharmony_ci *posp = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, de_down_pointer(d)) << 4) + 1; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci return de; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* Going up */ 8808c2ecf20Sopenharmony_ci if (dnode->root_dnode) goto bail; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (!(up_dnode = hpfs_map_dnode(inode->i_sb, le32_to_cpu(dnode->up), &qbh0))) 8838c2ecf20Sopenharmony_ci goto bail; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci end_up_de = dnode_end_de(up_dnode); 8868c2ecf20Sopenharmony_ci c = 0; 8878c2ecf20Sopenharmony_ci for (up_de = dnode_first_de(up_dnode); up_de < end_up_de; 8888c2ecf20Sopenharmony_ci up_de = de_next_de(up_de)) { 8898c2ecf20Sopenharmony_ci if (!(++c & 077)) hpfs_error(inode->i_sb, 8908c2ecf20Sopenharmony_ci "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", le32_to_cpu(dnode->up)); 8918c2ecf20Sopenharmony_ci if (up_de->down && de_down_pointer(up_de) == dno) { 8928c2ecf20Sopenharmony_ci *posp = ((loff_t) le32_to_cpu(dnode->up) << 4) + c; 8938c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh0); 8948c2ecf20Sopenharmony_ci return de; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x", 8998c2ecf20Sopenharmony_ci dno, le32_to_cpu(dnode->up)); 9008c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh0); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci bail: 9038c2ecf20Sopenharmony_ci *posp = 12; 9048c2ecf20Sopenharmony_ci return de; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci/* Find a dirent in tree */ 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistruct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, 9108c2ecf20Sopenharmony_ci const unsigned char *name, unsigned len, 9118c2ecf20Sopenharmony_ci dnode_secno *dd, struct quad_buffer_head *qbh) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct dnode *dnode; 9148c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 9158c2ecf20Sopenharmony_ci struct hpfs_dirent *de_end; 9168c2ecf20Sopenharmony_ci int c1, c2 = 0; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n"); 9198c2ecf20Sopenharmony_ci again: 9208c2ecf20Sopenharmony_ci if (hpfs_sb(inode->i_sb)->sb_chk) 9218c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(inode->i_sb, dno, &c1, &c2, "map_dirent")) return NULL; 9228c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(inode->i_sb, dno, qbh))) return NULL; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci de_end = dnode_end_de(dnode); 9258c2ecf20Sopenharmony_ci for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de)) { 9268c2ecf20Sopenharmony_ci int t = hpfs_compare_names(inode->i_sb, name, len, de->name, de->namelen, de->last); 9278c2ecf20Sopenharmony_ci if (!t) { 9288c2ecf20Sopenharmony_ci if (dd) *dd = dno; 9298c2ecf20Sopenharmony_ci return de; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci if (t < 0) { 9328c2ecf20Sopenharmony_ci if (de->down) { 9338c2ecf20Sopenharmony_ci dno = de_down_pointer(de); 9348c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 9358c2ecf20Sopenharmony_ci goto again; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 9418c2ecf20Sopenharmony_ci return NULL; 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci/* 9458c2ecf20Sopenharmony_ci * Remove empty directory. In normal cases it is only one dnode with two 9468c2ecf20Sopenharmony_ci * entries, but we must handle also such obscure cases when it's a tree 9478c2ecf20Sopenharmony_ci * of empty dnodes. 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_civoid hpfs_remove_dtree(struct super_block *s, dnode_secno dno) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct quad_buffer_head qbh; 9538c2ecf20Sopenharmony_ci struct dnode *dnode; 9548c2ecf20Sopenharmony_ci struct hpfs_dirent *de; 9558c2ecf20Sopenharmony_ci dnode_secno d1, d2, rdno = dno; 9568c2ecf20Sopenharmony_ci while (1) { 9578c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return; 9588c2ecf20Sopenharmony_ci de = dnode_first_de(dnode); 9598c2ecf20Sopenharmony_ci if (de->last) { 9608c2ecf20Sopenharmony_ci if (de->down) d1 = de_down_pointer(de); 9618c2ecf20Sopenharmony_ci else goto error; 9628c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 9638c2ecf20Sopenharmony_ci hpfs_free_dnode(s, dno); 9648c2ecf20Sopenharmony_ci dno = d1; 9658c2ecf20Sopenharmony_ci } else break; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci if (!de->first) goto error; 9688c2ecf20Sopenharmony_ci d1 = de->down ? de_down_pointer(de) : 0; 9698c2ecf20Sopenharmony_ci de = de_next_de(de); 9708c2ecf20Sopenharmony_ci if (!de->last) goto error; 9718c2ecf20Sopenharmony_ci d2 = de->down ? de_down_pointer(de) : 0; 9728c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 9738c2ecf20Sopenharmony_ci hpfs_free_dnode(s, dno); 9748c2ecf20Sopenharmony_ci do { 9758c2ecf20Sopenharmony_ci while (d1) { 9768c2ecf20Sopenharmony_ci if (!(dnode = hpfs_map_dnode(s, dno = d1, &qbh))) return; 9778c2ecf20Sopenharmony_ci de = dnode_first_de(dnode); 9788c2ecf20Sopenharmony_ci if (!de->last) goto error; 9798c2ecf20Sopenharmony_ci d1 = de->down ? de_down_pointer(de) : 0; 9808c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 9818c2ecf20Sopenharmony_ci hpfs_free_dnode(s, dno); 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci d1 = d2; 9848c2ecf20Sopenharmony_ci d2 = 0; 9858c2ecf20Sopenharmony_ci } while (d1); 9868c2ecf20Sopenharmony_ci return; 9878c2ecf20Sopenharmony_ci error: 9888c2ecf20Sopenharmony_ci hpfs_brelse4(&qbh); 9898c2ecf20Sopenharmony_ci hpfs_free_dnode(s, dno); 9908c2ecf20Sopenharmony_ci hpfs_error(s, "directory %08x is corrupted or not empty", rdno); 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci/* 9948c2ecf20Sopenharmony_ci * Find dirent for specified fnode. Use truncated 15-char name in fnode as 9958c2ecf20Sopenharmony_ci * a help for searching. 9968c2ecf20Sopenharmony_ci */ 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistruct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, 9998c2ecf20Sopenharmony_ci struct fnode *f, struct quad_buffer_head *qbh) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci unsigned char *name1; 10028c2ecf20Sopenharmony_ci unsigned char *name2; 10038c2ecf20Sopenharmony_ci int name1len, name2len; 10048c2ecf20Sopenharmony_ci struct dnode *d; 10058c2ecf20Sopenharmony_ci dnode_secno dno, downd; 10068c2ecf20Sopenharmony_ci struct fnode *upf; 10078c2ecf20Sopenharmony_ci struct buffer_head *bh; 10088c2ecf20Sopenharmony_ci struct hpfs_dirent *de, *de_end; 10098c2ecf20Sopenharmony_ci int c; 10108c2ecf20Sopenharmony_ci int c1, c2 = 0; 10118c2ecf20Sopenharmony_ci int d1, d2 = 0; 10128c2ecf20Sopenharmony_ci name1 = f->name; 10138c2ecf20Sopenharmony_ci if (!(name2 = kmalloc(256, GFP_NOFS))) { 10148c2ecf20Sopenharmony_ci pr_err("out of memory, can't map dirent\n"); 10158c2ecf20Sopenharmony_ci return NULL; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci if (f->len <= 15) 10188c2ecf20Sopenharmony_ci memcpy(name2, name1, name1len = name2len = f->len); 10198c2ecf20Sopenharmony_ci else { 10208c2ecf20Sopenharmony_ci memcpy(name2, name1, 15); 10218c2ecf20Sopenharmony_ci memset(name2 + 15, 0xff, 256 - 15); 10228c2ecf20Sopenharmony_ci /*name2[15] = 0xff;*/ 10238c2ecf20Sopenharmony_ci name1len = 15; name2len = 256; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci if (!(upf = hpfs_map_fnode(s, le32_to_cpu(f->up), &bh))) { 10268c2ecf20Sopenharmony_ci kfree(name2); 10278c2ecf20Sopenharmony_ci return NULL; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci if (!fnode_is_dir(upf)) { 10308c2ecf20Sopenharmony_ci brelse(bh); 10318c2ecf20Sopenharmony_ci hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up)); 10328c2ecf20Sopenharmony_ci kfree(name2); 10338c2ecf20Sopenharmony_ci return NULL; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci dno = le32_to_cpu(upf->u.external[0].disk_secno); 10368c2ecf20Sopenharmony_ci brelse(bh); 10378c2ecf20Sopenharmony_ci go_down: 10388c2ecf20Sopenharmony_ci downd = 0; 10398c2ecf20Sopenharmony_ci go_up: 10408c2ecf20Sopenharmony_ci if (!(d = hpfs_map_dnode(s, dno, qbh))) { 10418c2ecf20Sopenharmony_ci kfree(name2); 10428c2ecf20Sopenharmony_ci return NULL; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci de_end = dnode_end_de(d); 10458c2ecf20Sopenharmony_ci de = dnode_first_de(d); 10468c2ecf20Sopenharmony_ci if (downd) { 10478c2ecf20Sopenharmony_ci while (de < de_end) { 10488c2ecf20Sopenharmony_ci if (de->down) if (de_down_pointer(de) == downd) goto f; 10498c2ecf20Sopenharmony_ci de = de_next_de(de); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci hpfs_error(s, "pointer to dnode %08x not found in dnode %08x", downd, dno); 10528c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 10538c2ecf20Sopenharmony_ci kfree(name2); 10548c2ecf20Sopenharmony_ci return NULL; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci next_de: 10578c2ecf20Sopenharmony_ci if (le32_to_cpu(de->fnode) == fno) { 10588c2ecf20Sopenharmony_ci kfree(name2); 10598c2ecf20Sopenharmony_ci return de; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci c = hpfs_compare_names(s, name1, name1len, de->name, de->namelen, de->last); 10628c2ecf20Sopenharmony_ci if (c < 0 && de->down) { 10638c2ecf20Sopenharmony_ci dno = de_down_pointer(de); 10648c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 10658c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 10668c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(s, dno, &c1, &c2, "map_fnode_dirent #1")) { 10678c2ecf20Sopenharmony_ci kfree(name2); 10688c2ecf20Sopenharmony_ci return NULL; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci goto go_down; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci f: 10738c2ecf20Sopenharmony_ci if (le32_to_cpu(de->fnode) == fno) { 10748c2ecf20Sopenharmony_ci kfree(name2); 10758c2ecf20Sopenharmony_ci return de; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci c = hpfs_compare_names(s, name2, name2len, de->name, de->namelen, de->last); 10788c2ecf20Sopenharmony_ci if (c < 0 && !de->last) goto not_found; 10798c2ecf20Sopenharmony_ci if ((de = de_next_de(de)) < de_end) goto next_de; 10808c2ecf20Sopenharmony_ci if (d->root_dnode) goto not_found; 10818c2ecf20Sopenharmony_ci downd = dno; 10828c2ecf20Sopenharmony_ci dno = le32_to_cpu(d->up); 10838c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 10848c2ecf20Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 10858c2ecf20Sopenharmony_ci if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) { 10868c2ecf20Sopenharmony_ci kfree(name2); 10878c2ecf20Sopenharmony_ci return NULL; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci goto go_up; 10908c2ecf20Sopenharmony_ci not_found: 10918c2ecf20Sopenharmony_ci hpfs_brelse4(qbh); 10928c2ecf20Sopenharmony_ci hpfs_error(s, "dirent for fnode %08x not found", fno); 10938c2ecf20Sopenharmony_ci kfree(name2); 10948c2ecf20Sopenharmony_ci return NULL; 10958c2ecf20Sopenharmony_ci} 1096