162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/hpfs/dnode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * handling directory dnode tree - adding, deleteing & searching for dirents 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "hpfs_fn.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci struct hpfs_dirent *de; 1562306a36Sopenharmony_ci struct hpfs_dirent *de_end = dnode_end_de(d); 1662306a36Sopenharmony_ci int i = 1; 1762306a36Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 1862306a36Sopenharmony_ci if (de == fde) return ((loff_t) le32_to_cpu(d->self) << 4) | (loff_t)i; 1962306a36Sopenharmony_ci i++; 2062306a36Sopenharmony_ci } 2162306a36Sopenharmony_ci pr_info("%s(): not_found\n", __func__); 2262306a36Sopenharmony_ci return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1; 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciint hpfs_add_pos(struct inode *inode, loff_t *pos) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); 2862306a36Sopenharmony_ci int i = 0; 2962306a36Sopenharmony_ci loff_t **ppos; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (hpfs_inode->i_rddir_off) 3262306a36Sopenharmony_ci for (; hpfs_inode->i_rddir_off[i]; i++) 3362306a36Sopenharmony_ci if (hpfs_inode->i_rddir_off[i] == pos) 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci if (!(i&0x0f)) { 3662306a36Sopenharmony_ci ppos = kmalloc_array(i + 0x11, sizeof(loff_t *), GFP_NOFS); 3762306a36Sopenharmony_ci if (!ppos) { 3862306a36Sopenharmony_ci pr_err("out of memory for position list\n"); 3962306a36Sopenharmony_ci return -ENOMEM; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci if (hpfs_inode->i_rddir_off) { 4262306a36Sopenharmony_ci memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t)); 4362306a36Sopenharmony_ci kfree(hpfs_inode->i_rddir_off); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci hpfs_inode->i_rddir_off = ppos; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci hpfs_inode->i_rddir_off[i] = pos; 4862306a36Sopenharmony_ci hpfs_inode->i_rddir_off[i + 1] = NULL; 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_civoid hpfs_del_pos(struct inode *inode, loff_t *pos) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); 5562306a36Sopenharmony_ci loff_t **i, **j; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (!hpfs_inode->i_rddir_off) goto not_f; 5862306a36Sopenharmony_ci for (i = hpfs_inode->i_rddir_off; *i; i++) if (*i == pos) goto fnd; 5962306a36Sopenharmony_ci goto not_f; 6062306a36Sopenharmony_ci fnd: 6162306a36Sopenharmony_ci for (j = i + 1; *j; j++) ; 6262306a36Sopenharmony_ci *i = *(j - 1); 6362306a36Sopenharmony_ci *(j - 1) = NULL; 6462306a36Sopenharmony_ci if (j - 1 == hpfs_inode->i_rddir_off) { 6562306a36Sopenharmony_ci kfree(hpfs_inode->i_rddir_off); 6662306a36Sopenharmony_ci hpfs_inode->i_rddir_off = NULL; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci return; 6962306a36Sopenharmony_ci not_f: 7062306a36Sopenharmony_ci /*pr_warn("position pointer %p->%08x not found\n", 7162306a36Sopenharmony_ci pos, (int)*pos);*/ 7262306a36Sopenharmony_ci return; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t), 7662306a36Sopenharmony_ci loff_t p1, loff_t p2) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); 7962306a36Sopenharmony_ci loff_t **i; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (!hpfs_inode->i_rddir_off) return; 8262306a36Sopenharmony_ci for (i = hpfs_inode->i_rddir_off; *i; i++) (*f)(*i, p1, p2); 8362306a36Sopenharmony_ci return; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci if (*p == f) *p = t; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/*void hpfs_hpfs_pos_substd(loff_t *p, loff_t f, loff_t t) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci if ((*p & ~0x3f) == (f & ~0x3f)) *p = (t & ~0x3f) | (*p & 0x3f); 9462306a36Sopenharmony_ci}*/ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) { 9962306a36Sopenharmony_ci int n = (*p & 0x3f) + c; 10062306a36Sopenharmony_ci if (n > 0x3f) 10162306a36Sopenharmony_ci pr_err("%s(): %08x + %d\n", 10262306a36Sopenharmony_ci __func__, (int)*p, (int)c >> 8); 10362306a36Sopenharmony_ci else 10462306a36Sopenharmony_ci *p = (*p & ~0x3f) | n; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void hpfs_pos_del(loff_t *p, loff_t d, loff_t c) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) { 11162306a36Sopenharmony_ci int n = (*p & 0x3f) - c; 11262306a36Sopenharmony_ci if (n < 1) 11362306a36Sopenharmony_ci pr_err("%s(): %08x - %d\n", 11462306a36Sopenharmony_ci __func__, (int)*p, (int)c >> 8); 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci *p = (*p & ~0x3f) | n; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct hpfs_dirent *dnode_pre_last_de(struct dnode *d) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct hpfs_dirent *de, *de_end, *dee = NULL, *deee = NULL; 12362306a36Sopenharmony_ci de_end = dnode_end_de(d); 12462306a36Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 12562306a36Sopenharmony_ci deee = dee; dee = de; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci return deee; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic struct hpfs_dirent *dnode_last_de(struct dnode *d) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct hpfs_dirent *de, *de_end, *dee = NULL; 13362306a36Sopenharmony_ci de_end = dnode_end_de(d); 13462306a36Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 13562306a36Sopenharmony_ci dee = de; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci return dee; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno ptr) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct hpfs_dirent *de; 14362306a36Sopenharmony_ci if (!(de = dnode_last_de(d))) { 14462306a36Sopenharmony_ci hpfs_error(s, "set_last_pointer: empty dnode %08x", le32_to_cpu(d->self)); 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) { 14862306a36Sopenharmony_ci if (de->down) { 14962306a36Sopenharmony_ci hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x", 15062306a36Sopenharmony_ci le32_to_cpu(d->self), de_down_pointer(de)); 15162306a36Sopenharmony_ci return; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci if (le16_to_cpu(de->length) != 32) { 15462306a36Sopenharmony_ci hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", le32_to_cpu(d->self)); 15562306a36Sopenharmony_ci return; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci if (ptr) { 15962306a36Sopenharmony_ci le32_add_cpu(&d->first_free, 4); 16062306a36Sopenharmony_ci if (le32_to_cpu(d->first_free) > 2048) { 16162306a36Sopenharmony_ci hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self)); 16262306a36Sopenharmony_ci le32_add_cpu(&d->first_free, -4); 16362306a36Sopenharmony_ci return; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci de->length = cpu_to_le16(36); 16662306a36Sopenharmony_ci de->down = 1; 16762306a36Sopenharmony_ci *(__le32 *)((char *)de + 32) = cpu_to_le32(ptr); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* Add an entry to dnode and don't care if it grows over 2048 bytes */ 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistruct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, 17462306a36Sopenharmony_ci const unsigned char *name, 17562306a36Sopenharmony_ci unsigned namelen, secno down_ptr) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct hpfs_dirent *de; 17862306a36Sopenharmony_ci struct hpfs_dirent *de_end = dnode_end_de(d); 17962306a36Sopenharmony_ci unsigned d_size = de_size(namelen, down_ptr); 18062306a36Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 18162306a36Sopenharmony_ci int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last); 18262306a36Sopenharmony_ci if (!c) { 18362306a36Sopenharmony_ci hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, le32_to_cpu(d->self)); 18462306a36Sopenharmony_ci return NULL; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci if (c < 0) break; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci memmove((char *)de + d_size, de, (char *)de_end - (char *)de); 18962306a36Sopenharmony_ci memset(de, 0, d_size); 19062306a36Sopenharmony_ci if (down_ptr) { 19162306a36Sopenharmony_ci *(__le32 *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr); 19262306a36Sopenharmony_ci de->down = 1; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci de->length = cpu_to_le16(d_size); 19562306a36Sopenharmony_ci de->not_8x3 = hpfs_is_name_long(name, namelen); 19662306a36Sopenharmony_ci de->namelen = namelen; 19762306a36Sopenharmony_ci memcpy(de->name, name, namelen); 19862306a36Sopenharmony_ci le32_add_cpu(&d->first_free, d_size); 19962306a36Sopenharmony_ci return de; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* Delete dirent and don't care about its subtree */ 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void hpfs_delete_de(struct super_block *s, struct dnode *d, 20562306a36Sopenharmony_ci struct hpfs_dirent *de) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci if (de->last) { 20862306a36Sopenharmony_ci hpfs_error(s, "attempt to delete last dirent in dnode %08x", le32_to_cpu(d->self)); 20962306a36Sopenharmony_ci return; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - le16_to_cpu(de->length)); 21262306a36Sopenharmony_ci memmove(de, de_next_de(de), le32_to_cpu(d->first_free) + (char *)d - (char *)de); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void fix_up_ptrs(struct super_block *s, struct dnode *d) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct hpfs_dirent *de; 21862306a36Sopenharmony_ci struct hpfs_dirent *de_end = dnode_end_de(d); 21962306a36Sopenharmony_ci dnode_secno dno = le32_to_cpu(d->self); 22062306a36Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) 22162306a36Sopenharmony_ci if (de->down) { 22262306a36Sopenharmony_ci struct quad_buffer_head qbh; 22362306a36Sopenharmony_ci struct dnode *dd; 22462306a36Sopenharmony_ci if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) { 22562306a36Sopenharmony_ci if (le32_to_cpu(dd->up) != dno || dd->root_dnode) { 22662306a36Sopenharmony_ci dd->up = cpu_to_le32(dno); 22762306a36Sopenharmony_ci dd->root_dnode = 0; 22862306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci hpfs_brelse4(&qbh); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* Add an entry to dnode and do dnode splitting if required */ 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, 23862306a36Sopenharmony_ci const unsigned char *name, unsigned namelen, 23962306a36Sopenharmony_ci struct hpfs_dirent *new_de, dnode_secno down_ptr) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct quad_buffer_head qbh, qbh1, qbh2; 24262306a36Sopenharmony_ci struct dnode *d, *ad, *rd, *nd = NULL; 24362306a36Sopenharmony_ci dnode_secno adno, rdno; 24462306a36Sopenharmony_ci struct hpfs_dirent *de; 24562306a36Sopenharmony_ci struct hpfs_dirent nde; 24662306a36Sopenharmony_ci unsigned char *nname; 24762306a36Sopenharmony_ci int h; 24862306a36Sopenharmony_ci int pos; 24962306a36Sopenharmony_ci struct buffer_head *bh; 25062306a36Sopenharmony_ci struct fnode *fnode; 25162306a36Sopenharmony_ci int c1, c2 = 0; 25262306a36Sopenharmony_ci if (!(nname = kmalloc(256, GFP_NOFS))) { 25362306a36Sopenharmony_ci pr_err("out of memory, can't add to dnode\n"); 25462306a36Sopenharmony_ci return 1; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci go_up: 25762306a36Sopenharmony_ci if (namelen >= 256) { 25862306a36Sopenharmony_ci hpfs_error(i->i_sb, "%s(): namelen == %d", __func__, namelen); 25962306a36Sopenharmony_ci kfree(nd); 26062306a36Sopenharmony_ci kfree(nname); 26162306a36Sopenharmony_ci return 1; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) { 26462306a36Sopenharmony_ci kfree(nd); 26562306a36Sopenharmony_ci kfree(nname); 26662306a36Sopenharmony_ci return 1; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci go_up_a: 26962306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 27062306a36Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_to_dnode")) { 27162306a36Sopenharmony_ci hpfs_brelse4(&qbh); 27262306a36Sopenharmony_ci kfree(nd); 27362306a36Sopenharmony_ci kfree(nname); 27462306a36Sopenharmony_ci return 1; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci if (le32_to_cpu(d->first_free) + de_size(namelen, down_ptr) <= 2048) { 27762306a36Sopenharmony_ci loff_t t; 27862306a36Sopenharmony_ci copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de); 27962306a36Sopenharmony_ci t = get_pos(d, de); 28062306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_ins, t, 1); 28162306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, 4, t); 28262306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, 5, t + 1); 28362306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 28462306a36Sopenharmony_ci hpfs_brelse4(&qbh); 28562306a36Sopenharmony_ci kfree(nd); 28662306a36Sopenharmony_ci kfree(nname); 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci if (!nd) if (!(nd = kmalloc(0x924, GFP_NOFS))) { 29062306a36Sopenharmony_ci /* 0x924 is a max size of dnode after adding a dirent with 29162306a36Sopenharmony_ci max name length. We alloc this only once. There must 29262306a36Sopenharmony_ci not be any error while splitting dnodes, otherwise the 29362306a36Sopenharmony_ci whole directory, not only file we're adding, would 29462306a36Sopenharmony_ci be lost. */ 29562306a36Sopenharmony_ci pr_err("out of memory for dnode splitting\n"); 29662306a36Sopenharmony_ci hpfs_brelse4(&qbh); 29762306a36Sopenharmony_ci kfree(nname); 29862306a36Sopenharmony_ci return 1; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci memcpy(nd, d, le32_to_cpu(d->first_free)); 30162306a36Sopenharmony_ci copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de); 30262306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1); 30362306a36Sopenharmony_ci h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10; 30462306a36Sopenharmony_ci if (!(ad = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &adno, &qbh1))) { 30562306a36Sopenharmony_ci hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); 30662306a36Sopenharmony_ci hpfs_brelse4(&qbh); 30762306a36Sopenharmony_ci kfree(nd); 30862306a36Sopenharmony_ci kfree(nname); 30962306a36Sopenharmony_ci return 1; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci i->i_size += 2048; 31262306a36Sopenharmony_ci i->i_blocks += 4; 31362306a36Sopenharmony_ci pos = 1; 31462306a36Sopenharmony_ci for (de = dnode_first_de(nd); (char *)de_next_de(de) - (char *)nd < h; de = de_next_de(de)) { 31562306a36Sopenharmony_ci copy_de(hpfs_add_de(i->i_sb, ad, de->name, de->namelen, de->down ? de_down_pointer(de) : 0), de); 31662306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, ((loff_t)adno << 4) | pos); 31762306a36Sopenharmony_ci pos++; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci copy_de(new_de = &nde, de); 32062306a36Sopenharmony_ci memcpy(nname, de->name, de->namelen); 32162306a36Sopenharmony_ci name = nname; 32262306a36Sopenharmony_ci namelen = de->namelen; 32362306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4); 32462306a36Sopenharmony_ci down_ptr = adno; 32562306a36Sopenharmony_ci set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); 32662306a36Sopenharmony_ci de = de_next_de(de); 32762306a36Sopenharmony_ci memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de); 32862306a36Sopenharmony_ci le32_add_cpu(&nd->first_free, -((char *)de - (char *)nd - 20)); 32962306a36Sopenharmony_ci memcpy(d, nd, le32_to_cpu(nd->first_free)); 33062306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); 33162306a36Sopenharmony_ci fix_up_ptrs(i->i_sb, ad); 33262306a36Sopenharmony_ci if (!d->root_dnode) { 33362306a36Sopenharmony_ci ad->up = d->up; 33462306a36Sopenharmony_ci dno = le32_to_cpu(ad->up); 33562306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 33662306a36Sopenharmony_ci hpfs_brelse4(&qbh); 33762306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 33862306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 33962306a36Sopenharmony_ci goto go_up; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci if (!(rd = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &rdno, &qbh2))) { 34262306a36Sopenharmony_ci hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); 34362306a36Sopenharmony_ci hpfs_brelse4(&qbh); 34462306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 34562306a36Sopenharmony_ci kfree(nd); 34662306a36Sopenharmony_ci kfree(nname); 34762306a36Sopenharmony_ci return 1; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci i->i_size += 2048; 35062306a36Sopenharmony_ci i->i_blocks += 4; 35162306a36Sopenharmony_ci rd->root_dnode = 1; 35262306a36Sopenharmony_ci rd->up = d->up; 35362306a36Sopenharmony_ci if (!(fnode = hpfs_map_fnode(i->i_sb, le32_to_cpu(d->up), &bh))) { 35462306a36Sopenharmony_ci hpfs_free_dnode(i->i_sb, rdno); 35562306a36Sopenharmony_ci hpfs_brelse4(&qbh); 35662306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 35762306a36Sopenharmony_ci hpfs_brelse4(&qbh2); 35862306a36Sopenharmony_ci kfree(nd); 35962306a36Sopenharmony_ci kfree(nname); 36062306a36Sopenharmony_ci return 1; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci fnode->u.external[0].disk_secno = cpu_to_le32(rdno); 36362306a36Sopenharmony_ci mark_buffer_dirty(bh); 36462306a36Sopenharmony_ci brelse(bh); 36562306a36Sopenharmony_ci hpfs_i(i)->i_dno = rdno; 36662306a36Sopenharmony_ci d->up = ad->up = cpu_to_le32(rdno); 36762306a36Sopenharmony_ci d->root_dnode = ad->root_dnode = 0; 36862306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 36962306a36Sopenharmony_ci hpfs_brelse4(&qbh); 37062306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 37162306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 37262306a36Sopenharmony_ci qbh = qbh2; 37362306a36Sopenharmony_ci set_last_pointer(i->i_sb, rd, dno); 37462306a36Sopenharmony_ci dno = rdno; 37562306a36Sopenharmony_ci d = rd; 37662306a36Sopenharmony_ci goto go_up_a; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * Add an entry to directory btree. 38162306a36Sopenharmony_ci * I hate such crazy directory structure. 38262306a36Sopenharmony_ci * It's easy to read but terrible to write. 38362306a36Sopenharmony_ci * I wrote this directory code 4 times. 38462306a36Sopenharmony_ci * I hope, now it's finally bug-free. 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ciint hpfs_add_dirent(struct inode *i, 38862306a36Sopenharmony_ci const unsigned char *name, unsigned namelen, 38962306a36Sopenharmony_ci struct hpfs_dirent *new_de) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(i); 39262306a36Sopenharmony_ci struct dnode *d; 39362306a36Sopenharmony_ci struct hpfs_dirent *de, *de_end; 39462306a36Sopenharmony_ci struct quad_buffer_head qbh; 39562306a36Sopenharmony_ci dnode_secno dno; 39662306a36Sopenharmony_ci int c; 39762306a36Sopenharmony_ci int c1, c2 = 0; 39862306a36Sopenharmony_ci dno = hpfs_inode->i_dno; 39962306a36Sopenharmony_ci down: 40062306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 40162306a36Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1; 40262306a36Sopenharmony_ci if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 1; 40362306a36Sopenharmony_ci de_end = dnode_end_de(d); 40462306a36Sopenharmony_ci for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { 40562306a36Sopenharmony_ci if (!(c = hpfs_compare_names(i->i_sb, name, namelen, de->name, de->namelen, de->last))) { 40662306a36Sopenharmony_ci hpfs_brelse4(&qbh); 40762306a36Sopenharmony_ci return -1; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci if (c < 0) { 41062306a36Sopenharmony_ci if (de->down) { 41162306a36Sopenharmony_ci dno = de_down_pointer(de); 41262306a36Sopenharmony_ci hpfs_brelse4(&qbh); 41362306a36Sopenharmony_ci goto down; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci hpfs_brelse4(&qbh); 41962306a36Sopenharmony_ci if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) { 42062306a36Sopenharmony_ci c = 1; 42162306a36Sopenharmony_ci goto ret; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0); 42462306a36Sopenharmony_ci ret: 42562306a36Sopenharmony_ci return c; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* 42962306a36Sopenharmony_ci * Find dirent with higher name in 'from' subtree and move it to 'to' dnode. 43062306a36Sopenharmony_ci * Return the dnode we moved from (to be checked later if it's empty) 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci dnode_secno dno, ddno; 43662306a36Sopenharmony_ci dnode_secno chk_up = to; 43762306a36Sopenharmony_ci struct dnode *dnode; 43862306a36Sopenharmony_ci struct quad_buffer_head qbh; 43962306a36Sopenharmony_ci struct hpfs_dirent *de, *nde; 44062306a36Sopenharmony_ci int a; 44162306a36Sopenharmony_ci loff_t t; 44262306a36Sopenharmony_ci int c1, c2 = 0; 44362306a36Sopenharmony_ci dno = from; 44462306a36Sopenharmony_ci while (1) { 44562306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 44662306a36Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "move_to_top")) 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0; 44962306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) { 45062306a36Sopenharmony_ci if (le32_to_cpu(dnode->up) != chk_up) { 45162306a36Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x", 45262306a36Sopenharmony_ci dno, chk_up, le32_to_cpu(dnode->up)); 45362306a36Sopenharmony_ci hpfs_brelse4(&qbh); 45462306a36Sopenharmony_ci return 0; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci chk_up = dno; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci if (!(de = dnode_last_de(dnode))) { 45962306a36Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: dnode %08x has no last de", dno); 46062306a36Sopenharmony_ci hpfs_brelse4(&qbh); 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci if (!de->down) break; 46462306a36Sopenharmony_ci dno = de_down_pointer(de); 46562306a36Sopenharmony_ci hpfs_brelse4(&qbh); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci while (!(de = dnode_pre_last_de(dnode))) { 46862306a36Sopenharmony_ci dnode_secno up = le32_to_cpu(dnode->up); 46962306a36Sopenharmony_ci hpfs_brelse4(&qbh); 47062306a36Sopenharmony_ci hpfs_free_dnode(i->i_sb, dno); 47162306a36Sopenharmony_ci i->i_size -= 2048; 47262306a36Sopenharmony_ci i->i_blocks -= 4; 47362306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, 5); 47462306a36Sopenharmony_ci if (up == to) return to; 47562306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return 0; 47662306a36Sopenharmony_ci if (dnode->root_dnode) { 47762306a36Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: got to root_dnode while moving from %08x to %08x", from, to); 47862306a36Sopenharmony_ci hpfs_brelse4(&qbh); 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci de = dnode_last_de(dnode); 48262306a36Sopenharmony_ci if (!de || !de->down) { 48362306a36Sopenharmony_ci hpfs_error(i->i_sb, "move_to_top: dnode %08x doesn't point down to %08x", up, dno); 48462306a36Sopenharmony_ci hpfs_brelse4(&qbh); 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci le32_add_cpu(&dnode->first_free, -4); 48862306a36Sopenharmony_ci le16_add_cpu(&de->length, -4); 48962306a36Sopenharmony_ci de->down = 0; 49062306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 49162306a36Sopenharmony_ci dno = up; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci t = get_pos(dnode, de); 49462306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, t, 4); 49562306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, t + 1, 5); 49662306a36Sopenharmony_ci if (!(nde = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) { 49762306a36Sopenharmony_ci hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted"); 49862306a36Sopenharmony_ci hpfs_brelse4(&qbh); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci memcpy(nde, de, le16_to_cpu(de->length)); 50262306a36Sopenharmony_ci ddno = de->down ? de_down_pointer(de) : 0; 50362306a36Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de); 50462306a36Sopenharmony_ci set_last_pointer(i->i_sb, dnode, ddno); 50562306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 50662306a36Sopenharmony_ci hpfs_brelse4(&qbh); 50762306a36Sopenharmony_ci a = hpfs_add_to_dnode(i, to, nde->name, nde->namelen, nde, from); 50862306a36Sopenharmony_ci kfree(nde); 50962306a36Sopenharmony_ci if (a) return 0; 51062306a36Sopenharmony_ci return dno; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/* 51462306a36Sopenharmony_ci * Check if a dnode is empty and delete it from the tree 51562306a36Sopenharmony_ci * (chkdsk doesn't like empty dnodes) 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void delete_empty_dnode(struct inode *i, dnode_secno dno) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct hpfs_inode_info *hpfs_inode = hpfs_i(i); 52162306a36Sopenharmony_ci struct quad_buffer_head qbh; 52262306a36Sopenharmony_ci struct dnode *dnode; 52362306a36Sopenharmony_ci dnode_secno down, up, ndown; 52462306a36Sopenharmony_ci int p; 52562306a36Sopenharmony_ci struct hpfs_dirent *de; 52662306a36Sopenharmony_ci int c1, c2 = 0; 52762306a36Sopenharmony_ci try_it_again: 52862306a36Sopenharmony_ci if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return; 52962306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return; 53062306a36Sopenharmony_ci if (le32_to_cpu(dnode->first_free) > 56) goto end; 53162306a36Sopenharmony_ci if (le32_to_cpu(dnode->first_free) == 52 || le32_to_cpu(dnode->first_free) == 56) { 53262306a36Sopenharmony_ci struct hpfs_dirent *de_end; 53362306a36Sopenharmony_ci int root = dnode->root_dnode; 53462306a36Sopenharmony_ci up = le32_to_cpu(dnode->up); 53562306a36Sopenharmony_ci de = dnode_first_de(dnode); 53662306a36Sopenharmony_ci down = de->down ? de_down_pointer(de) : 0; 53762306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) if (root && !down) { 53862306a36Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: root dnode %08x is empty", dno); 53962306a36Sopenharmony_ci goto end; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci hpfs_brelse4(&qbh); 54262306a36Sopenharmony_ci hpfs_free_dnode(i->i_sb, dno); 54362306a36Sopenharmony_ci i->i_size -= 2048; 54462306a36Sopenharmony_ci i->i_blocks -= 4; 54562306a36Sopenharmony_ci if (root) { 54662306a36Sopenharmony_ci struct fnode *fnode; 54762306a36Sopenharmony_ci struct buffer_head *bh; 54862306a36Sopenharmony_ci struct dnode *d1; 54962306a36Sopenharmony_ci struct quad_buffer_head qbh1; 55062306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk) 55162306a36Sopenharmony_ci if (up != i->i_ino) { 55262306a36Sopenharmony_ci hpfs_error(i->i_sb, 55362306a36Sopenharmony_ci "bad pointer to fnode, dnode %08x, pointing to %08x, should be %08lx", 55462306a36Sopenharmony_ci dno, up, 55562306a36Sopenharmony_ci (unsigned long)i->i_ino); 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { 55962306a36Sopenharmony_ci d1->up = cpu_to_le32(up); 56062306a36Sopenharmony_ci d1->root_dnode = 1; 56162306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 56262306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) { 56562306a36Sopenharmony_ci fnode->u.external[0].disk_secno = cpu_to_le32(down); 56662306a36Sopenharmony_ci mark_buffer_dirty(bh); 56762306a36Sopenharmony_ci brelse(bh); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci hpfs_inode->i_dno = down; 57062306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12); 57162306a36Sopenharmony_ci return; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return; 57462306a36Sopenharmony_ci p = 1; 57562306a36Sopenharmony_ci de_end = dnode_end_de(dnode); 57662306a36Sopenharmony_ci for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de), p++) 57762306a36Sopenharmony_ci if (de->down) if (de_down_pointer(de) == dno) goto fnd; 57862306a36Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: pointer to dnode %08x not found in dnode %08x", dno, up); 57962306a36Sopenharmony_ci goto end; 58062306a36Sopenharmony_ci fnd: 58162306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p); 58262306a36Sopenharmony_ci if (!down) { 58362306a36Sopenharmony_ci de->down = 0; 58462306a36Sopenharmony_ci le16_add_cpu(&de->length, -4); 58562306a36Sopenharmony_ci le32_add_cpu(&dnode->first_free, -4); 58662306a36Sopenharmony_ci memmove(de_next_de(de), (char *)de_next_de(de) + 4, 58762306a36Sopenharmony_ci (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de)); 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci struct dnode *d1; 59062306a36Sopenharmony_ci struct quad_buffer_head qbh1; 59162306a36Sopenharmony_ci *(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4) = down; 59262306a36Sopenharmony_ci if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { 59362306a36Sopenharmony_ci d1->up = cpu_to_le32(up); 59462306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 59562306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci } else { 59962306a36Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, le32_to_cpu(dnode->first_free)); 60062306a36Sopenharmony_ci goto end; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (!de->last) { 60462306a36Sopenharmony_ci struct hpfs_dirent *de_next = de_next_de(de); 60562306a36Sopenharmony_ci struct hpfs_dirent *de_cp; 60662306a36Sopenharmony_ci struct dnode *d1; 60762306a36Sopenharmony_ci struct quad_buffer_head qbh1; 60862306a36Sopenharmony_ci if (!de_next->down) goto endm; 60962306a36Sopenharmony_ci ndown = de_down_pointer(de_next); 61062306a36Sopenharmony_ci if (!(de_cp = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) { 61162306a36Sopenharmony_ci pr_err("out of memory for dtree balancing\n"); 61262306a36Sopenharmony_ci goto endm; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci memcpy(de_cp, de, le16_to_cpu(de->length)); 61562306a36Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de); 61662306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 61762306a36Sopenharmony_ci hpfs_brelse4(&qbh); 61862306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4); 61962306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1); 62062306a36Sopenharmony_ci if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) { 62162306a36Sopenharmony_ci d1->up = cpu_to_le32(ndown); 62262306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 62362306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, de_cp->down ? de_down_pointer(de_cp) : 0); 62662306a36Sopenharmony_ci /*pr_info("UP-TO-DNODE: %08x (ndown = %08x, down = %08x, dno = %08x)\n", 62762306a36Sopenharmony_ci up, ndown, down, dno);*/ 62862306a36Sopenharmony_ci dno = up; 62962306a36Sopenharmony_ci kfree(de_cp); 63062306a36Sopenharmony_ci goto try_it_again; 63162306a36Sopenharmony_ci } else { 63262306a36Sopenharmony_ci struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode); 63362306a36Sopenharmony_ci struct hpfs_dirent *de_cp; 63462306a36Sopenharmony_ci struct dnode *d1; 63562306a36Sopenharmony_ci struct quad_buffer_head qbh1; 63662306a36Sopenharmony_ci dnode_secno dlp; 63762306a36Sopenharmony_ci if (!de_prev) { 63862306a36Sopenharmony_ci hpfs_error(i->i_sb, "delete_empty_dnode: empty dnode %08x", up); 63962306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 64062306a36Sopenharmony_ci hpfs_brelse4(&qbh); 64162306a36Sopenharmony_ci dno = up; 64262306a36Sopenharmony_ci goto try_it_again; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci if (!de_prev->down) goto endm; 64562306a36Sopenharmony_ci ndown = de_down_pointer(de_prev); 64662306a36Sopenharmony_ci if ((d1 = hpfs_map_dnode(i->i_sb, ndown, &qbh1))) { 64762306a36Sopenharmony_ci struct hpfs_dirent *del = dnode_last_de(d1); 64862306a36Sopenharmony_ci dlp = del->down ? de_down_pointer(del) : 0; 64962306a36Sopenharmony_ci if (!dlp && down) { 65062306a36Sopenharmony_ci if (le32_to_cpu(d1->first_free) > 2044) { 65162306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk >= 2) { 65262306a36Sopenharmony_ci pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n"); 65362306a36Sopenharmony_ci pr_err("terminating balancing operation\n"); 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 65662306a36Sopenharmony_ci goto endm; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci if (hpfs_sb(i->i_sb)->sb_chk >= 2) { 65962306a36Sopenharmony_ci pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n"); 66062306a36Sopenharmony_ci pr_err("goin'on\n"); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci le16_add_cpu(&del->length, 4); 66362306a36Sopenharmony_ci del->down = 1; 66462306a36Sopenharmony_ci le32_add_cpu(&d1->first_free, 4); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci if (dlp && !down) { 66762306a36Sopenharmony_ci le16_add_cpu(&del->length, -4); 66862306a36Sopenharmony_ci del->down = 0; 66962306a36Sopenharmony_ci le32_add_cpu(&d1->first_free, -4); 67062306a36Sopenharmony_ci } else if (down) 67162306a36Sopenharmony_ci *(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down); 67262306a36Sopenharmony_ci } else goto endm; 67362306a36Sopenharmony_ci if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) { 67462306a36Sopenharmony_ci pr_err("out of memory for dtree balancing\n"); 67562306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 67662306a36Sopenharmony_ci goto endm; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 67962306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 68062306a36Sopenharmony_ci memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length)); 68162306a36Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de_prev); 68262306a36Sopenharmony_ci if (!de_prev->down) { 68362306a36Sopenharmony_ci le16_add_cpu(&de_prev->length, 4); 68462306a36Sopenharmony_ci de_prev->down = 1; 68562306a36Sopenharmony_ci le32_add_cpu(&dnode->first_free, 4); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci *(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown); 68862306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 68962306a36Sopenharmony_ci hpfs_brelse4(&qbh); 69062306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4); 69162306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1)); 69262306a36Sopenharmony_ci if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) { 69362306a36Sopenharmony_ci d1->up = cpu_to_le32(ndown); 69462306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh1); 69562306a36Sopenharmony_ci hpfs_brelse4(&qbh1); 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, dlp); 69862306a36Sopenharmony_ci dno = up; 69962306a36Sopenharmony_ci kfree(de_cp); 70062306a36Sopenharmony_ci goto try_it_again; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci endm: 70362306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(&qbh); 70462306a36Sopenharmony_ci end: 70562306a36Sopenharmony_ci hpfs_brelse4(&qbh); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci/* Delete dirent from directory */ 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ciint hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, 71262306a36Sopenharmony_ci struct quad_buffer_head *qbh, int depth) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct dnode *dnode = qbh->data; 71562306a36Sopenharmony_ci dnode_secno down = 0; 71662306a36Sopenharmony_ci loff_t t; 71762306a36Sopenharmony_ci if (de->first || de->last) { 71862306a36Sopenharmony_ci hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno); 71962306a36Sopenharmony_ci hpfs_brelse4(qbh); 72062306a36Sopenharmony_ci return 1; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci if (de->down) down = de_down_pointer(de); 72362306a36Sopenharmony_ci if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) { 72462306a36Sopenharmony_ci if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) { 72562306a36Sopenharmony_ci hpfs_brelse4(qbh); 72662306a36Sopenharmony_ci return 2; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1); 73062306a36Sopenharmony_ci hpfs_delete_de(i->i_sb, dnode, de); 73162306a36Sopenharmony_ci hpfs_mark_4buffers_dirty(qbh); 73262306a36Sopenharmony_ci hpfs_brelse4(qbh); 73362306a36Sopenharmony_ci if (down) { 73462306a36Sopenharmony_ci dnode_secno a = move_to_top(i, down, dno); 73562306a36Sopenharmony_ci for_all_poss(i, hpfs_pos_subst, 5, t); 73662306a36Sopenharmony_ci if (a) delete_empty_dnode(i, a); 73762306a36Sopenharmony_ci return !a; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci delete_empty_dnode(i, dno); 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_civoid hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes, 74462306a36Sopenharmony_ci int *n_subdirs, int *n_items) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct dnode *dnode; 74762306a36Sopenharmony_ci struct quad_buffer_head qbh; 74862306a36Sopenharmony_ci struct hpfs_dirent *de; 74962306a36Sopenharmony_ci dnode_secno ptr, odno = 0; 75062306a36Sopenharmony_ci int c1, c2 = 0; 75162306a36Sopenharmony_ci int d1, d2 = 0; 75262306a36Sopenharmony_ci go_down: 75362306a36Sopenharmony_ci if (n_dnodes) (*n_dnodes)++; 75462306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 75562306a36Sopenharmony_ci if (hpfs_stop_cycles(s, dno, &c1, &c2, "hpfs_count_dnodes #1")) return; 75662306a36Sopenharmony_ci ptr = 0; 75762306a36Sopenharmony_ci go_up: 75862306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return; 75962306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && le32_to_cpu(dnode->up) != odno) 76062306a36Sopenharmony_ci hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, le32_to_cpu(dnode->up)); 76162306a36Sopenharmony_ci de = dnode_first_de(dnode); 76262306a36Sopenharmony_ci if (ptr) while(1) { 76362306a36Sopenharmony_ci if (de->down) if (de_down_pointer(de) == ptr) goto process_de; 76462306a36Sopenharmony_ci if (de->last) { 76562306a36Sopenharmony_ci hpfs_brelse4(&qbh); 76662306a36Sopenharmony_ci hpfs_error(s, "hpfs_count_dnodes: pointer to dnode %08x not found in dnode %08x, got here from %08x", 76762306a36Sopenharmony_ci ptr, dno, odno); 76862306a36Sopenharmony_ci return; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci de = de_next_de(de); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci next_de: 77362306a36Sopenharmony_ci if (de->down) { 77462306a36Sopenharmony_ci odno = dno; 77562306a36Sopenharmony_ci dno = de_down_pointer(de); 77662306a36Sopenharmony_ci hpfs_brelse4(&qbh); 77762306a36Sopenharmony_ci goto go_down; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci process_de: 78062306a36Sopenharmony_ci if (!de->first && !de->last && de->directory && n_subdirs) (*n_subdirs)++; 78162306a36Sopenharmony_ci if (!de->first && !de->last && n_items) (*n_items)++; 78262306a36Sopenharmony_ci if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de; 78362306a36Sopenharmony_ci ptr = dno; 78462306a36Sopenharmony_ci dno = le32_to_cpu(dnode->up); 78562306a36Sopenharmony_ci if (dnode->root_dnode) { 78662306a36Sopenharmony_ci hpfs_brelse4(&qbh); 78762306a36Sopenharmony_ci return; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci hpfs_brelse4(&qbh); 79062306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 79162306a36Sopenharmony_ci if (hpfs_stop_cycles(s, ptr, &d1, &d2, "hpfs_count_dnodes #2")) return; 79262306a36Sopenharmony_ci odno = -1; 79362306a36Sopenharmony_ci goto go_up; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic struct hpfs_dirent *map_nth_dirent(struct super_block *s, dnode_secno dno, int n, 79762306a36Sopenharmony_ci struct quad_buffer_head *qbh, struct dnode **dn) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci int i; 80062306a36Sopenharmony_ci struct hpfs_dirent *de, *de_end; 80162306a36Sopenharmony_ci struct dnode *dnode; 80262306a36Sopenharmony_ci dnode = hpfs_map_dnode(s, dno, qbh); 80362306a36Sopenharmony_ci if (!dnode) return NULL; 80462306a36Sopenharmony_ci if (dn) *dn=dnode; 80562306a36Sopenharmony_ci de = dnode_first_de(dnode); 80662306a36Sopenharmony_ci de_end = dnode_end_de(dnode); 80762306a36Sopenharmony_ci for (i = 1; de < de_end; i++, de = de_next_de(de)) { 80862306a36Sopenharmony_ci if (i == n) { 80962306a36Sopenharmony_ci return de; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci if (de->last) break; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci hpfs_brelse4(qbh); 81462306a36Sopenharmony_ci hpfs_error(s, "map_nth_dirent: n too high; dnode = %08x, requested %08x", dno, n); 81562306a36Sopenharmony_ci return NULL; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cidnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci struct quad_buffer_head qbh; 82162306a36Sopenharmony_ci dnode_secno d = dno; 82262306a36Sopenharmony_ci dnode_secno up = 0; 82362306a36Sopenharmony_ci struct hpfs_dirent *de; 82462306a36Sopenharmony_ci int c1, c2 = 0; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci again: 82762306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 82862306a36Sopenharmony_ci if (hpfs_stop_cycles(s, d, &c1, &c2, "hpfs_de_as_down_as_possible")) 82962306a36Sopenharmony_ci return d; 83062306a36Sopenharmony_ci if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno; 83162306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 83262306a36Sopenharmony_ci if (up && le32_to_cpu(((struct dnode *)qbh.data)->up) != up) 83362306a36Sopenharmony_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)); 83462306a36Sopenharmony_ci if (!de->down) { 83562306a36Sopenharmony_ci hpfs_brelse4(&qbh); 83662306a36Sopenharmony_ci return d; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci up = d; 83962306a36Sopenharmony_ci d = de_down_pointer(de); 84062306a36Sopenharmony_ci hpfs_brelse4(&qbh); 84162306a36Sopenharmony_ci goto again; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistruct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp, 84562306a36Sopenharmony_ci struct quad_buffer_head *qbh) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci loff_t pos; 84862306a36Sopenharmony_ci unsigned c; 84962306a36Sopenharmony_ci dnode_secno dno; 85062306a36Sopenharmony_ci struct hpfs_dirent *de, *d; 85162306a36Sopenharmony_ci struct hpfs_dirent *up_de; 85262306a36Sopenharmony_ci struct hpfs_dirent *end_up_de; 85362306a36Sopenharmony_ci struct dnode *dnode; 85462306a36Sopenharmony_ci struct dnode *up_dnode; 85562306a36Sopenharmony_ci struct quad_buffer_head qbh0; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci pos = *posp; 85862306a36Sopenharmony_ci dno = pos >> 6 << 2; 85962306a36Sopenharmony_ci pos &= 077; 86062306a36Sopenharmony_ci if (!(de = map_nth_dirent(inode->i_sb, dno, pos, qbh, &dnode))) 86162306a36Sopenharmony_ci goto bail; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Going to the next dirent */ 86462306a36Sopenharmony_ci if ((d = de_next_de(de)) < dnode_end_de(dnode)) { 86562306a36Sopenharmony_ci if (!(++*posp & 077)) { 86662306a36Sopenharmony_ci hpfs_error(inode->i_sb, 86762306a36Sopenharmony_ci "map_pos_dirent: pos crossed dnode boundary; pos = %08llx", 86862306a36Sopenharmony_ci (unsigned long long)*posp); 86962306a36Sopenharmony_ci goto bail; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci /* We're going down the tree */ 87262306a36Sopenharmony_ci if (d->down) { 87362306a36Sopenharmony_ci *posp = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, de_down_pointer(d)) << 4) + 1; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return de; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* Going up */ 88062306a36Sopenharmony_ci if (dnode->root_dnode) goto bail; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (!(up_dnode = hpfs_map_dnode(inode->i_sb, le32_to_cpu(dnode->up), &qbh0))) 88362306a36Sopenharmony_ci goto bail; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci end_up_de = dnode_end_de(up_dnode); 88662306a36Sopenharmony_ci c = 0; 88762306a36Sopenharmony_ci for (up_de = dnode_first_de(up_dnode); up_de < end_up_de; 88862306a36Sopenharmony_ci up_de = de_next_de(up_de)) { 88962306a36Sopenharmony_ci if (!(++c & 077)) hpfs_error(inode->i_sb, 89062306a36Sopenharmony_ci "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", le32_to_cpu(dnode->up)); 89162306a36Sopenharmony_ci if (up_de->down && de_down_pointer(up_de) == dno) { 89262306a36Sopenharmony_ci *posp = ((loff_t) le32_to_cpu(dnode->up) << 4) + c; 89362306a36Sopenharmony_ci hpfs_brelse4(&qbh0); 89462306a36Sopenharmony_ci return de; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x", 89962306a36Sopenharmony_ci dno, le32_to_cpu(dnode->up)); 90062306a36Sopenharmony_ci hpfs_brelse4(&qbh0); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci bail: 90362306a36Sopenharmony_ci *posp = 12; 90462306a36Sopenharmony_ci return de; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci/* Find a dirent in tree */ 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistruct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, 91062306a36Sopenharmony_ci const unsigned char *name, unsigned len, 91162306a36Sopenharmony_ci dnode_secno *dd, struct quad_buffer_head *qbh) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct dnode *dnode; 91462306a36Sopenharmony_ci struct hpfs_dirent *de; 91562306a36Sopenharmony_ci struct hpfs_dirent *de_end; 91662306a36Sopenharmony_ci int c1, c2 = 0; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n"); 91962306a36Sopenharmony_ci again: 92062306a36Sopenharmony_ci if (hpfs_sb(inode->i_sb)->sb_chk) 92162306a36Sopenharmony_ci if (hpfs_stop_cycles(inode->i_sb, dno, &c1, &c2, "map_dirent")) return NULL; 92262306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(inode->i_sb, dno, qbh))) return NULL; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci de_end = dnode_end_de(dnode); 92562306a36Sopenharmony_ci for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de)) { 92662306a36Sopenharmony_ci int t = hpfs_compare_names(inode->i_sb, name, len, de->name, de->namelen, de->last); 92762306a36Sopenharmony_ci if (!t) { 92862306a36Sopenharmony_ci if (dd) *dd = dno; 92962306a36Sopenharmony_ci return de; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci if (t < 0) { 93262306a36Sopenharmony_ci if (de->down) { 93362306a36Sopenharmony_ci dno = de_down_pointer(de); 93462306a36Sopenharmony_ci hpfs_brelse4(qbh); 93562306a36Sopenharmony_ci goto again; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci break; 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci hpfs_brelse4(qbh); 94162306a36Sopenharmony_ci return NULL; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci/* 94562306a36Sopenharmony_ci * Remove empty directory. In normal cases it is only one dnode with two 94662306a36Sopenharmony_ci * entries, but we must handle also such obscure cases when it's a tree 94762306a36Sopenharmony_ci * of empty dnodes. 94862306a36Sopenharmony_ci */ 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_civoid hpfs_remove_dtree(struct super_block *s, dnode_secno dno) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct quad_buffer_head qbh; 95362306a36Sopenharmony_ci struct dnode *dnode; 95462306a36Sopenharmony_ci struct hpfs_dirent *de; 95562306a36Sopenharmony_ci dnode_secno d1, d2, rdno = dno; 95662306a36Sopenharmony_ci while (1) { 95762306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return; 95862306a36Sopenharmony_ci de = dnode_first_de(dnode); 95962306a36Sopenharmony_ci if (de->last) { 96062306a36Sopenharmony_ci if (de->down) d1 = de_down_pointer(de); 96162306a36Sopenharmony_ci else goto error; 96262306a36Sopenharmony_ci hpfs_brelse4(&qbh); 96362306a36Sopenharmony_ci hpfs_free_dnode(s, dno); 96462306a36Sopenharmony_ci dno = d1; 96562306a36Sopenharmony_ci } else break; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci if (!de->first) goto error; 96862306a36Sopenharmony_ci d1 = de->down ? de_down_pointer(de) : 0; 96962306a36Sopenharmony_ci de = de_next_de(de); 97062306a36Sopenharmony_ci if (!de->last) goto error; 97162306a36Sopenharmony_ci d2 = de->down ? de_down_pointer(de) : 0; 97262306a36Sopenharmony_ci hpfs_brelse4(&qbh); 97362306a36Sopenharmony_ci hpfs_free_dnode(s, dno); 97462306a36Sopenharmony_ci do { 97562306a36Sopenharmony_ci while (d1) { 97662306a36Sopenharmony_ci if (!(dnode = hpfs_map_dnode(s, dno = d1, &qbh))) return; 97762306a36Sopenharmony_ci de = dnode_first_de(dnode); 97862306a36Sopenharmony_ci if (!de->last) goto error; 97962306a36Sopenharmony_ci d1 = de->down ? de_down_pointer(de) : 0; 98062306a36Sopenharmony_ci hpfs_brelse4(&qbh); 98162306a36Sopenharmony_ci hpfs_free_dnode(s, dno); 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci d1 = d2; 98462306a36Sopenharmony_ci d2 = 0; 98562306a36Sopenharmony_ci } while (d1); 98662306a36Sopenharmony_ci return; 98762306a36Sopenharmony_ci error: 98862306a36Sopenharmony_ci hpfs_brelse4(&qbh); 98962306a36Sopenharmony_ci hpfs_free_dnode(s, dno); 99062306a36Sopenharmony_ci hpfs_error(s, "directory %08x is corrupted or not empty", rdno); 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci/* 99462306a36Sopenharmony_ci * Find dirent for specified fnode. Use truncated 15-char name in fnode as 99562306a36Sopenharmony_ci * a help for searching. 99662306a36Sopenharmony_ci */ 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistruct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, 99962306a36Sopenharmony_ci struct fnode *f, struct quad_buffer_head *qbh) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci unsigned char *name1; 100262306a36Sopenharmony_ci unsigned char *name2; 100362306a36Sopenharmony_ci int name1len, name2len; 100462306a36Sopenharmony_ci struct dnode *d; 100562306a36Sopenharmony_ci dnode_secno dno, downd; 100662306a36Sopenharmony_ci struct fnode *upf; 100762306a36Sopenharmony_ci struct buffer_head *bh; 100862306a36Sopenharmony_ci struct hpfs_dirent *de, *de_end; 100962306a36Sopenharmony_ci int c; 101062306a36Sopenharmony_ci int c1, c2 = 0; 101162306a36Sopenharmony_ci int d1, d2 = 0; 101262306a36Sopenharmony_ci name1 = f->name; 101362306a36Sopenharmony_ci if (!(name2 = kmalloc(256, GFP_NOFS))) { 101462306a36Sopenharmony_ci pr_err("out of memory, can't map dirent\n"); 101562306a36Sopenharmony_ci return NULL; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci if (f->len <= 15) 101862306a36Sopenharmony_ci memcpy(name2, name1, name1len = name2len = f->len); 101962306a36Sopenharmony_ci else { 102062306a36Sopenharmony_ci memcpy(name2, name1, 15); 102162306a36Sopenharmony_ci memset(name2 + 15, 0xff, 256 - 15); 102262306a36Sopenharmony_ci /*name2[15] = 0xff;*/ 102362306a36Sopenharmony_ci name1len = 15; name2len = 256; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci if (!(upf = hpfs_map_fnode(s, le32_to_cpu(f->up), &bh))) { 102662306a36Sopenharmony_ci kfree(name2); 102762306a36Sopenharmony_ci return NULL; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci if (!fnode_is_dir(upf)) { 103062306a36Sopenharmony_ci brelse(bh); 103162306a36Sopenharmony_ci hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up)); 103262306a36Sopenharmony_ci kfree(name2); 103362306a36Sopenharmony_ci return NULL; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci dno = le32_to_cpu(upf->u.external[0].disk_secno); 103662306a36Sopenharmony_ci brelse(bh); 103762306a36Sopenharmony_ci go_down: 103862306a36Sopenharmony_ci downd = 0; 103962306a36Sopenharmony_ci go_up: 104062306a36Sopenharmony_ci if (!(d = hpfs_map_dnode(s, dno, qbh))) { 104162306a36Sopenharmony_ci kfree(name2); 104262306a36Sopenharmony_ci return NULL; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci de_end = dnode_end_de(d); 104562306a36Sopenharmony_ci de = dnode_first_de(d); 104662306a36Sopenharmony_ci if (downd) { 104762306a36Sopenharmony_ci while (de < de_end) { 104862306a36Sopenharmony_ci if (de->down) if (de_down_pointer(de) == downd) goto f; 104962306a36Sopenharmony_ci de = de_next_de(de); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci hpfs_error(s, "pointer to dnode %08x not found in dnode %08x", downd, dno); 105262306a36Sopenharmony_ci hpfs_brelse4(qbh); 105362306a36Sopenharmony_ci kfree(name2); 105462306a36Sopenharmony_ci return NULL; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci next_de: 105762306a36Sopenharmony_ci if (le32_to_cpu(de->fnode) == fno) { 105862306a36Sopenharmony_ci kfree(name2); 105962306a36Sopenharmony_ci return de; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci c = hpfs_compare_names(s, name1, name1len, de->name, de->namelen, de->last); 106262306a36Sopenharmony_ci if (c < 0 && de->down) { 106362306a36Sopenharmony_ci dno = de_down_pointer(de); 106462306a36Sopenharmony_ci hpfs_brelse4(qbh); 106562306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 106662306a36Sopenharmony_ci if (hpfs_stop_cycles(s, dno, &c1, &c2, "map_fnode_dirent #1")) { 106762306a36Sopenharmony_ci kfree(name2); 106862306a36Sopenharmony_ci return NULL; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci goto go_down; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci f: 107362306a36Sopenharmony_ci if (le32_to_cpu(de->fnode) == fno) { 107462306a36Sopenharmony_ci kfree(name2); 107562306a36Sopenharmony_ci return de; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci c = hpfs_compare_names(s, name2, name2len, de->name, de->namelen, de->last); 107862306a36Sopenharmony_ci if (c < 0 && !de->last) goto not_found; 107962306a36Sopenharmony_ci if ((de = de_next_de(de)) < de_end) goto next_de; 108062306a36Sopenharmony_ci if (d->root_dnode) goto not_found; 108162306a36Sopenharmony_ci downd = dno; 108262306a36Sopenharmony_ci dno = le32_to_cpu(d->up); 108362306a36Sopenharmony_ci hpfs_brelse4(qbh); 108462306a36Sopenharmony_ci if (hpfs_sb(s)->sb_chk) 108562306a36Sopenharmony_ci if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) { 108662306a36Sopenharmony_ci kfree(name2); 108762306a36Sopenharmony_ci return NULL; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci goto go_up; 109062306a36Sopenharmony_ci not_found: 109162306a36Sopenharmony_ci hpfs_brelse4(qbh); 109262306a36Sopenharmony_ci hpfs_error(s, "dirent for fnode %08x not found", fno); 109362306a36Sopenharmony_ci kfree(name2); 109462306a36Sopenharmony_ci return NULL; 109562306a36Sopenharmony_ci} 1096