]> 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 98 ext2_ino_t ino;
3cbb51f9 99 errcode_t retval;
b2346118 100 struct ext2_inode inode;
3cbb51f9 101 unsigned long devmajor, devminor, mode;
b2346118
RY
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;
ec3a42b1 120 break;
3aec816f 121 default:
ec3a42b1 122 return EXT2_ET_INVALID_ARGUMENT;
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);
ec3a42b1 149 return retval;
b2346118 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 158
3cbb51f9
AD
159 if (filetype != S_IFIFO) {
160 devmajor = major(st->st_rdev);
161 devminor = minor(st->st_rdev);
162
163 if ((devmajor < 256) && (devminor < 256)) {
164 inode.i_block[0] = devmajor * 256 + devminor;
165 inode.i_block[1] = 0;
166 } else {
167 inode.i_block[0] = 0;
168 inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) |
169 ((devminor & ~0xff) << 12);
170 }
b2346118
RY
171 }
172 inode.i_links_count = 1;
173
a3111e80 174 retval = ext2fs_write_new_inode(fs, ino, &inode);
b2346118
RY
175 if (retval)
176 com_err(__func__, retval, "while creating inode %u", ino);
177
178 return retval;
0d4deba2
RY
179}
180
181/* Make a symlink name -> target */
a3111e80
DW
182errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
183 char *target, ext2_ino_t root)
0d4deba2 184{
b25ddc5e
RY
185 char *cp;
186 ext2_ino_t parent_ino;
187 errcode_t retval;
188 struct ext2_inode inode;
189 struct stat st;
190
191 cp = strrchr(name, '/');
192 if (cp) {
193 *cp = 0;
a3111e80 194 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
8f8d8a57 195 if (retval) {
b25ddc5e
RY
196 com_err(name, retval, 0);
197 return retval;
198 }
199 name = cp+1;
200 } else
201 parent_ino = cwd;
202
203try_again:
a3111e80 204 retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
b25ddc5e 205 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 206 retval = ext2fs_expand_dir(fs, parent_ino);
b25ddc5e 207 if (retval) {
9c891f7e
DW
208 com_err("do_symlink_internal", retval,
209 "while expanding directory");
b25ddc5e
RY
210 return retval;
211 }
212 goto try_again;
213 }
3aec816f 214 if (retval)
b25ddc5e 215 com_err("ext2fs_symlink", retval, 0);
3aec816f 216 return retval;
0d4deba2
RY
217}
218
219/* Make a directory in the fs */
a3111e80
DW
220errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
221 struct stat *st, ext2_ino_t root)
0d4deba2 222{
3068f03f
RY
223 char *cp;
224 ext2_ino_t parent_ino, ino;
225 errcode_t retval;
226 struct ext2_inode inode;
227
228
229 cp = strrchr(name, '/');
230 if (cp) {
231 *cp = 0;
a3111e80 232 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
8f8d8a57 233 if (retval) {
3068f03f
RY
234 com_err(name, retval, 0);
235 return retval;
236 }
237 name = cp+1;
238 } else
239 parent_ino = cwd;
240
241try_again:
a3111e80 242 retval = ext2fs_mkdir(fs, parent_ino, 0, name);
3068f03f 243 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 244 retval = ext2fs_expand_dir(fs, parent_ino);
3068f03f
RY
245 if (retval) {
246 com_err(__func__, retval, "while expanding directory");
247 return retval;
248 }
249 goto try_again;
250 }
3aec816f 251 if (retval)
3068f03f 252 com_err("ext2fs_mkdir", retval, 0);
3aec816f 253 return retval;
0d4deba2
RY
254}
255
a3111e80
DW
256static errcode_t copy_file(ext2_filsys fs, int fd, ext2_ino_t newfile,
257 int bufsize, int make_holes)
ce600dc4
RY
258{
259 ext2_file_t e2_file;
6bb88459 260 errcode_t retval, close_ret;
ce600dc4
RY
261 int got;
262 unsigned int written;
263 char *buf;
264 char *ptr;
265 char *zero_buf;
266 int cmp;
267
a3111e80 268 retval = ext2fs_file_open(fs, newfile,
ce600dc4
RY
269 EXT2_FILE_WRITE, &e2_file);
270 if (retval)
271 return retval;
272
273 retval = ext2fs_get_mem(bufsize, &buf);
274 if (retval) {
275 com_err("copy_file", retval, "can't allocate buffer\n");
6bb88459 276 goto out_close;
ce600dc4
RY
277 }
278
279 /* This is used for checking whether the whole block is zero */
280 retval = ext2fs_get_memzero(bufsize, &zero_buf);
281 if (retval) {
6bb88459
TT
282 com_err("copy_file", retval, "can't allocate zero buffer\n");
283 goto out_free_buf;
ce600dc4
RY
284 }
285
286 while (1) {
287 got = read(fd, buf, bufsize);
288 if (got == 0)
289 break;
290 if (got < 0) {
291 retval = errno;
292 goto fail;
293 }
294 ptr = buf;
295
296 /* Sparse copy */
297 if (make_holes) {
298 /* Check whether all is zero */
299 cmp = memcmp(ptr, zero_buf, got);
300 if (cmp == 0) {
301 /* The whole block is zero, make a hole */
9c891f7e
DW
302 retval = ext2fs_file_lseek(e2_file, got,
303 EXT2_SEEK_CUR,
304 NULL);
ce600dc4
RY
305 if (retval)
306 goto fail;
307 got = 0;
308 }
309 }
310
311 /* Normal copy */
312 while (got > 0) {
313 retval = ext2fs_file_write(e2_file, ptr,
314 got, &written);
315 if (retval)
316 goto fail;
317
318 got -= written;
319 ptr += written;
320 }
321 }
ce600dc4
RY
322
323fail:
ce600dc4 324 ext2fs_free_mem(&zero_buf);
6bb88459
TT
325out_free_buf:
326 ext2fs_free_mem(&buf);
327out_close:
328 close_ret = ext2fs_file_close(e2_file);
329 if (retval == 0)
330 retval = close_ret;
ce600dc4
RY
331 return retval;
332}
333
b99888a0 334static int is_hardlink(struct hdlinks_s *hdlinks, dev_t dev, ino_t ino)
f84894bc
RY
335{
336 int i;
337
b99888a0
DW
338 for (i = 0; i < hdlinks->count; i++) {
339 if (hdlinks->hdl[i].src_dev == dev &&
340 hdlinks->hdl[i].src_ino == ino)
f84894bc
RY
341 return i;
342 }
343 return -1;
344}
345
0d4deba2 346/* Copy the native file to the fs */
a3111e80
DW
347errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
348 const char *dest, ext2_ino_t root)
0d4deba2 349{
ce600dc4
RY
350 int fd;
351 struct stat statbuf;
352 ext2_ino_t newfile;
353 errcode_t retval;
354 struct ext2_inode inode;
355 int bufsize = IO_BUFSIZE;
356 int make_holes = 0;
357
ec3a42b1 358 fd = ext2fs_open_file(src, O_RDONLY, 0);
ce600dc4
RY
359 if (fd < 0) {
360 com_err(src, errno, 0);
361 return errno;
362 }
363 if (fstat(fd, &statbuf) < 0) {
364 com_err(src, errno, 0);
365 close(fd);
366 return errno;
367 }
368
a3111e80 369 retval = ext2fs_namei(fs, root, cwd, dest, &newfile);
ce600dc4 370 if (retval == 0) {
ce600dc4 371 close(fd);
117b54c3 372 return EXT2_ET_FILE_EXISTS;
ce600dc4
RY
373 }
374
a3111e80 375 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
ce600dc4
RY
376 if (retval) {
377 com_err(__func__, retval, 0);
378 close(fd);
117b54c3 379 return retval;
ce600dc4
RY
380 }
381#ifdef DEBUGFS
382 printf("Allocated inode: %u\n", newfile);
383#endif
a3111e80 384 retval = ext2fs_link(fs, cwd, dest, newfile,
ce600dc4
RY
385 EXT2_FT_REG_FILE);
386 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 387 retval = ext2fs_expand_dir(fs, cwd);
ce600dc4
RY
388 if (retval) {
389 com_err(__func__, retval, "while expanding directory");
390 close(fd);
117b54c3 391 return retval;
ce600dc4 392 }
a3111e80 393 retval = ext2fs_link(fs, cwd, dest, newfile,
ce600dc4
RY
394 EXT2_FT_REG_FILE);
395 }
396 if (retval) {
397 com_err(dest, retval, 0);
398 close(fd);
399 return errno;
400 }
a3111e80 401 if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile))
ce600dc4 402 com_err(__func__, 0, "Warning: inode already set");
a3111e80 403 ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
ce600dc4
RY
404 memset(&inode, 0, sizeof(inode));
405 inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
406 inode.i_atime = inode.i_ctime = inode.i_mtime =
a3111e80 407 fs->now ? fs->now : time(0);
ce600dc4
RY
408 inode.i_links_count = 1;
409 inode.i_size = statbuf.st_size;
a3111e80 410 if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
d23b1965
TT
411 EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
412 inode.i_flags |= EXT4_INLINE_DATA_FL;
a3111e80 413 } else if (fs->super->s_feature_incompat &
d23b1965 414 EXT3_FEATURE_INCOMPAT_EXTENTS) {
ce600dc4
RY
415 int i;
416 struct ext3_extent_header *eh;
417
418 eh = (struct ext3_extent_header *) &inode.i_block[0];
419 eh->eh_depth = 0;
420 eh->eh_entries = 0;
421 eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
422 i = (sizeof(inode.i_block) - sizeof(*eh)) /
423 sizeof(struct ext3_extent);
424 eh->eh_max = ext2fs_cpu_to_le16(i);
425 inode.i_flags |= EXT4_EXTENTS_FL;
426 }
427
a3111e80 428 retval = ext2fs_write_new_inode(fs, newfile, &inode);
8f8d8a57 429 if (retval) {
ce600dc4
RY
430 com_err(__func__, retval, "while creating inode %u", newfile);
431 close(fd);
117b54c3 432 return retval;
ce600dc4 433 }
d23b1965 434 if (inode.i_flags & EXT4_INLINE_DATA_FL) {
a3111e80 435 retval = ext2fs_inline_data_init(fs, newfile);
117b54c3
DW
436 if (retval) {
437 com_err("copy_file", retval, 0);
438 close(fd);
439 return retval;
440 }
d23b1965 441 }
ce600dc4
RY
442 if (LINUX_S_ISREG(inode.i_mode)) {
443 if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
444 make_holes = 1;
445 /*
446 * Use I/O blocksize as buffer size when
447 * copying sparse files.
448 */
449 bufsize = statbuf.st_blksize;
450 }
a3111e80 451 retval = copy_file(fs, fd, newfile, bufsize, make_holes);
ce600dc4
RY
452 if (retval)
453 com_err("copy_file", retval, 0);
454 }
455 close(fd);
456
117b54c3 457 return retval;
0d4deba2
RY
458}
459
460/* Copy files from source_dir to fs */
b99888a0
DW
461static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
462 const char *source_dir, ext2_ino_t root,
463 struct hdlinks_s *hdlinks)
0d4deba2 464{
052064b9
RY
465 const char *name;
466 DIR *dh;
467 struct dirent *dent;
468 struct stat st;
469 char ln_target[PATH_MAX];
f84894bc 470 unsigned int save_inode;
052064b9 471 ext2_ino_t ino;
1bad6f46 472 errcode_t retval = 0;
052064b9 473 int read_cnt;
f84894bc 474 int hdlink;
052064b9 475
052064b9
RY
476 if (chdir(source_dir) < 0) {
477 com_err(__func__, errno,
9c891f7e
DW
478 _("while changing working directory to \"%s\""),
479 source_dir);
052064b9
RY
480 return errno;
481 }
482
483 if (!(dh = opendir("."))) {
484 com_err(__func__, errno,
8f8d8a57 485 _("while opening directory \"%s\""), source_dir);
052064b9
RY
486 return errno;
487 }
488
8f8d8a57 489 while ((dent = readdir(dh))) {
9c891f7e
DW
490 if ((!strcmp(dent->d_name, ".")) ||
491 (!strcmp(dent->d_name, "..")))
052064b9 492 continue;
1bad6f46
DW
493 if (lstat(dent->d_name, &st)) {
494 com_err(__func__, errno, _("while lstat \"%s\""),
495 dent->d_name);
496 goto out;
497 }
052064b9
RY
498 name = dent->d_name;
499
f84894bc
RY
500 /* Check for hardlinks */
501 save_inode = 0;
9c891f7e
DW
502 if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) &&
503 st.st_nlink > 1) {
b99888a0 504 hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino);
f84894bc 505 if (hdlink >= 0) {
a3111e80 506 retval = add_link(fs, parent_ino,
b99888a0 507 hdlinks->hdl[hdlink].dst_ino,
9c891f7e 508 name);
f84894bc 509 if (retval) {
9c891f7e
DW
510 com_err(__func__, retval,
511 "while linking %s", name);
1bad6f46 512 goto out;
f84894bc
RY
513 }
514 continue;
515 } else
516 save_inode = 1;
517 }
518
052064b9 519 switch(st.st_mode & S_IFMT) {
9c891f7e
DW
520 case S_IFCHR:
521 case S_IFBLK:
522 case S_IFIFO:
c61e0068 523 case S_IFSOCK:
a3111e80 524 retval = do_mknod_internal(fs, parent_ino, name, &st);
9c891f7e
DW
525 if (retval) {
526 com_err(__func__, retval,
527 _("while creating special file "
528 "\"%s\""), name);
1bad6f46 529 goto out;
9c891f7e
DW
530 }
531 break;
9c891f7e
DW
532 case S_IFLNK:
533 read_cnt = readlink(name, ln_target,
1bad6f46 534 sizeof(ln_target) - 1);
9c891f7e
DW
535 if (read_cnt == -1) {
536 com_err(__func__, errno,
537 _("while trying to readlink \"%s\""),
538 name);
ec3a42b1
DW
539 retval = errno;
540 goto out;
9c891f7e
DW
541 }
542 ln_target[read_cnt] = '\0';
a3111e80
DW
543 retval = do_symlink_internal(fs, parent_ino, name,
544 ln_target, root);
9c891f7e
DW
545 if (retval) {
546 com_err(__func__, retval,
547 _("while writing symlink\"%s\""),
548 name);
1bad6f46 549 goto out;
9c891f7e
DW
550 }
551 break;
552 case S_IFREG:
a3111e80
DW
553 retval = do_write_internal(fs, parent_ino, name, name,
554 root);
9c891f7e
DW
555 if (retval) {
556 com_err(__func__, retval,
557 _("while writing file \"%s\""), name);
1bad6f46 558 goto out;
9c891f7e
DW
559 }
560 break;
561 case S_IFDIR:
a3111e80
DW
562 retval = do_mkdir_internal(fs, parent_ino, name, &st,
563 root);
9c891f7e
DW
564 if (retval) {
565 com_err(__func__, retval,
566 _("while making dir \"%s\""), name);
1bad6f46 567 goto out;
9c891f7e 568 }
a3111e80 569 retval = ext2fs_namei(fs, root, parent_ino,
9c891f7e
DW
570 name, &ino);
571 if (retval) {
572 com_err(name, retval, 0);
1bad6f46 573 goto out;
9c891f7e
DW
574 }
575 /* Populate the dir recursively*/
b99888a0 576 retval = __populate_fs(fs, ino, name, root, hdlinks);
9c891f7e
DW
577 if (retval) {
578 com_err(__func__, retval,
579 _("while adding dir \"%s\""), name);
1bad6f46 580 goto out;
9c891f7e 581 }
a3111e80 582 if (chdir("..")) {
1bad6f46
DW
583 com_err(__func__, errno, _("during cd .."));
584 retval = errno;
585 goto out;
a3111e80 586 }
9c891f7e
DW
587 break;
588 default:
589 com_err(__func__, 0,
590 _("ignoring entry \"%s\""), name);
052064b9 591 }
b6960654 592
a3111e80 593 retval = ext2fs_namei(fs, root, parent_ino, name, &ino);
8f8d8a57 594 if (retval) {
b6960654 595 com_err(name, retval, 0);
1bad6f46 596 goto out;
b6960654
RY
597 }
598
a3111e80 599 retval = set_inode_extra(fs, parent_ino, ino, &st);
8f8d8a57 600 if (retval) {
b6960654
RY
601 com_err(__func__, retval,
602 _("while setting inode for \"%s\""), name);
1bad6f46 603 goto out;
b6960654 604 }
f84894bc
RY
605
606 /* Save the hardlink ino */
607 if (save_inode) {
608 /*
609 * Check whether need more memory, and we don't need
610 * free() since the lifespan will be over after the fs
611 * populated.
612 */
b99888a0
DW
613 if (hdlinks->count == hdlinks->size) {
614 void *p = realloc(hdlinks->hdl,
615 (hdlinks->size + HDLINK_CNT) *
616 sizeof(struct hdlink_s));
617 if (p == NULL) {
618 com_err(name, errno,
619 _("Not enough memory"));
1bad6f46
DW
620 retval = EXT2_ET_NO_MEMORY;
621 goto out;
f84894bc 622 }
b99888a0
DW
623 hdlinks->hdl = p;
624 hdlinks->size += HDLINK_CNT;
f84894bc 625 }
b99888a0
DW
626 hdlinks->hdl[hdlinks->count].src_dev = st.st_dev;
627 hdlinks->hdl[hdlinks->count].src_ino = st.st_ino;
628 hdlinks->hdl[hdlinks->count].dst_ino = ino;
629 hdlinks->count++;
f84894bc 630 }
052064b9 631 }
1bad6f46
DW
632
633out:
052064b9
RY
634 closedir(dh);
635 return retval;
0d4deba2 636}
b99888a0
DW
637
638errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
639 const char *source_dir, ext2_ino_t root)
640{
641 struct hdlinks_s hdlinks;
642 errcode_t retval;
643
644 hdlinks.count = 0;
645 hdlinks.size = HDLINK_CNT;
646 hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s));
647 if (hdlinks.hdl == NULL) {
648 com_err(__func__, errno, "Not enough memory");
649 return errno;
650 }
651
652 retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks);
653
654 free(hdlinks.hdl);
655 return retval;
656}