]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - misc/create_inode.c
create_inode: move debugfs internal state back to debugfs
[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
RY
24/* For saving the hard links */
25int hdlink_cnt = HDLINK_CNT;
26
27/* Link an inode number to a directory */
a3111e80
DW
28static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino,
29 ext2_ino_t ino, const char *name)
f84894bc
RY
30{
31 struct ext2_inode inode;
32 errcode_t retval;
33
a3111e80 34 retval = ext2fs_read_inode(fs, ino, &inode);
f84894bc
RY
35 if (retval) {
36 com_err(__func__, retval, "while reading inode %u", ino);
37 return retval;
38 }
39
a3111e80 40 retval = ext2fs_link(fs, parent_ino, name, ino, inode.i_flags);
f84894bc 41 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 42 retval = ext2fs_expand_dir(fs, parent_ino);
f84894bc
RY
43 if (retval) {
44 com_err(__func__, retval, "while expanding directory");
45 return retval;
46 }
a3111e80 47 retval = ext2fs_link(fs, parent_ino, name, ino, inode.i_flags);
f84894bc
RY
48 }
49 if (retval) {
50 com_err(__func__, retval, "while linking %s", name);
51 return retval;
52 }
53
54 inode.i_links_count++;
55
a3111e80 56 retval = ext2fs_write_inode(fs, ino, &inode);
f84894bc
RY
57 if (retval)
58 com_err(__func__, retval, "while writing inode %u", ino);
59
60 return retval;
61}
62
b6960654
RY
63/* Fill the uid, gid, mode and time for the inode */
64static void fill_inode(struct ext2_inode *inode, struct stat *st)
65{
66 if (st != NULL) {
67 inode->i_uid = st->st_uid;
68 inode->i_gid = st->st_gid;
69 inode->i_mode |= st->st_mode;
70 inode->i_atime = st->st_atime;
71 inode->i_mtime = st->st_mtime;
72 inode->i_ctime = st->st_ctime;
73 }
74}
75
76/* Set the uid, gid, mode and time for the inode */
a3111e80
DW
77static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t cwd,
78 ext2_ino_t ino, struct stat *st)
b6960654
RY
79{
80 errcode_t retval;
81 struct ext2_inode inode;
82
a3111e80 83 retval = ext2fs_read_inode(fs, ino, &inode);
b6960654
RY
84 if (retval) {
85 com_err(__func__, retval, "while reading inode %u", ino);
86 return retval;
87 }
88
89 fill_inode(&inode, st);
90
a3111e80 91 retval = ext2fs_write_inode(fs, ino, &inode);
b6960654
RY
92 if (retval) {
93 com_err(__func__, retval, "while writing inode %u", ino);
94 return retval;
95 }
96}
97
0d4deba2 98/* Make a special file which is block, character and fifo */
a3111e80
DW
99errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
100 struct stat *st)
0d4deba2 101{
b2346118
RY
102 ext2_ino_t ino;
103 errcode_t retval;
104 struct ext2_inode inode;
105 unsigned long major, minor, mode;
106 int filetype;
107
108 switch(st->st_mode & S_IFMT) {
9c891f7e
DW
109 case S_IFCHR:
110 mode = LINUX_S_IFCHR;
111 filetype = EXT2_FT_CHRDEV;
112 break;
113 case S_IFBLK:
114 mode = LINUX_S_IFBLK;
115 filetype = EXT2_FT_BLKDEV;
116 break;
117 case S_IFIFO:
118 mode = LINUX_S_IFIFO;
119 filetype = EXT2_FT_FIFO;
120 break;
b2346118
RY
121 }
122
a3111e80 123 if (!(fs->flags & EXT2_FLAG_RW)) {
b2346118
RY
124 com_err(__func__, 0, "Filesystem opened read/only");
125 return -1;
126 }
a3111e80 127 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino);
b2346118
RY
128 if (retval) {
129 com_err(__func__, retval, 0);
130 return retval;
131 }
132
133#ifdef DEBUGFS
134 printf("Allocated inode: %u\n", ino);
135#endif
a3111e80 136 retval = ext2fs_link(fs, cwd, name, ino, filetype);
b2346118 137 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 138 retval = ext2fs_expand_dir(fs, cwd);
b2346118
RY
139 if (retval) {
140 com_err(__func__, retval, "while expanding directory");
141 return retval;
142 }
a3111e80 143 retval = ext2fs_link(fs, cwd, name, ino, filetype);
b2346118
RY
144 }
145 if (retval) {
146 com_err(name, retval, 0);
147 return -1;
148 }
a3111e80 149 if (ext2fs_test_inode_bitmap2(fs->inode_map, ino))
b2346118 150 com_err(__func__, 0, "Warning: inode already set");
a3111e80 151 ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
b2346118
RY
152 memset(&inode, 0, sizeof(inode));
153 inode.i_mode = mode;
154 inode.i_atime = inode.i_ctime = inode.i_mtime =
a3111e80 155 fs->now ? fs->now : time(0);
b2346118
RY
156
157 major = major(st->st_rdev);
158 minor = minor(st->st_rdev);
159
160 if ((major < 256) && (minor < 256)) {
161 inode.i_block[0] = major * 256 + minor;
162 inode.i_block[1] = 0;
163 } else {
164 inode.i_block[0] = 0;
9c891f7e
DW
165 inode.i_block[1] = (minor & 0xff) | (major << 8) |
166 ((minor & ~0xff) << 12);
b2346118
RY
167 }
168 inode.i_links_count = 1;
169
a3111e80 170 retval = ext2fs_write_new_inode(fs, ino, &inode);
b2346118
RY
171 if (retval)
172 com_err(__func__, retval, "while creating inode %u", ino);
173
174 return retval;
0d4deba2
RY
175}
176
177/* Make a symlink name -> target */
a3111e80
DW
178errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
179 char *target, ext2_ino_t root)
0d4deba2 180{
b25ddc5e
RY
181 char *cp;
182 ext2_ino_t parent_ino;
183 errcode_t retval;
184 struct ext2_inode inode;
185 struct stat st;
186
187 cp = strrchr(name, '/');
188 if (cp) {
189 *cp = 0;
a3111e80 190 retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
8f8d8a57 191 if (retval) {
b25ddc5e
RY
192 com_err(name, retval, 0);
193 return retval;
194 }
195 name = cp+1;
196 } else
197 parent_ino = cwd;
198
199try_again:
a3111e80 200 retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
b25ddc5e 201 if (retval == EXT2_ET_DIR_NO_SPACE) {
a3111e80 202 retval = ext2fs_expand_dir(fs, parent_ino);
b25ddc5e 203 if (retval) {
9c891f7e
DW
204 com_err("do_symlink_internal", retval,
205 "while expanding directory");
b25ddc5e
RY
206 return retval;
207 }
208 goto try_again;
209 }
210 if (retval) {
211 com_err("ext2fs_symlink", retval, 0);
212 return retval;
213 }
214
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 }
249 if (retval) {
250 com_err("ext2fs_mkdir", retval, 0);
251 return retval;
252 }
0d4deba2
RY
253}
254
a3111e80
DW
255static errcode_t copy_file(ext2_filsys fs, int fd, ext2_ino_t newfile,
256 int bufsize, int make_holes)
ce600dc4
RY
257{
258 ext2_file_t e2_file;
259 errcode_t retval;
260 int got;
261 unsigned int written;
262 char *buf;
263 char *ptr;
264 char *zero_buf;
265 int cmp;
266
a3111e80 267 retval = ext2fs_file_open(fs, newfile,
ce600dc4
RY
268 EXT2_FILE_WRITE, &e2_file);
269 if (retval)
270 return retval;
271
272 retval = ext2fs_get_mem(bufsize, &buf);
273 if (retval) {
274 com_err("copy_file", retval, "can't allocate buffer\n");
275 return retval;
276 }
277
278 /* This is used for checking whether the whole block is zero */
279 retval = ext2fs_get_memzero(bufsize, &zero_buf);
280 if (retval) {
281 com_err("copy_file", retval, "can't allocate buffer\n");
282 ext2fs_free_mem(&buf);
283 return retval;
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 }
322 ext2fs_free_mem(&buf);
323 ext2fs_free_mem(&zero_buf);
324 retval = ext2fs_file_close(e2_file);
325 return retval;
326
327fail:
328 ext2fs_free_mem(&buf);
329 ext2fs_free_mem(&zero_buf);
330 (void) ext2fs_file_close(e2_file);
331 return retval;
332}
333
a3111e80 334static int is_hardlink(ext2_ino_t ino)
f84894bc
RY
335{
336 int i;
337
338 for(i = 0; i < hdlinks.count; i++) {
339 if(hdlinks.hdl[i].src_ino == ino)
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 */
a3111e80
DW
460errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
461 const char *source_dir, ext2_ino_t root)
0d4deba2 462{
052064b9
RY
463 const char *name;
464 DIR *dh;
465 struct dirent *dent;
466 struct stat st;
467 char ln_target[PATH_MAX];
f84894bc 468 unsigned int save_inode;
052064b9
RY
469 ext2_ino_t ino;
470 errcode_t retval;
471 int read_cnt;
f84894bc 472 int hdlink;
052064b9 473
052064b9
RY
474 if (chdir(source_dir) < 0) {
475 com_err(__func__, errno,
9c891f7e
DW
476 _("while changing working directory to \"%s\""),
477 source_dir);
052064b9
RY
478 return errno;
479 }
480
481 if (!(dh = opendir("."))) {
482 com_err(__func__, errno,
8f8d8a57 483 _("while opening directory \"%s\""), source_dir);
052064b9
RY
484 return errno;
485 }
486
8f8d8a57 487 while ((dent = readdir(dh))) {
9c891f7e
DW
488 if ((!strcmp(dent->d_name, ".")) ||
489 (!strcmp(dent->d_name, "..")))
052064b9
RY
490 continue;
491 lstat(dent->d_name, &st);
492 name = dent->d_name;
493
f84894bc
RY
494 /* Check for hardlinks */
495 save_inode = 0;
9c891f7e
DW
496 if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) &&
497 st.st_nlink > 1) {
f84894bc
RY
498 hdlink = is_hardlink(st.st_ino);
499 if (hdlink >= 0) {
a3111e80 500 retval = add_link(fs, parent_ino,
9c891f7e
DW
501 hdlinks.hdl[hdlink].dst_ino,
502 name);
f84894bc 503 if (retval) {
9c891f7e
DW
504 com_err(__func__, retval,
505 "while linking %s", name);
f84894bc
RY
506 return retval;
507 }
508 continue;
509 } else
510 save_inode = 1;
511 }
512
052064b9 513 switch(st.st_mode & S_IFMT) {
9c891f7e
DW
514 case S_IFCHR:
515 case S_IFBLK:
516 case S_IFIFO:
a3111e80 517 retval = do_mknod_internal(fs, parent_ino, name, &st);
9c891f7e
DW
518 if (retval) {
519 com_err(__func__, retval,
520 _("while creating special file "
521 "\"%s\""), name);
522 return retval;
523 }
524 break;
525 case S_IFSOCK:
526 /* FIXME: there is no make socket function atm. */
527 com_err(__func__, 0,
528 _("ignoring socket file \"%s\""), name);
529 continue;
530 case S_IFLNK:
531 read_cnt = readlink(name, ln_target,
532 sizeof(ln_target));
533 if (read_cnt == -1) {
534 com_err(__func__, errno,
535 _("while trying to readlink \"%s\""),
536 name);
537 return errno;
538 }
539 ln_target[read_cnt] = '\0';
a3111e80
DW
540 retval = do_symlink_internal(fs, parent_ino, name,
541 ln_target, root);
9c891f7e
DW
542 if (retval) {
543 com_err(__func__, retval,
544 _("while writing symlink\"%s\""),
545 name);
546 return retval;
547 }
548 break;
549 case S_IFREG:
a3111e80
DW
550 retval = do_write_internal(fs, parent_ino, name, name,
551 root);
9c891f7e
DW
552 if (retval) {
553 com_err(__func__, retval,
554 _("while writing file \"%s\""), name);
555 return retval;
556 }
557 break;
558 case S_IFDIR:
a3111e80
DW
559 retval = do_mkdir_internal(fs, parent_ino, name, &st,
560 root);
9c891f7e
DW
561 if (retval) {
562 com_err(__func__, retval,
563 _("while making dir \"%s\""), name);
564 return retval;
565 }
a3111e80 566 retval = ext2fs_namei(fs, root, parent_ino,
9c891f7e
DW
567 name, &ino);
568 if (retval) {
569 com_err(name, retval, 0);
052064b9 570 return retval;
9c891f7e
DW
571 }
572 /* Populate the dir recursively*/
a3111e80 573 retval = populate_fs(fs, ino, name, root);
9c891f7e
DW
574 if (retval) {
575 com_err(__func__, retval,
576 _("while adding dir \"%s\""), name);
577 return retval;
578 }
a3111e80
DW
579 if (chdir("..")) {
580 com_err(__func__, errno,
581 _("during cd .."));
582 return errno;
583 }
9c891f7e
DW
584 break;
585 default:
586 com_err(__func__, 0,
587 _("ignoring entry \"%s\""), name);
052064b9 588 }
b6960654 589
a3111e80 590 retval = ext2fs_namei(fs, root, parent_ino, name, &ino);
8f8d8a57 591 if (retval) {
b6960654
RY
592 com_err(name, retval, 0);
593 return retval;
594 }
595
a3111e80 596 retval = set_inode_extra(fs, parent_ino, ino, &st);
8f8d8a57 597 if (retval) {
b6960654
RY
598 com_err(__func__, retval,
599 _("while setting inode for \"%s\""), name);
600 return retval;
601 }
f84894bc
RY
602
603 /* Save the hardlink ino */
604 if (save_inode) {
605 /*
606 * Check whether need more memory, and we don't need
607 * free() since the lifespan will be over after the fs
608 * populated.
609 */
610 if (hdlinks.count == hdlink_cnt) {
611 if ((hdlinks.hdl = realloc (hdlinks.hdl,
612 (hdlink_cnt + HDLINK_CNT) *
613 sizeof (struct hdlink_s))) == NULL) {
614 com_err(name, errno, "Not enough memory");
615 return errno;
616 }
617 hdlink_cnt += HDLINK_CNT;
618 }
619 hdlinks.hdl[hdlinks.count].src_ino = st.st_ino;
620 hdlinks.hdl[hdlinks.count].dst_ino = ino;
621 hdlinks.count++;
622 }
052064b9
RY
623 }
624 closedir(dh);
625 return retval;
0d4deba2 626}