]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - misc/create_inode.c
Merge branch 'maint' into next
[thirdparty/e2fsprogs.git] / misc / create_inode.c
CommitLineData
8f8d8a57
DW
1#include <time.h>
2#include <unistd.h>
3
0d4deba2
RY
4#include "create_inode.h"
5
052064b9
RY
6#if __STDC_VERSION__ < 199901L
7# if __GNUC__ >= 2
8# define __func__ __FUNCTION__
9# else
10# define __func__ "<unknown>"
11# endif
12#endif
13
ce600dc4
RY
14/* 64KiB is the minimium blksize to best minimize system call overhead. */
15#ifndef IO_BUFSIZE
16#define IO_BUFSIZE 64*1024
17#endif
18
19/* Block size for `st_blocks' */
20#ifndef S_BLKSIZE
21#define S_BLKSIZE 512
22#endif
23
f84894bc 24/* Link an inode number to a directory */
a3111e80
DW
25static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino,
26 ext2_ino_t ino, const char *name)
f84894bc
RY
27{
28 struct ext2_inode inode;
29 errcode_t retval;
30
a3111e80 31 retval = ext2fs_read_inode(fs, ino, &inode);
f84894bc
RY
32 if (retval) {
33 com_err(__func__, retval, "while reading inode %u", ino);
34 return retval;
35 }
36
a3111e80 37 retval = ext2fs_link(fs, parent_ino, name, ino, inode.i_flags);
f84894bc 38 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 39 retval = ext2fs_expand_dir(fs, parent_ino);
f84894bc
RY
40 if (retval) {
41 com_err(__func__, retval, "while expanding directory");
42 return retval;
43 }
a3111e80 44 retval = ext2fs_link(fs, parent_ino, name, ino, inode.i_flags);
f84894bc
RY
45 }
46 if (retval) {
47 com_err(__func__, retval, "while linking %s", name);
48 return retval;
49 }
50
51 inode.i_links_count++;
52
a3111e80 53 retval = ext2fs_write_inode(fs, ino, &inode);
f84894bc
RY
54 if (retval)
55 com_err(__func__, retval, "while writing inode %u", ino);
56
57 return retval;
58}
59
b6960654
RY
60/* Fill the uid, gid, mode and time for the inode */
61static void fill_inode(struct ext2_inode *inode, struct stat *st)
62{
63 if (st != NULL) {
64 inode->i_uid = st->st_uid;
65 inode->i_gid = st->st_gid;
66 inode->i_mode |= st->st_mode;
67 inode->i_atime = st->st_atime;
68 inode->i_mtime = st->st_mtime;
69 inode->i_ctime = st->st_ctime;
70 }
71}
72
73/* Set the uid, gid, mode and time for the inode */
a3111e80
DW
74static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t cwd,
75 ext2_ino_t ino, struct stat *st)
b6960654
RY
76{
77 errcode_t retval;
78 struct ext2_inode inode;
79
a3111e80 80 retval = ext2fs_read_inode(fs, ino, &inode);
b6960654
RY
81 if (retval) {
82 com_err(__func__, retval, "while reading inode %u", ino);
83 return retval;
84 }
85
86 fill_inode(&inode, st);
87
a3111e80 88 retval = ext2fs_write_inode(fs, ino, &inode);
3aec816f 89 if (retval)
b6960654 90 com_err(__func__, retval, "while writing inode %u", ino);
3aec816f 91 return retval;
b6960654
RY
92}
93
c61e0068 94/* Make a special files (block and character devices), fifo's, and sockets */
a3111e80
DW
95errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
96 struct stat *st)
0d4deba2 97{
b2346118
RY
98 ext2_ino_t ino;
99 errcode_t retval;
100 struct ext2_inode inode;
101 unsigned long major, minor, mode;
102 int filetype;
103
104 switch(st->st_mode & S_IFMT) {
9c891f7e
DW
105 case S_IFCHR:
106 mode = LINUX_S_IFCHR;
107 filetype = EXT2_FT_CHRDEV;
108 break;
109 case S_IFBLK:
110 mode = LINUX_S_IFBLK;
111 filetype = EXT2_FT_BLKDEV;
112 break;
113 case S_IFIFO:
114 mode = LINUX_S_IFIFO;
115 filetype = EXT2_FT_FIFO;
116 break;
c61e0068
DW
117 case S_IFSOCK:
118 mode = LINUX_S_IFSOCK;
119 filetype = EXT2_FT_SOCK;
3aec816f
TT
120 default:
121 abort();
122 /* NOTREACHED */
b2346118
RY
123 }
124
a3111e80 125 if (!(fs->flags & EXT2_FLAG_RW)) {
b2346118 126 com_err(__func__, 0, "Filesystem opened read/only");
c61e0068 127 return EROFS;
b2346118 128 }
a3111e80 129 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino);
b2346118
RY
130 if (retval) {
131 com_err(__func__, retval, 0);
132 return retval;
133 }
134
135#ifdef DEBUGFS
136 printf("Allocated inode: %u\n", ino);
137#endif
a3111e80 138 retval = ext2fs_link(fs, cwd, name, ino, filetype);
b2346118 139 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 140 retval = ext2fs_expand_dir(fs, cwd);
b2346118
RY
141 if (retval) {
142 com_err(__func__, retval, "while expanding directory");
143 return retval;
144 }
a3111e80 145 retval = ext2fs_link(fs, cwd, name, ino, filetype);
b2346118
RY
146 }
147 if (retval) {
148 com_err(name, retval, 0);
149 return -1;
150 }
a3111e80 151 if (ext2fs_test_inode_bitmap2(fs->inode_map, ino))
b2346118 152 com_err(__func__, 0, "Warning: inode already set");
a3111e80 153 ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
b2346118
RY
154 memset(&inode, 0, sizeof(inode));
155 inode.i_mode = mode;
156 inode.i_atime = inode.i_ctime = inode.i_mtime =
a3111e80 157 fs->now ? fs->now : time(0);
b2346118
RY
158
159 major = major(st->st_rdev);
160 minor = minor(st->st_rdev);
161
162 if ((major < 256) && (minor < 256)) {
163 inode.i_block[0] = major * 256 + minor;
164 inode.i_block[1] = 0;
165 } else {
166 inode.i_block[0] = 0;
9c891f7e
DW
167 inode.i_block[1] = (minor & 0xff) | (major << 8) |
168 ((minor & ~0xff) << 12);
b2346118
RY
169 }
170 inode.i_links_count = 1;
171
a3111e80 172 retval = ext2fs_write_new_inode(fs, ino, &inode);
b2346118
RY
173 if (retval)
174 com_err(__func__, retval, "while creating inode %u", ino);
175
176 return retval;
0d4deba2
RY
177}
178
179/* Make a symlink name -> target */
a3111e80
DW
180errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
181 char *target, ext2_ino_t root)
0d4deba2 182{
b25ddc5e
RY
183 char *cp;
184 ext2_ino_t parent_ino;
185 errcode_t retval;
186 struct ext2_inode inode;
187 struct stat st;
188
189 cp = strrchr(name, '/');
190 if (cp) {
191 *cp = 0;
a3111e80 192 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
8f8d8a57 193 if (retval) {
b25ddc5e
RY
194 com_err(name, retval, 0);
195 return retval;
196 }
197 name = cp+1;
198 } else
199 parent_ino = cwd;
200
201try_again:
a3111e80 202 retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
b25ddc5e 203 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 204 retval = ext2fs_expand_dir(fs, parent_ino);
b25ddc5e 205 if (retval) {
9c891f7e
DW
206 com_err("do_symlink_internal", retval,
207 "while expanding directory");
b25ddc5e
RY
208 return retval;
209 }
210 goto try_again;
211 }
3aec816f 212 if (retval)
b25ddc5e 213 com_err("ext2fs_symlink", retval, 0);
3aec816f 214 return retval;
0d4deba2
RY
215}
216
217/* Make a directory in the fs */
a3111e80
DW
218errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
219 struct stat *st, ext2_ino_t root)
0d4deba2 220{
3068f03f
RY
221 char *cp;
222 ext2_ino_t parent_ino, ino;
223 errcode_t retval;
224 struct ext2_inode inode;
225
226
227 cp = strrchr(name, '/');
228 if (cp) {
229 *cp = 0;
a3111e80 230 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
8f8d8a57 231 if (retval) {
3068f03f
RY
232 com_err(name, retval, 0);
233 return retval;
234 }
235 name = cp+1;
236 } else
237 parent_ino = cwd;
238
239try_again:
a3111e80 240 retval = ext2fs_mkdir(fs, parent_ino, 0, name);
3068f03f 241 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 242 retval = ext2fs_expand_dir(fs, parent_ino);
3068f03f
RY
243 if (retval) {
244 com_err(__func__, retval, "while expanding directory");
245 return retval;
246 }
247 goto try_again;
248 }
3aec816f 249 if (retval)
3068f03f 250 com_err("ext2fs_mkdir", retval, 0);
3aec816f 251 return retval;
0d4deba2
RY
252}
253
a3111e80
DW
254static errcode_t copy_file(ext2_filsys fs, int fd, ext2_ino_t newfile,
255 int bufsize, int make_holes)
ce600dc4
RY
256{
257 ext2_file_t e2_file;
258 errcode_t retval;
259 int got;
260 unsigned int written;
261 char *buf;
262 char *ptr;
263 char *zero_buf;
264 int cmp;
265
a3111e80 266 retval = ext2fs_file_open(fs, newfile,
ce600dc4
RY
267 EXT2_FILE_WRITE, &e2_file);
268 if (retval)
269 return retval;
270
271 retval = ext2fs_get_mem(bufsize, &buf);
272 if (retval) {
273 com_err("copy_file", retval, "can't allocate buffer\n");
274 return retval;
275 }
276
277 /* This is used for checking whether the whole block is zero */
278 retval = ext2fs_get_memzero(bufsize, &zero_buf);
279 if (retval) {
280 com_err("copy_file", retval, "can't allocate buffer\n");
281 ext2fs_free_mem(&buf);
282 return retval;
283 }
284
285 while (1) {
286 got = read(fd, buf, bufsize);
287 if (got == 0)
288 break;
289 if (got < 0) {
290 retval = errno;
291 goto fail;
292 }
293 ptr = buf;
294
295 /* Sparse copy */
296 if (make_holes) {
297 /* Check whether all is zero */
298 cmp = memcmp(ptr, zero_buf, got);
299 if (cmp == 0) {
300 /* The whole block is zero, make a hole */
9c891f7e
DW
301 retval = ext2fs_file_lseek(e2_file, got,
302 EXT2_SEEK_CUR,
303 NULL);
ce600dc4
RY
304 if (retval)
305 goto fail;
306 got = 0;
307 }
308 }
309
310 /* Normal copy */
311 while (got > 0) {
312 retval = ext2fs_file_write(e2_file, ptr,
313 got, &written);
314 if (retval)
315 goto fail;
316
317 got -= written;
318 ptr += written;
319 }
320 }
321 ext2fs_free_mem(&buf);
322 ext2fs_free_mem(&zero_buf);
323 retval = ext2fs_file_close(e2_file);
324 return retval;
325
326fail:
327 ext2fs_free_mem(&buf);
328 ext2fs_free_mem(&zero_buf);
329 (void) ext2fs_file_close(e2_file);
330 return retval;
331}
332
b99888a0 333static int is_hardlink(struct hdlinks_s *hdlinks, dev_t dev, ino_t ino)
f84894bc
RY
334{
335 int i;
336
b99888a0
DW
337 for (i = 0; i < hdlinks->count; i++) {
338 if (hdlinks->hdl[i].src_dev == dev &&
339 hdlinks->hdl[i].src_ino == ino)
f84894bc
RY
340 return i;
341 }
342 return -1;
343}
344
0d4deba2 345/* Copy the native file to the fs */
a3111e80
DW
346errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
347 const char *dest, ext2_ino_t root)
0d4deba2 348{
ce600dc4
RY
349 int fd;
350 struct stat statbuf;
351 ext2_ino_t newfile;
352 errcode_t retval;
353 struct ext2_inode inode;
354 int bufsize = IO_BUFSIZE;
355 int make_holes = 0;
356
357 fd = open(src, O_RDONLY);
358 if (fd < 0) {
359 com_err(src, errno, 0);
360 return errno;
361 }
362 if (fstat(fd, &statbuf) < 0) {
363 com_err(src, errno, 0);
364 close(fd);
365 return errno;
366 }
367
a3111e80 368 retval = ext2fs_namei(fs, root, cwd, dest, &newfile);
ce600dc4 369 if (retval == 0) {
ce600dc4 370 close(fd);
117b54c3 371 return EXT2_ET_FILE_EXISTS;
ce600dc4
RY
372 }
373
a3111e80 374 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
ce600dc4
RY
375 if (retval) {
376 com_err(__func__, retval, 0);
377 close(fd);
117b54c3 378 return retval;
ce600dc4
RY
379 }
380#ifdef DEBUGFS
381 printf("Allocated inode: %u\n", newfile);
382#endif
a3111e80 383 retval = ext2fs_link(fs, cwd, dest, newfile,
ce600dc4
RY
384 EXT2_FT_REG_FILE);
385 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 386 retval = ext2fs_expand_dir(fs, cwd);
ce600dc4
RY
387 if (retval) {
388 com_err(__func__, retval, "while expanding directory");
389 close(fd);
117b54c3 390 return retval;
ce600dc4 391 }
a3111e80 392 retval = ext2fs_link(fs, cwd, dest, newfile,
ce600dc4
RY
393 EXT2_FT_REG_FILE);
394 }
395 if (retval) {
396 com_err(dest, retval, 0);
397 close(fd);
398 return errno;
399 }
a3111e80 400 if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile))
ce600dc4 401 com_err(__func__, 0, "Warning: inode already set");
a3111e80 402 ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
ce600dc4
RY
403 memset(&inode, 0, sizeof(inode));
404 inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
405 inode.i_atime = inode.i_ctime = inode.i_mtime =
a3111e80 406 fs->now ? fs->now : time(0);
ce600dc4
RY
407 inode.i_links_count = 1;
408 inode.i_size = statbuf.st_size;
a3111e80 409 if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
d23b1965
TT
410 EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
411 inode.i_flags |= EXT4_INLINE_DATA_FL;
a3111e80 412 } else if (fs->super->s_feature_incompat &
d23b1965 413 EXT3_FEATURE_INCOMPAT_EXTENTS) {
ce600dc4
RY
414 int i;
415 struct ext3_extent_header *eh;
416
417 eh = (struct ext3_extent_header *) &inode.i_block[0];
418 eh->eh_depth = 0;
419 eh->eh_entries = 0;
420 eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
421 i = (sizeof(inode.i_block) - sizeof(*eh)) /
422 sizeof(struct ext3_extent);
423 eh->eh_max = ext2fs_cpu_to_le16(i);
424 inode.i_flags |= EXT4_EXTENTS_FL;
425 }
426
a3111e80 427 retval = ext2fs_write_new_inode(fs, newfile, &inode);
8f8d8a57 428 if (retval) {
ce600dc4
RY
429 com_err(__func__, retval, "while creating inode %u", newfile);
430 close(fd);
117b54c3 431 return retval;
ce600dc4 432 }
d23b1965 433 if (inode.i_flags & EXT4_INLINE_DATA_FL) {
a3111e80 434 retval = ext2fs_inline_data_init(fs, newfile);
117b54c3
DW
435 if (retval) {
436 com_err("copy_file", retval, 0);
437 close(fd);
438 return retval;
439 }
d23b1965 440 }
ce600dc4
RY
441 if (LINUX_S_ISREG(inode.i_mode)) {
442 if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
443 make_holes = 1;
444 /*
445 * Use I/O blocksize as buffer size when
446 * copying sparse files.
447 */
448 bufsize = statbuf.st_blksize;
449 }
a3111e80 450 retval = copy_file(fs, fd, newfile, bufsize, make_holes);
ce600dc4
RY
451 if (retval)
452 com_err("copy_file", retval, 0);
453 }
454 close(fd);
455
117b54c3 456 return retval;
0d4deba2
RY
457}
458
459/* Copy files from source_dir to fs */
b99888a0
DW
460static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
461 const char *source_dir, ext2_ino_t root,
462 struct hdlinks_s *hdlinks)
0d4deba2 463{
052064b9
RY
464 const char *name;
465 DIR *dh;
466 struct dirent *dent;
467 struct stat st;
468 char ln_target[PATH_MAX];
f84894bc 469 unsigned int save_inode;
052064b9 470 ext2_ino_t ino;
1bad6f46 471 errcode_t retval = 0;
052064b9 472 int read_cnt;
f84894bc 473 int hdlink;
052064b9 474
052064b9
RY
475 if (chdir(source_dir) < 0) {
476 com_err(__func__, errno,
9c891f7e
DW
477 _("while changing working directory to \"%s\""),
478 source_dir);
052064b9
RY
479 return errno;
480 }
481
482 if (!(dh = opendir("."))) {
483 com_err(__func__, errno,
8f8d8a57 484 _("while opening directory \"%s\""), source_dir);
052064b9
RY
485 return errno;
486 }
487
8f8d8a57 488 while ((dent = readdir(dh))) {
9c891f7e
DW
489 if ((!strcmp(dent->d_name, ".")) ||
490 (!strcmp(dent->d_name, "..")))
052064b9 491 continue;
1bad6f46
DW
492 if (lstat(dent->d_name, &st)) {
493 com_err(__func__, errno, _("while lstat \"%s\""),
494 dent->d_name);
495 goto out;
496 }
052064b9
RY
497 name = dent->d_name;
498
f84894bc
RY
499 /* Check for hardlinks */
500 save_inode = 0;
9c891f7e
DW
501 if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) &&
502 st.st_nlink > 1) {
b99888a0 503 hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino);
f84894bc 504 if (hdlink >= 0) {
a3111e80 505 retval = add_link(fs, parent_ino,
b99888a0 506 hdlinks->hdl[hdlink].dst_ino,
9c891f7e 507 name);
f84894bc 508 if (retval) {
9c891f7e
DW
509 com_err(__func__, retval,
510 "while linking %s", name);
1bad6f46 511 goto out;
f84894bc
RY
512 }
513 continue;
514 } else
515 save_inode = 1;
516 }
517
052064b9 518 switch(st.st_mode & S_IFMT) {
9c891f7e
DW
519 case S_IFCHR:
520 case S_IFBLK:
521 case S_IFIFO:
c61e0068 522 case S_IFSOCK:
a3111e80 523 retval = do_mknod_internal(fs, parent_ino, name, &st);
9c891f7e
DW
524 if (retval) {
525 com_err(__func__, retval,
526 _("while creating special file "
527 "\"%s\""), name);
1bad6f46 528 goto out;
9c891f7e
DW
529 }
530 break;
9c891f7e
DW
531 case S_IFLNK:
532 read_cnt = readlink(name, ln_target,
1bad6f46 533 sizeof(ln_target) - 1);
9c891f7e
DW
534 if (read_cnt == -1) {
535 com_err(__func__, errno,
536 _("while trying to readlink \"%s\""),
537 name);
538 return errno;
539 }
540 ln_target[read_cnt] = '\0';
a3111e80
DW
541 retval = do_symlink_internal(fs, parent_ino, name,
542 ln_target, root);
9c891f7e
DW
543 if (retval) {
544 com_err(__func__, retval,
545 _("while writing symlink\"%s\""),
546 name);
1bad6f46 547 goto out;
9c891f7e
DW
548 }
549 break;
550 case S_IFREG:
a3111e80
DW
551 retval = do_write_internal(fs, parent_ino, name, name,
552 root);
9c891f7e
DW
553 if (retval) {
554 com_err(__func__, retval,
555 _("while writing file \"%s\""), name);
1bad6f46 556 goto out;
9c891f7e
DW
557 }
558 break;
559 case S_IFDIR:
a3111e80
DW
560 retval = do_mkdir_internal(fs, parent_ino, name, &st,
561 root);
9c891f7e
DW
562 if (retval) {
563 com_err(__func__, retval,
564 _("while making dir \"%s\""), name);
1bad6f46 565 goto out;
9c891f7e 566 }
a3111e80 567 retval = ext2fs_namei(fs, root, parent_ino,
9c891f7e
DW
568 name, &ino);
569 if (retval) {
570 com_err(name, retval, 0);
1bad6f46 571 goto out;
9c891f7e
DW
572 }
573 /* Populate the dir recursively*/
b99888a0 574 retval = __populate_fs(fs, ino, name, root, hdlinks);
9c891f7e
DW
575 if (retval) {
576 com_err(__func__, retval,
577 _("while adding dir \"%s\""), name);
1bad6f46 578 goto out;
9c891f7e 579 }
a3111e80 580 if (chdir("..")) {
1bad6f46
DW
581 com_err(__func__, errno, _("during cd .."));
582 retval = errno;
583 goto out;
a3111e80 584 }
9c891f7e
DW
585 break;
586 default:
587 com_err(__func__, 0,
588 _("ignoring entry \"%s\""), name);
052064b9 589 }
b6960654 590
a3111e80 591 retval = ext2fs_namei(fs, root, parent_ino, name, &ino);
8f8d8a57 592 if (retval) {
b6960654 593 com_err(name, retval, 0);
1bad6f46 594 goto out;
b6960654
RY
595 }
596
a3111e80 597 retval = set_inode_extra(fs, parent_ino, ino, &st);
8f8d8a57 598 if (retval) {
b6960654
RY
599 com_err(__func__, retval,
600 _("while setting inode for \"%s\""), name);
1bad6f46 601 goto out;
b6960654 602 }
f84894bc
RY
603
604 /* Save the hardlink ino */
605 if (save_inode) {
606 /*
607 * Check whether need more memory, and we don't need
608 * free() since the lifespan will be over after the fs
609 * populated.
610 */
b99888a0
DW
611 if (hdlinks->count == hdlinks->size) {
612 void *p = realloc(hdlinks->hdl,
613 (hdlinks->size + HDLINK_CNT) *
614 sizeof(struct hdlink_s));
615 if (p == NULL) {
616 com_err(name, errno,
617 _("Not enough memory"));
1bad6f46
DW
618 retval = EXT2_ET_NO_MEMORY;
619 goto out;
f84894bc 620 }
b99888a0
DW
621 hdlinks->hdl = p;
622 hdlinks->size += HDLINK_CNT;
f84894bc 623 }
b99888a0
DW
624 hdlinks->hdl[hdlinks->count].src_dev = st.st_dev;
625 hdlinks->hdl[hdlinks->count].src_ino = st.st_ino;
626 hdlinks->hdl[hdlinks->count].dst_ino = ino;
627 hdlinks->count++;
f84894bc 628 }
052064b9 629 }
1bad6f46
DW
630
631out:
052064b9
RY
632 closedir(dh);
633 return retval;
0d4deba2 634}
b99888a0
DW
635
636errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
637 const char *source_dir, ext2_ino_t root)
638{
639 struct hdlinks_s hdlinks;
640 errcode_t retval;
641
642 hdlinks.count = 0;
643 hdlinks.size = HDLINK_CNT;
644 hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s));
645 if (hdlinks.hdl == NULL) {
646 com_err(__func__, errno, "Not enough memory");
647 return errno;
648 }
649
650 retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks);
651
652 free(hdlinks.hdl);
653 return retval;
654}