X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=helper%2Fext2.c;h=23958710bdac5cf81bd0c2628be7aad664710c5a;hb=9e7f9f6782bd619a893850c4ab9d14e7176f6e44;hp=a27fb47e744c45f80e0de33b8de9041ebf16f27e;hpb=0f89ba0654de234429042ffcc91c8a0de94ec98b;p=febootstrap.git diff --git a/helper/ext2.c b/helper/ext2.c index a27fb47..2395871 100644 --- a/helper/ext2.c +++ b/helper/ext2.c @@ -1,5 +1,5 @@ /* febootstrap-supermin-helper reimplementation in C. - * Copyright (C) 2009-2010 Red Hat Inc. + * Copyright (C) 2009-2011 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,13 +43,13 @@ ext2_filsys fs; * * The downside of allocating a very large initial disk is that the * fixed overhead of ext2 is larger (since ext2 calculates it based on - * the size of the disk). For a 1GB disk the overhead is - * approximately 16MB. + * the size of the disk). For a 4GB disk the overhead is + * approximately 66MB. * * In future, make this configurable, or determine it from the input * files (XXX). */ -#define APPLIANCE_SIZE (1024*1024*1024) +#define APPLIANCE_SIZE ((off_t)4*1024*1024*1024) static void ext2_start (const char *hostcpu, const char *appliance, @@ -65,7 +65,7 @@ ext2_start (const char *hostcpu, const char *appliance, if (fd == -1) error (EXIT_FAILURE, errno, "open: %s", appliance); - if (lseek (fd, APPLIANCE_SIZE - 1, SEEK_SET) == -1) + if (lseek (fd, APPLIANCE_SIZE - 1, SEEK_SET) == (off_t) -1) error (EXIT_FAILURE, errno, "lseek"); char c = 0; @@ -135,10 +135,20 @@ ext2_mkdir (ext2_ino_t dir_ino, const char *dirname, const char *basename, if (err != 0) error (EXIT_FAILURE, 0, "ext2fs_new_inode: %s", error_message (err)); + try_again: err = ext2fs_mkdir (fs, dir_ino, ino, basename); - if (err != 0) - error (EXIT_FAILURE, 0, "ext2fs_mkdir: %s/%s: %s", - dirname, basename, error_message (err)); + if (err != 0) { + /* See: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=217892 */ + if (err == EXT2_ET_DIR_NO_SPACE) { + err = ext2fs_expand_dir (fs, dir_ino); + if (err) + error (EXIT_FAILURE, 0, "ext2fs_expand_dir: %s/%s: %s", + dirname, basename, error_message (err)); + goto try_again; + } else + error (EXIT_FAILURE, 0, "ext2fs_mkdir: %s/%s: %s", + dirname, basename, error_message (err)); + } /* Copy the final permissions, UID etc. to the inode. */ struct ext2_inode inode; @@ -196,13 +206,15 @@ ext2_empty_inode (ext2_ino_t dir_ino, const char *dirname, const char *basename, /* You must create the file first with ext2_empty_inode. */ void -ext2_write_file (ext2_ino_t ino, const char *buf, size_t size) +ext2_write_file (ext2_ino_t ino, const char *buf, size_t size, + const char *orig_filename) { errcode_t err; ext2_file_t file; err = ext2fs_file_open2 (fs, ino, NULL, EXT2_FILE_WRITE, &file); if (err != 0) - error (EXIT_FAILURE, 0, "ext2fs_file_open2: %s", error_message (err)); + error (EXIT_FAILURE, 0, "ext2fs_file_open2: %s: %s", + orig_filename, error_message (err)); /* ext2fs_file_write cannot deal with partial writes. You have * to write the entire file in a single call. @@ -210,28 +222,37 @@ ext2_write_file (ext2_ino_t ino, const char *buf, size_t size) unsigned int written; err = ext2fs_file_write (file, buf, size, &written); if (err != 0) - error (EXIT_FAILURE, 0, "ext2fs_file_write: %s", error_message (err)); + error (EXIT_FAILURE, 0, "ext2fs_file_write: %s: %s\n" + "Block allocation failures can happen here for several reasons:\n" + " - /lib/modules contains modules with debug that makes the modules very large\n" + " - a file listed in 'hostfiles' is unexpectedly very large\n" + " - too many packages added to the supermin appliance", + orig_filename, error_message (err)); if ((size_t) written != size) error (EXIT_FAILURE, 0, - "ext2fs_file_write: size = %zu != written = %u\n", - size, written); + "ext2fs_file_write: %s: size = %zu != written = %u\n", + orig_filename, size, written); err = ext2fs_file_flush (file); if (err != 0) - error (EXIT_FAILURE, 0, "ext2fs_file_flush: %s", error_message (err)); + error (EXIT_FAILURE, 0, "ext2fs_file_flush: %s: %s", + orig_filename, error_message (err)); err = ext2fs_file_close (file); if (err != 0) - error (EXIT_FAILURE, 0, "ext2fs_file_close: %s", error_message (err)); + error (EXIT_FAILURE, 0, "ext2fs_file_close: %s: %s", + orig_filename, error_message (err)); /* Update the true size in the inode. */ struct ext2_inode inode; err = ext2fs_read_inode (fs, ino, &inode); if (err != 0) - error (EXIT_FAILURE, 0, "ext2fs_read_inode: %s", error_message (err)); + error (EXIT_FAILURE, 0, "ext2fs_read_inode: %s: %s", + orig_filename, error_message (err)); inode.i_size = size; err = ext2fs_write_inode (fs, ino, &inode); if (err != 0) - error (EXIT_FAILURE, 0, "ext2fs_write_inode: %s", error_message (err)); + error (EXIT_FAILURE, 0, "ext2fs_write_inode: %s: %s", + orig_filename, error_message (err)); } /* This is just a wrapper around ext2fs_link which calls @@ -304,9 +325,19 @@ ext2_clean_path (ext2_ino_t dir_ino, if (err != 0) error (EXIT_FAILURE, 0, "ext2fs_write_inode: %s", error_message (err)); - if (ext2fs_inode_has_valid_blocks (&inode)) - ext2fs_block_iterate (fs, ino, BLOCK_FLAG_READ_ONLY, NULL, + if (ext2fs_inode_has_valid_blocks (&inode)) { + int flags = 0; + /* From the docs: "BLOCK_FLAG_READ_ONLY is a promise by the + * caller that it will not modify returned block number." + * RHEL 5 does not have this flag, so just omit it if it is + * not defined. + */ +#ifdef BLOCK_FLAG_READ_ONLY + flags |= BLOCK_FLAG_READ_ONLY; +#endif + ext2fs_block_iterate (fs, ino, flags, NULL, release_block, NULL); + } ext2fs_inode_alloc_stats2 (fs, ino, -1, isdir); } @@ -382,6 +413,20 @@ ext2_file_stat (const char *orig_filename, const struct stat *statbuf) dirname = strndup (orig_filename, p-orig_filename); basename = p+1; + /* If the parent directory is a symlink to another directory, then + * we want to look up the target directory. (RHBZ#698089). + */ + struct stat stat1, stat2; + if (lstat (dirname, &stat1) == 0 && S_ISLNK (stat1.st_mode) && + stat (dirname, &stat2) == 0 && S_ISDIR (stat2.st_mode)) { + char *new_dirname = malloc (PATH_MAX+1); + ssize_t r = readlink (dirname, new_dirname, PATH_MAX+1); + if (r == -1) + error (EXIT_FAILURE, errno, "readlink: %s", orig_filename); + new_dirname[r] = '\0'; + dirname = new_dirname; + } + /* Look up the parent directory. */ err = ext2fs_namei (fs, EXT2_ROOT_INO, EXT2_ROOT_INO, dirname, &dir_ino); if (err != 0) @@ -404,7 +449,7 @@ ext2_file_stat (const char *orig_filename, const struct stat *statbuf) if (statbuf->st_size > 0) { char *buf = read_whole_file (orig_filename, statbuf->st_size); - ext2_write_file (ino, buf, statbuf->st_size); + ext2_write_file (ino, buf, statbuf->st_size, orig_filename); free (buf); } } @@ -420,7 +465,7 @@ ext2_file_stat (const char *orig_filename, const struct stat *statbuf) ssize_t r = readlink (orig_filename, buf, sizeof buf); if (r == -1) error (EXIT_FAILURE, errno, "readlink: %s", orig_filename); - ext2_write_file (ino, buf, r); + ext2_write_file (ino, buf, r, orig_filename); } /* Create directory. */ else if (S_ISDIR (statbuf->st_mode))