1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * link.c --- create links in a ext2fs directory
3*6a54128fSAndroid Build Coastguard Worker *
4*6a54128fSAndroid Build Coastguard Worker * Copyright (C) 1993, 1994 Theodore Ts'o.
5*6a54128fSAndroid Build Coastguard Worker *
6*6a54128fSAndroid Build Coastguard Worker * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker * This file may be redistributed under the terms of the GNU Library
8*6a54128fSAndroid Build Coastguard Worker * General Public License, version 2.
9*6a54128fSAndroid Build Coastguard Worker * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker */
11*6a54128fSAndroid Build Coastguard Worker
12*6a54128fSAndroid Build Coastguard Worker #include "config.h"
13*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
14*6a54128fSAndroid Build Coastguard Worker #include <string.h>
15*6a54128fSAndroid Build Coastguard Worker #if HAVE_UNISTD_H
16*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
17*6a54128fSAndroid Build Coastguard Worker #endif
18*6a54128fSAndroid Build Coastguard Worker
19*6a54128fSAndroid Build Coastguard Worker #include "ext2_fs.h"
20*6a54128fSAndroid Build Coastguard Worker #include "ext2fs.h"
21*6a54128fSAndroid Build Coastguard Worker #include "ext2fsP.h"
22*6a54128fSAndroid Build Coastguard Worker
23*6a54128fSAndroid Build Coastguard Worker #define EXT2_DX_ROOT_OFF 24
24*6a54128fSAndroid Build Coastguard Worker
25*6a54128fSAndroid Build Coastguard Worker struct dx_frame {
26*6a54128fSAndroid Build Coastguard Worker void *buf;
27*6a54128fSAndroid Build Coastguard Worker blk64_t pblock;
28*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_countlimit *head;
29*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_entry *entries;
30*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_entry *at;
31*6a54128fSAndroid Build Coastguard Worker };
32*6a54128fSAndroid Build Coastguard Worker
33*6a54128fSAndroid Build Coastguard Worker struct dx_lookup_info {
34*6a54128fSAndroid Build Coastguard Worker const char *name;
35*6a54128fSAndroid Build Coastguard Worker int namelen;
36*6a54128fSAndroid Build Coastguard Worker int hash_alg;
37*6a54128fSAndroid Build Coastguard Worker __u32 hash;
38*6a54128fSAndroid Build Coastguard Worker unsigned levels;
39*6a54128fSAndroid Build Coastguard Worker struct dx_frame frames[EXT4_HTREE_LEVEL];
40*6a54128fSAndroid Build Coastguard Worker };
41*6a54128fSAndroid Build Coastguard Worker
alloc_dx_frame(ext2_filsys fs,struct dx_frame * frame)42*6a54128fSAndroid Build Coastguard Worker static errcode_t alloc_dx_frame(ext2_filsys fs, struct dx_frame *frame)
43*6a54128fSAndroid Build Coastguard Worker {
44*6a54128fSAndroid Build Coastguard Worker return ext2fs_get_mem(fs->blocksize, &frame->buf);
45*6a54128fSAndroid Build Coastguard Worker }
46*6a54128fSAndroid Build Coastguard Worker
dx_release(struct dx_lookup_info * info)47*6a54128fSAndroid Build Coastguard Worker static void dx_release(struct dx_lookup_info *info)
48*6a54128fSAndroid Build Coastguard Worker {
49*6a54128fSAndroid Build Coastguard Worker unsigned level;
50*6a54128fSAndroid Build Coastguard Worker
51*6a54128fSAndroid Build Coastguard Worker for (level = 0; level < info->levels; level++) {
52*6a54128fSAndroid Build Coastguard Worker if (info->frames[level].buf == NULL)
53*6a54128fSAndroid Build Coastguard Worker break;
54*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&(info->frames[level].buf));
55*6a54128fSAndroid Build Coastguard Worker }
56*6a54128fSAndroid Build Coastguard Worker info->levels = 0;
57*6a54128fSAndroid Build Coastguard Worker }
58*6a54128fSAndroid Build Coastguard Worker
dx_search_entry(struct dx_frame * frame,int count,__u32 hash)59*6a54128fSAndroid Build Coastguard Worker static void dx_search_entry(struct dx_frame *frame, int count, __u32 hash)
60*6a54128fSAndroid Build Coastguard Worker {
61*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_entry *p, *q, *m;
62*6a54128fSAndroid Build Coastguard Worker
63*6a54128fSAndroid Build Coastguard Worker p = frame->entries + 1;
64*6a54128fSAndroid Build Coastguard Worker q = frame->entries + count - 1;
65*6a54128fSAndroid Build Coastguard Worker while (p <= q) {
66*6a54128fSAndroid Build Coastguard Worker m = p + (q - p) / 2;
67*6a54128fSAndroid Build Coastguard Worker if (ext2fs_le32_to_cpu(m->hash) > hash)
68*6a54128fSAndroid Build Coastguard Worker q = m - 1;
69*6a54128fSAndroid Build Coastguard Worker else
70*6a54128fSAndroid Build Coastguard Worker p = m + 1;
71*6a54128fSAndroid Build Coastguard Worker }
72*6a54128fSAndroid Build Coastguard Worker frame->at = p - 1;
73*6a54128fSAndroid Build Coastguard Worker }
74*6a54128fSAndroid Build Coastguard Worker
load_logical_dir_block(ext2_filsys fs,ext2_ino_t dir,struct ext2_inode * diri,blk64_t block,blk64_t * pblk,void * buf)75*6a54128fSAndroid Build Coastguard Worker static errcode_t load_logical_dir_block(ext2_filsys fs, ext2_ino_t dir,
76*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *diri, blk64_t block,
77*6a54128fSAndroid Build Coastguard Worker blk64_t *pblk, void *buf)
78*6a54128fSAndroid Build Coastguard Worker {
79*6a54128fSAndroid Build Coastguard Worker errcode_t errcode;
80*6a54128fSAndroid Build Coastguard Worker int ret_flags;
81*6a54128fSAndroid Build Coastguard Worker
82*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_bmap2(fs, dir, diri, NULL, 0, block, &ret_flags,
83*6a54128fSAndroid Build Coastguard Worker pblk);
84*6a54128fSAndroid Build Coastguard Worker if (errcode)
85*6a54128fSAndroid Build Coastguard Worker return errcode;
86*6a54128fSAndroid Build Coastguard Worker if (ret_flags & BMAP_RET_UNINIT)
87*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_DIR_CORRUPTED;
88*6a54128fSAndroid Build Coastguard Worker return ext2fs_read_dir_block4(fs, *pblk, buf, 0, dir);
89*6a54128fSAndroid Build Coastguard Worker }
90*6a54128fSAndroid Build Coastguard Worker
dx_lookup(ext2_filsys fs,ext2_ino_t dir,struct ext2_inode * diri,struct dx_lookup_info * info)91*6a54128fSAndroid Build Coastguard Worker static errcode_t dx_lookup(ext2_filsys fs, ext2_ino_t dir,
92*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *diri, struct dx_lookup_info *info)
93*6a54128fSAndroid Build Coastguard Worker {
94*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_root_info *root;
95*6a54128fSAndroid Build Coastguard Worker errcode_t errcode;
96*6a54128fSAndroid Build Coastguard Worker int level = 0;
97*6a54128fSAndroid Build Coastguard Worker int count, limit;
98*6a54128fSAndroid Build Coastguard Worker int hash_alg;
99*6a54128fSAndroid Build Coastguard Worker int hash_flags = diri->i_flags & EXT4_CASEFOLD_FL;
100*6a54128fSAndroid Build Coastguard Worker __u32 minor_hash;
101*6a54128fSAndroid Build Coastguard Worker struct dx_frame *frame;
102*6a54128fSAndroid Build Coastguard Worker
103*6a54128fSAndroid Build Coastguard Worker errcode = alloc_dx_frame(fs, &(info->frames[0]));
104*6a54128fSAndroid Build Coastguard Worker if (errcode)
105*6a54128fSAndroid Build Coastguard Worker return errcode;
106*6a54128fSAndroid Build Coastguard Worker info->levels = 1;
107*6a54128fSAndroid Build Coastguard Worker
108*6a54128fSAndroid Build Coastguard Worker errcode = load_logical_dir_block(fs, dir, diri, 0,
109*6a54128fSAndroid Build Coastguard Worker &(info->frames[0].pblock),
110*6a54128fSAndroid Build Coastguard Worker info->frames[0].buf);
111*6a54128fSAndroid Build Coastguard Worker if (errcode)
112*6a54128fSAndroid Build Coastguard Worker goto out_err;
113*6a54128fSAndroid Build Coastguard Worker root = (struct ext2_dx_root_info *) ((char *)info->frames[0].buf +
114*6a54128fSAndroid Build Coastguard Worker EXT2_DX_ROOT_OFF);
115*6a54128fSAndroid Build Coastguard Worker hash_alg = root->hash_version;
116*6a54128fSAndroid Build Coastguard Worker if (hash_alg != EXT2_HASH_TEA && hash_alg != EXT2_HASH_HALF_MD4 &&
117*6a54128fSAndroid Build Coastguard Worker hash_alg != EXT2_HASH_LEGACY) {
118*6a54128fSAndroid Build Coastguard Worker errcode = EXT2_ET_DIRHASH_UNSUPP;
119*6a54128fSAndroid Build Coastguard Worker goto out_err;
120*6a54128fSAndroid Build Coastguard Worker }
121*6a54128fSAndroid Build Coastguard Worker if (hash_alg <= EXT2_HASH_TEA &&
122*6a54128fSAndroid Build Coastguard Worker fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)
123*6a54128fSAndroid Build Coastguard Worker hash_alg += 3;
124*6a54128fSAndroid Build Coastguard Worker if (root->indirect_levels >= ext2_dir_htree_level(fs)) {
125*6a54128fSAndroid Build Coastguard Worker errcode = EXT2_ET_DIR_CORRUPTED;
126*6a54128fSAndroid Build Coastguard Worker goto out_err;
127*6a54128fSAndroid Build Coastguard Worker }
128*6a54128fSAndroid Build Coastguard Worker info->hash_alg = hash_alg;
129*6a54128fSAndroid Build Coastguard Worker
130*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_dirhash2(hash_alg, info->name, info->namelen,
131*6a54128fSAndroid Build Coastguard Worker fs->encoding, hash_flags,
132*6a54128fSAndroid Build Coastguard Worker fs->super->s_hash_seed, &info->hash,
133*6a54128fSAndroid Build Coastguard Worker &minor_hash);
134*6a54128fSAndroid Build Coastguard Worker if (errcode)
135*6a54128fSAndroid Build Coastguard Worker goto out_err;
136*6a54128fSAndroid Build Coastguard Worker
137*6a54128fSAndroid Build Coastguard Worker for (level = 0; level <= root->indirect_levels; level++) {
138*6a54128fSAndroid Build Coastguard Worker frame = &(info->frames[level]);
139*6a54128fSAndroid Build Coastguard Worker if (level > 0) {
140*6a54128fSAndroid Build Coastguard Worker errcode = alloc_dx_frame(fs, frame);
141*6a54128fSAndroid Build Coastguard Worker if (errcode)
142*6a54128fSAndroid Build Coastguard Worker goto out_err;
143*6a54128fSAndroid Build Coastguard Worker info->levels++;
144*6a54128fSAndroid Build Coastguard Worker
145*6a54128fSAndroid Build Coastguard Worker errcode = load_logical_dir_block(fs, dir, diri,
146*6a54128fSAndroid Build Coastguard Worker ext2fs_le32_to_cpu(info->frames[level-1].at->block) & 0x0fffffff,
147*6a54128fSAndroid Build Coastguard Worker &(frame->pblock), frame->buf);
148*6a54128fSAndroid Build Coastguard Worker if (errcode)
149*6a54128fSAndroid Build Coastguard Worker goto out_err;
150*6a54128fSAndroid Build Coastguard Worker }
151*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_get_dx_countlimit(fs, frame->buf,
152*6a54128fSAndroid Build Coastguard Worker &(frame->head), NULL);
153*6a54128fSAndroid Build Coastguard Worker if (errcode)
154*6a54128fSAndroid Build Coastguard Worker goto out_err;
155*6a54128fSAndroid Build Coastguard Worker count = ext2fs_le16_to_cpu(frame->head->count);
156*6a54128fSAndroid Build Coastguard Worker limit = ext2fs_le16_to_cpu(frame->head->limit);
157*6a54128fSAndroid Build Coastguard Worker frame->entries = (struct ext2_dx_entry *)(frame->head);
158*6a54128fSAndroid Build Coastguard Worker if (!count || count > limit) {
159*6a54128fSAndroid Build Coastguard Worker errcode = EXT2_ET_DIR_CORRUPTED;
160*6a54128fSAndroid Build Coastguard Worker goto out_err;
161*6a54128fSAndroid Build Coastguard Worker }
162*6a54128fSAndroid Build Coastguard Worker
163*6a54128fSAndroid Build Coastguard Worker dx_search_entry(frame, count, info->hash);
164*6a54128fSAndroid Build Coastguard Worker }
165*6a54128fSAndroid Build Coastguard Worker return 0;
166*6a54128fSAndroid Build Coastguard Worker out_err:
167*6a54128fSAndroid Build Coastguard Worker dx_release(info);
168*6a54128fSAndroid Build Coastguard Worker return errcode;
169*6a54128fSAndroid Build Coastguard Worker }
170*6a54128fSAndroid Build Coastguard Worker
171*6a54128fSAndroid Build Coastguard Worker struct link_struct {
172*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs;
173*6a54128fSAndroid Build Coastguard Worker const char *name;
174*6a54128fSAndroid Build Coastguard Worker int namelen;
175*6a54128fSAndroid Build Coastguard Worker ext2_ino_t inode;
176*6a54128fSAndroid Build Coastguard Worker int flags;
177*6a54128fSAndroid Build Coastguard Worker int done;
178*6a54128fSAndroid Build Coastguard Worker unsigned int blocksize;
179*6a54128fSAndroid Build Coastguard Worker errcode_t err;
180*6a54128fSAndroid Build Coastguard Worker struct ext2_super_block *sb;
181*6a54128fSAndroid Build Coastguard Worker };
182*6a54128fSAndroid Build Coastguard Worker
link_proc(ext2_ino_t dir EXT2FS_ATTR ((unused)),int entru EXT2FS_ATTR ((unused)),struct ext2_dir_entry * dirent,int offset,int blocksize,char * buf,void * priv_data)183*6a54128fSAndroid Build Coastguard Worker static int link_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
184*6a54128fSAndroid Build Coastguard Worker int entru EXT2FS_ATTR((unused)),
185*6a54128fSAndroid Build Coastguard Worker struct ext2_dir_entry *dirent,
186*6a54128fSAndroid Build Coastguard Worker int offset,
187*6a54128fSAndroid Build Coastguard Worker int blocksize,
188*6a54128fSAndroid Build Coastguard Worker char *buf,
189*6a54128fSAndroid Build Coastguard Worker void *priv_data)
190*6a54128fSAndroid Build Coastguard Worker {
191*6a54128fSAndroid Build Coastguard Worker struct link_struct *ls = (struct link_struct *) priv_data;
192*6a54128fSAndroid Build Coastguard Worker struct ext2_dir_entry *next;
193*6a54128fSAndroid Build Coastguard Worker unsigned int rec_len, min_rec_len, curr_rec_len;
194*6a54128fSAndroid Build Coastguard Worker int ret = 0;
195*6a54128fSAndroid Build Coastguard Worker int csum_size = 0;
196*6a54128fSAndroid Build Coastguard Worker
197*6a54128fSAndroid Build Coastguard Worker if (ls->done)
198*6a54128fSAndroid Build Coastguard Worker return DIRENT_ABORT;
199*6a54128fSAndroid Build Coastguard Worker
200*6a54128fSAndroid Build Coastguard Worker rec_len = EXT2_DIR_REC_LEN(ls->namelen);
201*6a54128fSAndroid Build Coastguard Worker
202*6a54128fSAndroid Build Coastguard Worker ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
203*6a54128fSAndroid Build Coastguard Worker if (ls->err)
204*6a54128fSAndroid Build Coastguard Worker return DIRENT_ABORT;
205*6a54128fSAndroid Build Coastguard Worker
206*6a54128fSAndroid Build Coastguard Worker if (ext2fs_has_feature_metadata_csum(ls->fs->super))
207*6a54128fSAndroid Build Coastguard Worker csum_size = sizeof(struct ext2_dir_entry_tail);
208*6a54128fSAndroid Build Coastguard Worker /*
209*6a54128fSAndroid Build Coastguard Worker * See if the following directory entry (if any) is unused;
210*6a54128fSAndroid Build Coastguard Worker * if so, absorb it into this one.
211*6a54128fSAndroid Build Coastguard Worker */
212*6a54128fSAndroid Build Coastguard Worker next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
213*6a54128fSAndroid Build Coastguard Worker if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) &&
214*6a54128fSAndroid Build Coastguard Worker (next->inode == 0) &&
215*6a54128fSAndroid Build Coastguard Worker (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) {
216*6a54128fSAndroid Build Coastguard Worker curr_rec_len += next->rec_len;
217*6a54128fSAndroid Build Coastguard Worker ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
218*6a54128fSAndroid Build Coastguard Worker if (ls->err)
219*6a54128fSAndroid Build Coastguard Worker return DIRENT_ABORT;
220*6a54128fSAndroid Build Coastguard Worker ret = DIRENT_CHANGED;
221*6a54128fSAndroid Build Coastguard Worker }
222*6a54128fSAndroid Build Coastguard Worker
223*6a54128fSAndroid Build Coastguard Worker /*
224*6a54128fSAndroid Build Coastguard Worker * If the directory entry is used, see if we can split the
225*6a54128fSAndroid Build Coastguard Worker * directory entry to make room for the new name. If so,
226*6a54128fSAndroid Build Coastguard Worker * truncate it and return.
227*6a54128fSAndroid Build Coastguard Worker */
228*6a54128fSAndroid Build Coastguard Worker if (dirent->inode) {
229*6a54128fSAndroid Build Coastguard Worker min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent));
230*6a54128fSAndroid Build Coastguard Worker if (curr_rec_len < (min_rec_len + rec_len))
231*6a54128fSAndroid Build Coastguard Worker return ret;
232*6a54128fSAndroid Build Coastguard Worker rec_len = curr_rec_len - min_rec_len;
233*6a54128fSAndroid Build Coastguard Worker ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent);
234*6a54128fSAndroid Build Coastguard Worker if (ls->err)
235*6a54128fSAndroid Build Coastguard Worker return DIRENT_ABORT;
236*6a54128fSAndroid Build Coastguard Worker next = (struct ext2_dir_entry *) (buf + offset +
237*6a54128fSAndroid Build Coastguard Worker dirent->rec_len);
238*6a54128fSAndroid Build Coastguard Worker next->inode = 0;
239*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_name_len(next, 0);
240*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_file_type(next, 0);
241*6a54128fSAndroid Build Coastguard Worker ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next);
242*6a54128fSAndroid Build Coastguard Worker if (ls->err)
243*6a54128fSAndroid Build Coastguard Worker return DIRENT_ABORT;
244*6a54128fSAndroid Build Coastguard Worker return DIRENT_CHANGED;
245*6a54128fSAndroid Build Coastguard Worker }
246*6a54128fSAndroid Build Coastguard Worker
247*6a54128fSAndroid Build Coastguard Worker /*
248*6a54128fSAndroid Build Coastguard Worker * If we get this far, then the directory entry is not used.
249*6a54128fSAndroid Build Coastguard Worker * See if we can fit the request entry in. If so, do it.
250*6a54128fSAndroid Build Coastguard Worker */
251*6a54128fSAndroid Build Coastguard Worker if (curr_rec_len < rec_len)
252*6a54128fSAndroid Build Coastguard Worker return ret;
253*6a54128fSAndroid Build Coastguard Worker dirent->inode = ls->inode;
254*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_name_len(dirent, ls->namelen);
255*6a54128fSAndroid Build Coastguard Worker strncpy(dirent->name, ls->name, ls->namelen);
256*6a54128fSAndroid Build Coastguard Worker if (ext2fs_has_feature_filetype(ls->sb))
257*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7);
258*6a54128fSAndroid Build Coastguard Worker
259*6a54128fSAndroid Build Coastguard Worker ls->done++;
260*6a54128fSAndroid Build Coastguard Worker return DIRENT_ABORT|DIRENT_CHANGED;
261*6a54128fSAndroid Build Coastguard Worker }
262*6a54128fSAndroid Build Coastguard Worker
add_dirent_to_buf(ext2_filsys fs,e2_blkcnt_t blockcnt,char * buf,ext2_ino_t dir,struct ext2_inode * diri,const char * name,ext2_ino_t ino,int flags,blk64_t * pblkp)263*6a54128fSAndroid Build Coastguard Worker static errcode_t add_dirent_to_buf(ext2_filsys fs, e2_blkcnt_t blockcnt,
264*6a54128fSAndroid Build Coastguard Worker char *buf, ext2_ino_t dir,
265*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *diri, const char *name,
266*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino, int flags, blk64_t *pblkp)
267*6a54128fSAndroid Build Coastguard Worker {
268*6a54128fSAndroid Build Coastguard Worker struct dir_context ctx;
269*6a54128fSAndroid Build Coastguard Worker struct link_struct ls;
270*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
271*6a54128fSAndroid Build Coastguard Worker
272*6a54128fSAndroid Build Coastguard Worker retval = load_logical_dir_block(fs, dir, diri, blockcnt, pblkp, buf);
273*6a54128fSAndroid Build Coastguard Worker if (retval)
274*6a54128fSAndroid Build Coastguard Worker return retval;
275*6a54128fSAndroid Build Coastguard Worker ctx.errcode = 0;
276*6a54128fSAndroid Build Coastguard Worker ctx.func = link_proc;
277*6a54128fSAndroid Build Coastguard Worker ctx.dir = dir;
278*6a54128fSAndroid Build Coastguard Worker ctx.flags = DIRENT_FLAG_INCLUDE_EMPTY;
279*6a54128fSAndroid Build Coastguard Worker ctx.buf = buf;
280*6a54128fSAndroid Build Coastguard Worker ctx.priv_data = &ls;
281*6a54128fSAndroid Build Coastguard Worker
282*6a54128fSAndroid Build Coastguard Worker ls.fs = fs;
283*6a54128fSAndroid Build Coastguard Worker ls.name = name;
284*6a54128fSAndroid Build Coastguard Worker ls.namelen = strlen(name);
285*6a54128fSAndroid Build Coastguard Worker ls.inode = ino;
286*6a54128fSAndroid Build Coastguard Worker ls.flags = flags;
287*6a54128fSAndroid Build Coastguard Worker ls.done = 0;
288*6a54128fSAndroid Build Coastguard Worker ls.sb = fs->super;
289*6a54128fSAndroid Build Coastguard Worker ls.blocksize = fs->blocksize;
290*6a54128fSAndroid Build Coastguard Worker ls.err = 0;
291*6a54128fSAndroid Build Coastguard Worker
292*6a54128fSAndroid Build Coastguard Worker ext2fs_process_dir_block(fs, pblkp, blockcnt, 0, 0, &ctx);
293*6a54128fSAndroid Build Coastguard Worker if (ctx.errcode)
294*6a54128fSAndroid Build Coastguard Worker return ctx.errcode;
295*6a54128fSAndroid Build Coastguard Worker if (ls.err)
296*6a54128fSAndroid Build Coastguard Worker return ls.err;
297*6a54128fSAndroid Build Coastguard Worker if (!ls.done)
298*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_DIR_NO_SPACE;
299*6a54128fSAndroid Build Coastguard Worker return 0;
300*6a54128fSAndroid Build Coastguard Worker }
301*6a54128fSAndroid Build Coastguard Worker
302*6a54128fSAndroid Build Coastguard Worker struct dx_hash_map {
303*6a54128fSAndroid Build Coastguard Worker __u32 hash;
304*6a54128fSAndroid Build Coastguard Worker int size;
305*6a54128fSAndroid Build Coastguard Worker int off;
306*6a54128fSAndroid Build Coastguard Worker };
307*6a54128fSAndroid Build Coastguard Worker
dx_hash_map_cmp(const void * ap,const void * bp)308*6a54128fSAndroid Build Coastguard Worker static EXT2_QSORT_TYPE dx_hash_map_cmp(const void *ap, const void *bp)
309*6a54128fSAndroid Build Coastguard Worker {
310*6a54128fSAndroid Build Coastguard Worker const struct dx_hash_map *a = ap, *b = bp;
311*6a54128fSAndroid Build Coastguard Worker
312*6a54128fSAndroid Build Coastguard Worker if (a->hash < b->hash)
313*6a54128fSAndroid Build Coastguard Worker return -1;
314*6a54128fSAndroid Build Coastguard Worker if (a->hash > b->hash)
315*6a54128fSAndroid Build Coastguard Worker return 1;
316*6a54128fSAndroid Build Coastguard Worker return 0;
317*6a54128fSAndroid Build Coastguard Worker }
318*6a54128fSAndroid Build Coastguard Worker
dx_move_dirents(ext2_filsys fs,struct dx_hash_map * map,int count,void * from,void * to)319*6a54128fSAndroid Build Coastguard Worker static errcode_t dx_move_dirents(ext2_filsys fs, struct dx_hash_map *map,
320*6a54128fSAndroid Build Coastguard Worker int count, void *from, void *to)
321*6a54128fSAndroid Build Coastguard Worker {
322*6a54128fSAndroid Build Coastguard Worker struct ext2_dir_entry *de;
323*6a54128fSAndroid Build Coastguard Worker int i;
324*6a54128fSAndroid Build Coastguard Worker int rec_len = 0;
325*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
326*6a54128fSAndroid Build Coastguard Worker int csum_size = 0;
327*6a54128fSAndroid Build Coastguard Worker void *base = to;
328*6a54128fSAndroid Build Coastguard Worker
329*6a54128fSAndroid Build Coastguard Worker if (ext2fs_has_feature_metadata_csum(fs->super))
330*6a54128fSAndroid Build Coastguard Worker csum_size = sizeof(struct ext2_dir_entry_tail);
331*6a54128fSAndroid Build Coastguard Worker
332*6a54128fSAndroid Build Coastguard Worker for (i = 0; i < count; i++) {
333*6a54128fSAndroid Build Coastguard Worker de = (struct ext2_dir_entry *) ((char *)from + map[i].off);
334*6a54128fSAndroid Build Coastguard Worker rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(de));
335*6a54128fSAndroid Build Coastguard Worker memcpy(to, de, rec_len);
336*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_set_rec_len(fs, rec_len, to);
337*6a54128fSAndroid Build Coastguard Worker if (retval)
338*6a54128fSAndroid Build Coastguard Worker return retval;
339*6a54128fSAndroid Build Coastguard Worker to = (char *)to + rec_len;
340*6a54128fSAndroid Build Coastguard Worker }
341*6a54128fSAndroid Build Coastguard Worker /*
342*6a54128fSAndroid Build Coastguard Worker * Update rec_len of the last dir entry to stretch to the end of block
343*6a54128fSAndroid Build Coastguard Worker */
344*6a54128fSAndroid Build Coastguard Worker to = (char *)to - rec_len;
345*6a54128fSAndroid Build Coastguard Worker rec_len = fs->blocksize - ((char *)to - (char *)base) - csum_size;
346*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_set_rec_len(fs, rec_len, to);
347*6a54128fSAndroid Build Coastguard Worker if (retval)
348*6a54128fSAndroid Build Coastguard Worker return retval;
349*6a54128fSAndroid Build Coastguard Worker if (csum_size)
350*6a54128fSAndroid Build Coastguard Worker ext2fs_initialize_dirent_tail(fs,
351*6a54128fSAndroid Build Coastguard Worker EXT2_DIRENT_TAIL(base, fs->blocksize));
352*6a54128fSAndroid Build Coastguard Worker return 0;
353*6a54128fSAndroid Build Coastguard Worker }
354*6a54128fSAndroid Build Coastguard Worker
dx_insert_entry(ext2_filsys fs,ext2_ino_t dir,struct dx_lookup_info * info,int level,__u32 hash,blk64_t lblk)355*6a54128fSAndroid Build Coastguard Worker static errcode_t dx_insert_entry(ext2_filsys fs, ext2_ino_t dir,
356*6a54128fSAndroid Build Coastguard Worker struct dx_lookup_info *info, int level,
357*6a54128fSAndroid Build Coastguard Worker __u32 hash, blk64_t lblk)
358*6a54128fSAndroid Build Coastguard Worker {
359*6a54128fSAndroid Build Coastguard Worker int pcount;
360*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_entry *top, *new;
361*6a54128fSAndroid Build Coastguard Worker
362*6a54128fSAndroid Build Coastguard Worker pcount = ext2fs_le16_to_cpu(info->frames[level].head->count);
363*6a54128fSAndroid Build Coastguard Worker top = info->frames[level].entries + pcount;
364*6a54128fSAndroid Build Coastguard Worker new = info->frames[level].at + 1;
365*6a54128fSAndroid Build Coastguard Worker memmove(new + 1, new, (char *)top - (char *)new);
366*6a54128fSAndroid Build Coastguard Worker new->hash = ext2fs_cpu_to_le32(hash);
367*6a54128fSAndroid Build Coastguard Worker new->block = ext2fs_cpu_to_le32(lblk);
368*6a54128fSAndroid Build Coastguard Worker info->frames[level].head->count = ext2fs_cpu_to_le16(pcount + 1);
369*6a54128fSAndroid Build Coastguard Worker return ext2fs_write_dir_block4(fs, info->frames[level].pblock,
370*6a54128fSAndroid Build Coastguard Worker info->frames[level].buf, 0, dir);
371*6a54128fSAndroid Build Coastguard Worker }
372*6a54128fSAndroid Build Coastguard Worker
dx_split_leaf(ext2_filsys fs,ext2_ino_t dir,struct ext2_inode * diri,struct dx_lookup_info * info,void * buf,blk64_t leaf_pblk,blk64_t new_lblk,blk64_t new_pblk)373*6a54128fSAndroid Build Coastguard Worker static errcode_t dx_split_leaf(ext2_filsys fs, ext2_ino_t dir,
374*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *diri,
375*6a54128fSAndroid Build Coastguard Worker struct dx_lookup_info *info, void *buf,
376*6a54128fSAndroid Build Coastguard Worker blk64_t leaf_pblk, blk64_t new_lblk,
377*6a54128fSAndroid Build Coastguard Worker blk64_t new_pblk)
378*6a54128fSAndroid Build Coastguard Worker {
379*6a54128fSAndroid Build Coastguard Worker int hash_flags = diri->i_flags & EXT4_CASEFOLD_FL;
380*6a54128fSAndroid Build Coastguard Worker struct ext2_dir_entry *de;
381*6a54128fSAndroid Build Coastguard Worker void *buf2;
382*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
383*6a54128fSAndroid Build Coastguard Worker unsigned int rec_len;
384*6a54128fSAndroid Build Coastguard Worker unsigned int offset, move_size;
385*6a54128fSAndroid Build Coastguard Worker int i, count = 0;
386*6a54128fSAndroid Build Coastguard Worker struct dx_hash_map *map;
387*6a54128fSAndroid Build Coastguard Worker int continued;
388*6a54128fSAndroid Build Coastguard Worker __u32 minor_hash;
389*6a54128fSAndroid Build Coastguard Worker
390*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_mem(fs->blocksize, &buf2);
391*6a54128fSAndroid Build Coastguard Worker if (retval)
392*6a54128fSAndroid Build Coastguard Worker return retval;
393*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_array(fs->blocksize / 12,
394*6a54128fSAndroid Build Coastguard Worker sizeof(struct dx_hash_map), &map);
395*6a54128fSAndroid Build Coastguard Worker if (retval) {
396*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&buf2);
397*6a54128fSAndroid Build Coastguard Worker return retval;
398*6a54128fSAndroid Build Coastguard Worker }
399*6a54128fSAndroid Build Coastguard Worker for (offset = 0; offset < fs->blocksize; offset += rec_len) {
400*6a54128fSAndroid Build Coastguard Worker de = (struct ext2_dir_entry *) ((char *)buf + offset);
401*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_rec_len(fs, de, &rec_len);
402*6a54128fSAndroid Build Coastguard Worker if (retval)
403*6a54128fSAndroid Build Coastguard Worker goto out;
404*6a54128fSAndroid Build Coastguard Worker if (ext2fs_dirent_name_len(de) > 0 && de->inode) {
405*6a54128fSAndroid Build Coastguard Worker map[count].off = offset;
406*6a54128fSAndroid Build Coastguard Worker map[count].size = rec_len;
407*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_dirhash2(info->hash_alg, de->name,
408*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_name_len(de),
409*6a54128fSAndroid Build Coastguard Worker fs->encoding, hash_flags,
410*6a54128fSAndroid Build Coastguard Worker fs->super->s_hash_seed,
411*6a54128fSAndroid Build Coastguard Worker &(map[count].hash),
412*6a54128fSAndroid Build Coastguard Worker &minor_hash);
413*6a54128fSAndroid Build Coastguard Worker if (retval)
414*6a54128fSAndroid Build Coastguard Worker goto out;
415*6a54128fSAndroid Build Coastguard Worker count++;
416*6a54128fSAndroid Build Coastguard Worker }
417*6a54128fSAndroid Build Coastguard Worker }
418*6a54128fSAndroid Build Coastguard Worker qsort(map, count, sizeof(struct dx_hash_map), dx_hash_map_cmp);
419*6a54128fSAndroid Build Coastguard Worker move_size = 0;
420*6a54128fSAndroid Build Coastguard Worker /* Find place to split block */
421*6a54128fSAndroid Build Coastguard Worker for (i = count - 1; i >= 0; i--) {
422*6a54128fSAndroid Build Coastguard Worker if (move_size + map[i].size / 2 > fs->blocksize / 2)
423*6a54128fSAndroid Build Coastguard Worker break;
424*6a54128fSAndroid Build Coastguard Worker move_size += map[i].size;
425*6a54128fSAndroid Build Coastguard Worker }
426*6a54128fSAndroid Build Coastguard Worker /* Let i be the first entry to move */
427*6a54128fSAndroid Build Coastguard Worker i++;
428*6a54128fSAndroid Build Coastguard Worker /* Move selected directory entries to new block */
429*6a54128fSAndroid Build Coastguard Worker retval = dx_move_dirents(fs, map + i, count - i, buf, buf2);
430*6a54128fSAndroid Build Coastguard Worker if (retval)
431*6a54128fSAndroid Build Coastguard Worker goto out;
432*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_dir_block4(fs, new_pblk, buf2, 0, dir);
433*6a54128fSAndroid Build Coastguard Worker if (retval)
434*6a54128fSAndroid Build Coastguard Worker goto out;
435*6a54128fSAndroid Build Coastguard Worker /* Repack remaining entries in the old block */
436*6a54128fSAndroid Build Coastguard Worker retval = dx_move_dirents(fs, map, i, buf, buf2);
437*6a54128fSAndroid Build Coastguard Worker if (retval)
438*6a54128fSAndroid Build Coastguard Worker goto out;
439*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_dir_block4(fs, leaf_pblk, buf2, 0, dir);
440*6a54128fSAndroid Build Coastguard Worker if (retval)
441*6a54128fSAndroid Build Coastguard Worker goto out;
442*6a54128fSAndroid Build Coastguard Worker /* Update parent node */
443*6a54128fSAndroid Build Coastguard Worker continued = map[i].hash == map[i-1].hash;
444*6a54128fSAndroid Build Coastguard Worker retval = dx_insert_entry(fs, dir, info, info->levels - 1,
445*6a54128fSAndroid Build Coastguard Worker map[i].hash + continued, new_lblk);
446*6a54128fSAndroid Build Coastguard Worker out:
447*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&buf2);
448*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&map);
449*6a54128fSAndroid Build Coastguard Worker return retval;
450*6a54128fSAndroid Build Coastguard Worker }
451*6a54128fSAndroid Build Coastguard Worker
dx_grow_tree(ext2_filsys fs,ext2_ino_t dir,struct ext2_inode * diri,struct dx_lookup_info * info,void * buf,blk64_t leaf_pblk)452*6a54128fSAndroid Build Coastguard Worker static errcode_t dx_grow_tree(ext2_filsys fs, ext2_ino_t dir,
453*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *diri,
454*6a54128fSAndroid Build Coastguard Worker struct dx_lookup_info *info, void *buf,
455*6a54128fSAndroid Build Coastguard Worker blk64_t leaf_pblk)
456*6a54128fSAndroid Build Coastguard Worker {
457*6a54128fSAndroid Build Coastguard Worker int i;
458*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
459*6a54128fSAndroid Build Coastguard Worker ext2_off64_t size = EXT2_I_SIZE(diri);
460*6a54128fSAndroid Build Coastguard Worker blk64_t lblk, pblk;
461*6a54128fSAndroid Build Coastguard Worker struct ext2_dir_entry *de;
462*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_countlimit *head;
463*6a54128fSAndroid Build Coastguard Worker int csum_size = 0;
464*6a54128fSAndroid Build Coastguard Worker int count;
465*6a54128fSAndroid Build Coastguard Worker
466*6a54128fSAndroid Build Coastguard Worker if (ext2fs_has_feature_metadata_csum(fs->super))
467*6a54128fSAndroid Build Coastguard Worker csum_size = sizeof(struct ext2_dx_tail);
468*6a54128fSAndroid Build Coastguard Worker
469*6a54128fSAndroid Build Coastguard Worker /* Find level which can accommodate new child */
470*6a54128fSAndroid Build Coastguard Worker for (i = info->levels - 1; i >= 0; i--)
471*6a54128fSAndroid Build Coastguard Worker if (ext2fs_le16_to_cpu(info->frames[i].head->count) <
472*6a54128fSAndroid Build Coastguard Worker ext2fs_le16_to_cpu(info->frames[i].head->limit))
473*6a54128fSAndroid Build Coastguard Worker break;
474*6a54128fSAndroid Build Coastguard Worker /* Need to grow tree depth? */
475*6a54128fSAndroid Build Coastguard Worker if (i < 0 && info->levels >= ext2_dir_htree_level(fs))
476*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_DIR_NO_SPACE;
477*6a54128fSAndroid Build Coastguard Worker lblk = size / fs->blocksize;
478*6a54128fSAndroid Build Coastguard Worker size += fs->blocksize;
479*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_inode_size_set(fs, diri, size);
480*6a54128fSAndroid Build Coastguard Worker if (retval)
481*6a54128fSAndroid Build Coastguard Worker return retval;
482*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_fallocate(fs,
483*6a54128fSAndroid Build Coastguard Worker EXT2_FALLOCATE_FORCE_INIT | EXT2_FALLOCATE_ZERO_BLOCKS,
484*6a54128fSAndroid Build Coastguard Worker dir, diri, 0, lblk, 1);
485*6a54128fSAndroid Build Coastguard Worker if (retval)
486*6a54128fSAndroid Build Coastguard Worker return retval;
487*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_inode(fs, dir, diri);
488*6a54128fSAndroid Build Coastguard Worker if (retval)
489*6a54128fSAndroid Build Coastguard Worker return retval;
490*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_bmap2(fs, dir, diri, NULL, 0, lblk, NULL, &pblk);
491*6a54128fSAndroid Build Coastguard Worker if (retval)
492*6a54128fSAndroid Build Coastguard Worker return retval;
493*6a54128fSAndroid Build Coastguard Worker /* Only leaf addition needed? */
494*6a54128fSAndroid Build Coastguard Worker if (i == (int)info->levels - 1)
495*6a54128fSAndroid Build Coastguard Worker return dx_split_leaf(fs, dir, diri, info, buf, leaf_pblk,
496*6a54128fSAndroid Build Coastguard Worker lblk, pblk);
497*6a54128fSAndroid Build Coastguard Worker
498*6a54128fSAndroid Build Coastguard Worker de = buf;
499*6a54128fSAndroid Build Coastguard Worker de->inode = 0;
500*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_name_len(de, 0);
501*6a54128fSAndroid Build Coastguard Worker ext2fs_dirent_set_file_type(de, 0);
502*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_set_rec_len(fs, fs->blocksize, de);
503*6a54128fSAndroid Build Coastguard Worker if (retval)
504*6a54128fSAndroid Build Coastguard Worker return retval;
505*6a54128fSAndroid Build Coastguard Worker head = (struct ext2_dx_countlimit *) ((char *)buf + 8);
506*6a54128fSAndroid Build Coastguard Worker count = ext2fs_le16_to_cpu(info->frames[i+1].head->count);
507*6a54128fSAndroid Build Coastguard Worker /* Growing tree depth? */
508*6a54128fSAndroid Build Coastguard Worker if (i < 0) {
509*6a54128fSAndroid Build Coastguard Worker struct ext2_dx_root_info *root;
510*6a54128fSAndroid Build Coastguard Worker
511*6a54128fSAndroid Build Coastguard Worker memcpy(head, info->frames[0].entries,
512*6a54128fSAndroid Build Coastguard Worker count * sizeof(struct ext2_dx_entry));
513*6a54128fSAndroid Build Coastguard Worker head->limit = ext2fs_cpu_to_le16(
514*6a54128fSAndroid Build Coastguard Worker (fs->blocksize - (8 + csum_size)) /
515*6a54128fSAndroid Build Coastguard Worker sizeof(struct ext2_dx_entry));
516*6a54128fSAndroid Build Coastguard Worker /* head->count gets set by memcpy above to correct value */
517*6a54128fSAndroid Build Coastguard Worker
518*6a54128fSAndroid Build Coastguard Worker /* Now update tree root */
519*6a54128fSAndroid Build Coastguard Worker info->frames[0].head->count = ext2fs_cpu_to_le16(1);
520*6a54128fSAndroid Build Coastguard Worker info->frames[0].entries[0].block = ext2fs_cpu_to_le32(lblk);
521*6a54128fSAndroid Build Coastguard Worker root = (struct ext2_dx_root_info *)
522*6a54128fSAndroid Build Coastguard Worker ((char *)info->frames[0].buf + EXT2_DX_ROOT_OFF);
523*6a54128fSAndroid Build Coastguard Worker root->indirect_levels++;
524*6a54128fSAndroid Build Coastguard Worker } else {
525*6a54128fSAndroid Build Coastguard Worker /* Splitting internal node in two */
526*6a54128fSAndroid Build Coastguard Worker int count1 = count / 2;
527*6a54128fSAndroid Build Coastguard Worker int count2 = count - count1;
528*6a54128fSAndroid Build Coastguard Worker __u32 split_hash = ext2fs_le32_to_cpu(info->frames[i+1].entries[count1].hash);
529*6a54128fSAndroid Build Coastguard Worker
530*6a54128fSAndroid Build Coastguard Worker memcpy(head, info->frames[i+1].entries + count1,
531*6a54128fSAndroid Build Coastguard Worker count2 * sizeof(struct ext2_dx_entry));
532*6a54128fSAndroid Build Coastguard Worker head->count = ext2fs_cpu_to_le16(count2);
533*6a54128fSAndroid Build Coastguard Worker head->limit = ext2fs_cpu_to_le16(
534*6a54128fSAndroid Build Coastguard Worker (fs->blocksize - (8 + csum_size)) /
535*6a54128fSAndroid Build Coastguard Worker sizeof(struct ext2_dx_entry));
536*6a54128fSAndroid Build Coastguard Worker info->frames[i+1].head->count = ext2fs_cpu_to_le16(count1);
537*6a54128fSAndroid Build Coastguard Worker
538*6a54128fSAndroid Build Coastguard Worker /* Update parent node */
539*6a54128fSAndroid Build Coastguard Worker retval = dx_insert_entry(fs, dir, info, i, split_hash, lblk);
540*6a54128fSAndroid Build Coastguard Worker if (retval)
541*6a54128fSAndroid Build Coastguard Worker return retval;
542*6a54128fSAndroid Build Coastguard Worker
543*6a54128fSAndroid Build Coastguard Worker }
544*6a54128fSAndroid Build Coastguard Worker /* Writeout split block / updated root */
545*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_dir_block4(fs, info->frames[i+1].pblock,
546*6a54128fSAndroid Build Coastguard Worker info->frames[i+1].buf, 0, dir);
547*6a54128fSAndroid Build Coastguard Worker if (retval)
548*6a54128fSAndroid Build Coastguard Worker return retval;
549*6a54128fSAndroid Build Coastguard Worker /* Writeout new tree block */
550*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_write_dir_block4(fs, pblk, buf, 0, dir);
551*6a54128fSAndroid Build Coastguard Worker if (retval)
552*6a54128fSAndroid Build Coastguard Worker return retval;
553*6a54128fSAndroid Build Coastguard Worker return 0;
554*6a54128fSAndroid Build Coastguard Worker }
555*6a54128fSAndroid Build Coastguard Worker
dx_link(ext2_filsys fs,ext2_ino_t dir,struct ext2_inode * diri,const char * name,ext2_ino_t ino,int flags)556*6a54128fSAndroid Build Coastguard Worker static errcode_t dx_link(ext2_filsys fs, ext2_ino_t dir,
557*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *diri, const char *name,
558*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino, int flags)
559*6a54128fSAndroid Build Coastguard Worker {
560*6a54128fSAndroid Build Coastguard Worker struct dx_lookup_info dx_info;
561*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
562*6a54128fSAndroid Build Coastguard Worker void *blockbuf;
563*6a54128fSAndroid Build Coastguard Worker unsigned restart = 0;
564*6a54128fSAndroid Build Coastguard Worker blk64_t leaf_pblk;
565*6a54128fSAndroid Build Coastguard Worker
566*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_mem(fs->blocksize, &blockbuf);
567*6a54128fSAndroid Build Coastguard Worker if (retval)
568*6a54128fSAndroid Build Coastguard Worker return retval;
569*6a54128fSAndroid Build Coastguard Worker
570*6a54128fSAndroid Build Coastguard Worker dx_info.name = name;
571*6a54128fSAndroid Build Coastguard Worker dx_info.namelen = strlen(name);
572*6a54128fSAndroid Build Coastguard Worker again:
573*6a54128fSAndroid Build Coastguard Worker retval = dx_lookup(fs, dir, diri, &dx_info);
574*6a54128fSAndroid Build Coastguard Worker if (retval)
575*6a54128fSAndroid Build Coastguard Worker goto free_buf;
576*6a54128fSAndroid Build Coastguard Worker
577*6a54128fSAndroid Build Coastguard Worker retval = add_dirent_to_buf(fs,
578*6a54128fSAndroid Build Coastguard Worker ext2fs_le32_to_cpu(dx_info.frames[dx_info.levels-1].at->block) & 0x0fffffff,
579*6a54128fSAndroid Build Coastguard Worker blockbuf, dir, diri, name, ino, flags, &leaf_pblk);
580*6a54128fSAndroid Build Coastguard Worker /*
581*6a54128fSAndroid Build Coastguard Worker * Success or error other than ENOSPC...? We are done. We may need upto
582*6a54128fSAndroid Build Coastguard Worker * two tries to add entry. One to split htree node and another to add
583*6a54128fSAndroid Build Coastguard Worker * new leaf block.
584*6a54128fSAndroid Build Coastguard Worker */
585*6a54128fSAndroid Build Coastguard Worker if (restart >= dx_info.levels || retval != EXT2_ET_DIR_NO_SPACE)
586*6a54128fSAndroid Build Coastguard Worker goto free_frames;
587*6a54128fSAndroid Build Coastguard Worker retval = dx_grow_tree(fs, dir, diri, &dx_info, blockbuf, leaf_pblk);
588*6a54128fSAndroid Build Coastguard Worker if (retval)
589*6a54128fSAndroid Build Coastguard Worker goto free_frames;
590*6a54128fSAndroid Build Coastguard Worker /* Restart everything now that the tree is larger */
591*6a54128fSAndroid Build Coastguard Worker restart++;
592*6a54128fSAndroid Build Coastguard Worker dx_release(&dx_info);
593*6a54128fSAndroid Build Coastguard Worker goto again;
594*6a54128fSAndroid Build Coastguard Worker free_frames:
595*6a54128fSAndroid Build Coastguard Worker dx_release(&dx_info);
596*6a54128fSAndroid Build Coastguard Worker free_buf:
597*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&blockbuf);
598*6a54128fSAndroid Build Coastguard Worker return retval;
599*6a54128fSAndroid Build Coastguard Worker }
600*6a54128fSAndroid Build Coastguard Worker
601*6a54128fSAndroid Build Coastguard Worker /*
602*6a54128fSAndroid Build Coastguard Worker * Note: the low 3 bits of the flags field are used as the directory
603*6a54128fSAndroid Build Coastguard Worker * entry filetype.
604*6a54128fSAndroid Build Coastguard Worker */
605*6a54128fSAndroid Build Coastguard Worker #ifdef __TURBOC__
606*6a54128fSAndroid Build Coastguard Worker #pragma argsused
607*6a54128fSAndroid Build Coastguard Worker #endif
ext2fs_link(ext2_filsys fs,ext2_ino_t dir,const char * name,ext2_ino_t ino,int flags)608*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
609*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino, int flags)
610*6a54128fSAndroid Build Coastguard Worker {
611*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
612*6a54128fSAndroid Build Coastguard Worker struct link_struct ls;
613*6a54128fSAndroid Build Coastguard Worker struct ext2_inode inode;
614*6a54128fSAndroid Build Coastguard Worker
615*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
616*6a54128fSAndroid Build Coastguard Worker
617*6a54128fSAndroid Build Coastguard Worker if (!(fs->flags & EXT2_FLAG_RW))
618*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_RO_FILSYS;
619*6a54128fSAndroid Build Coastguard Worker
620*6a54128fSAndroid Build Coastguard Worker if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
621*6a54128fSAndroid Build Coastguard Worker return retval;
622*6a54128fSAndroid Build Coastguard Worker
623*6a54128fSAndroid Build Coastguard Worker if (inode.i_flags & EXT2_INDEX_FL)
624*6a54128fSAndroid Build Coastguard Worker return dx_link(fs, dir, &inode, name, ino, flags);
625*6a54128fSAndroid Build Coastguard Worker
626*6a54128fSAndroid Build Coastguard Worker ls.fs = fs;
627*6a54128fSAndroid Build Coastguard Worker ls.name = name;
628*6a54128fSAndroid Build Coastguard Worker ls.namelen = name ? strlen(name) : 0;
629*6a54128fSAndroid Build Coastguard Worker ls.inode = ino;
630*6a54128fSAndroid Build Coastguard Worker ls.flags = flags;
631*6a54128fSAndroid Build Coastguard Worker ls.done = 0;
632*6a54128fSAndroid Build Coastguard Worker ls.sb = fs->super;
633*6a54128fSAndroid Build Coastguard Worker ls.blocksize = fs->blocksize;
634*6a54128fSAndroid Build Coastguard Worker ls.err = 0;
635*6a54128fSAndroid Build Coastguard Worker
636*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_dir_iterate2(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
637*6a54128fSAndroid Build Coastguard Worker NULL, link_proc, &ls);
638*6a54128fSAndroid Build Coastguard Worker if (retval)
639*6a54128fSAndroid Build Coastguard Worker return retval;
640*6a54128fSAndroid Build Coastguard Worker if (ls.err)
641*6a54128fSAndroid Build Coastguard Worker return ls.err;
642*6a54128fSAndroid Build Coastguard Worker
643*6a54128fSAndroid Build Coastguard Worker if (!ls.done)
644*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_DIR_NO_SPACE;
645*6a54128fSAndroid Build Coastguard Worker return 0;
646*6a54128fSAndroid Build Coastguard Worker }
647