Allow specifying reserved blocks percentage
[project/make_ext4fs.git] / make_ext4fs.c
index 62a3f1a..edfa25c 100644 (file)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "make_ext4fs.h"
 #include "ext4_utils.h"
 #include "allocate.h"
 #include "contents.h"
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#ifdef USE_MINGW
-
-#include <winsock2.h>
-
-/* These match the Linux definitions of these flags.
-   L_xx is defined to avoid conflicting with the win32 versions.
-*/
-#define L_S_IRUSR 00400
-#define L_S_IWUSR 00200
-#define L_S_IXUSR 00100
-#define S_IRWXU (L_S_IRUSR | L_S_IWUSR | L_S_IXUSR)
-#define S_IRGRP 00040
-#define S_IWGRP 00020
-#define S_IXGRP 00010
-#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
-#define S_IROTH 00004
-#define S_IWOTH 00002
-#define S_IXOTH 00001
-#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0004000
-#define S_ISGID 0002000
-#define S_ISVTX 0001000
-
-#else
-
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-#include <selinux/android.h>
-
-#define O_BINARY 0
-
-#endif
-
 /* TODO: Not implemented:
    Allocating blocks in the same block group as the file inode
    Hash or binary tree directories
-   Special files: sockets, devices, fifos
  */
 
 static int filter_dot(const struct dirent *d)
@@ -79,8 +44,7 @@ static int filter_dot(const struct dirent *d)
        return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
 }
 
-static u32 build_default_directory_structure(const char *dir_path,
-                                            struct selabel_handle *sehnd)
+static u32 build_default_directory_structure(const char *dir_path)
 {
        u32 inode;
        u32 root_inode;
@@ -98,26 +62,9 @@ static u32 build_default_directory_structure(const char *dir_path,
        inode_set_permissions(inode, dentries.mode,
                dentries.uid, dentries.gid, dentries.mtime);
 
-#ifndef USE_MINGW
-       if (sehnd) {
-               char *path = NULL;
-               char *secontext = NULL;
-
-               asprintf(&path, "%slost+found", dir_path);
-               if (selabel_lookup(sehnd, &secontext, path, S_IFDIR) < 0) {
-                       error("cannot lookup security context for %s", path);
-               } else {
-                       inode_set_selinux(inode, secontext);
-                       freecon(secontext);
-               }
-               free(path);
-       }
-#endif
-
        return root_inode;
 }
 
-#ifndef USE_MINGW
 /* Read a local directory and create the same tree in the generated filesystem.
    Calls itself recursively with each directory in the given directory.
    full_path is an absolute or relative path, with a trailing slash, to the
@@ -127,7 +74,7 @@ static u32 build_default_directory_structure(const char *dir_path,
    if the image were mounted at the specified mount point */
 static u32 build_directory_structure(const char *full_path, const char *dir_path,
                u32 dir_inode, fs_config_func_t fs_config_func,
-               struct selabel_handle *sehnd, int verbose, time_t fixed_time)
+               int verbose, time_t fixed_time)
 {
        int entries = 0;
        struct dentry *dentries;
@@ -198,30 +145,17 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
                }
                uint64_t capabilities;
                if (fs_config_func != NULL) {
-#ifdef ANDROID
                        unsigned int mode = 0;
                        unsigned int uid = 0;
                        unsigned int gid = 0;
                        int dir = S_ISDIR(stat.st_mode);
-                       fs_config_func(dentries[i].path, dir, &uid, &gid, &mode, &capabilities);
-                       dentries[i].mode = mode;
-                       dentries[i].uid = uid;
-                       dentries[i].gid = gid;
-                       dentries[i].capabilities = capabilities;
-#else
-                       error("can't set android permissions - built without android support");
-#endif
-               }
-#ifndef USE_MINGW
-               if (sehnd) {
-                       if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) {
-                               error("cannot lookup security context for %s", dentries[i].path);
+                       if (fs_config_func(dentries[i].path, dir, &uid, &gid, &mode, &capabilities)) {
+                               dentries[i].mode = mode;
+                               dentries[i].uid = uid;
+                               dentries[i].gid = gid;
+                               dentries[i].capabilities = capabilities;
                        }
-
-                       if (dentries[i].secon && verbose)
-                               printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon);
                }
-#endif
 
                if (S_ISREG(stat.st_mode)) {
                        dentries[i].file_type = EXT4_FT_REG_FILE;
@@ -263,10 +197,6 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
                dentries[0].file_type = EXT4_FT_DIR;
                dentries[0].uid = 0;
                dentries[0].gid = 0;
-               if (sehnd) {
-                       if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0)
-                               error("cannot lookup security context for %s", dentries[0].path);
-               }
                entries++;
                dirs++;
        }
@@ -288,11 +218,16 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
                        if (ret < 0)
                                critical_error_errno("asprintf");
                        entry_inode = build_directory_structure(subdir_full_path,
-                                       subdir_dir_path, inode, fs_config_func, sehnd, verbose, fixed_time);
+                                       subdir_dir_path, inode, fs_config_func, verbose, fixed_time);
                        free(subdir_full_path);
                        free(subdir_dir_path);
                } else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
                        entry_inode = make_link(dentries[i].link);
+               } else if (dentries[i].file_type == EXT4_FT_CHRDEV ||
+                          dentries[i].file_type == EXT4_FT_BLKDEV ||
+                          dentries[i].file_type == EXT4_FT_SOCK ||
+                          dentries[i].file_type == EXT4_FT_FIFO) {
+                       entry_inode = make_special(dentries[i].full_path);
                } else {
                        error("unknown file type on %s", dentries[i].path);
                        entry_inode = 0;
@@ -305,16 +240,6 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
                if (ret)
                        error("failed to set permissions on %s\n", dentries[i].path);
 
-               /*
-                * It's important to call inode_set_selinux() before
-                * inode_set_capabilities(). Extended attributes need to
-                * be stored sorted order, and we guarantee this by making
-                * the calls in the proper order.
-                * Please see xattr_assert_sane() in contents.c
-                */
-               ret = inode_set_selinux(entry_inode, dentries[i].secon);
-               if (ret)
-                       error("failed to set SELinux context on %s\n", dentries[i].path);
                ret = inode_set_capabilities(entry_inode, dentries[i].capabilities);
                if (ret)
                        error("failed to set capability on %s\n", dentries[i].path);
@@ -323,13 +248,11 @@ static u32 build_directory_structure(const char *full_path, const char *dir_path
                free(dentries[i].full_path);
                free(dentries[i].link);
                free((void *)dentries[i].filename);
-               free(dentries[i].secon);
        }
 
        free(dentries);
        return inode;
 }
-#endif
 
 static u32 compute_block_size()
 {
@@ -388,48 +311,6 @@ static u32 compute_bg_desc_reserve_blocks()
        return bg_desc_reserve_blocks;
 }
 
-void reset_ext4fs_info() {
-       // Reset all the global data structures used by make_ext4fs so it
-       // can be called again.
-       memset(&info, 0, sizeof(info));
-       memset(&aux_info, 0, sizeof(aux_info));
-
-       if (ext4_sparse_file) {
-               sparse_file_destroy(ext4_sparse_file);
-               ext4_sparse_file = NULL;
-       }
-}
-
-int make_ext4fs_sparse_fd(int fd, long long len,
-                               const char *mountpoint, struct selabel_handle *sehnd)
-{
-       reset_ext4fs_info();
-       info.len = len;
-
-       return make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 1, 0, 0, sehnd, 0, -1, NULL);
-}
-
-int make_ext4fs(const char *filename, long long len,
-                               const char *mountpoint, struct selabel_handle *sehnd)
-{
-       int fd;
-       int status;
-
-       reset_ext4fs_info();
-       info.len = len;
-
-       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-       if (fd < 0) {
-               error_errno("open");
-               return EXIT_FAILURE;
-       }
-
-       status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, sehnd, 0, -1, NULL);
-       close(fd);
-
-       return status;
-}
-
 /* return a newly-malloc'd string that is a copy of str.  The new string
    is guaranteed to have a trailing slash.  If absolute is true, the new string
    is also guaranteed to have a leading slash.
@@ -491,28 +372,24 @@ static char *canonicalize_rel_slashes(const char *str)
 }
 
 int make_ext4fs_internal(int fd, const char *_directory,
-                                                const char *_mountpoint, fs_config_func_t fs_config_func, int gzip,
+                                                fs_config_func_t fs_config_func, int gzip,
                                                 int sparse, int crc, int wipe,
-                                                struct selabel_handle *sehnd, int verbose, time_t fixed_time,
+                                                int verbose, time_t fixed_time,
                                                 FILE* block_list_file)
 {
        u32 root_inode_num;
        u16 root_mode;
-       char *mountpoint;
        char *directory = NULL;
 
        if (setjmp(setjmp_env))
                return EXIT_FAILURE; /* Handle a call to longjmp() */
 
-       if (_mountpoint == NULL) {
-               mountpoint = strdup("");
-       } else {
-               mountpoint = canonicalize_abs_slashes(_mountpoint);
+       if (_directory == NULL) {
+               fprintf(stderr, "Need a source directory\n");
+               return EXIT_FAILURE;
        }
 
-       if (_directory) {
-               directory = canonicalize_rel_slashes(_directory);
-       }
+       directory = canonicalize_rel_slashes(_directory);
 
        if (info.len <= 0)
                info.len = get_file_size(fd);
@@ -579,6 +456,7 @@ int make_ext4fs_internal(int fd, const char *_directory,
 
        printf("    Blocks: %"PRIu64"\n", aux_info.len_blocks);
        printf("    Block groups: %d\n", aux_info.groups);
+       printf("    Reserved blocks: %"PRIu64"\n",  (aux_info.len_blocks / 100) * info.reserve_pcnt);
        printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
 
        ext4_sparse_file = sparse_file_new(info.block_size, info.len);
@@ -596,49 +474,22 @@ int make_ext4fs_internal(int fd, const char *_directory,
        if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
                ext4_create_resize_inode();
 
-#ifdef USE_MINGW
-       // Windows needs only 'create an empty fs image' functionality
-       assert(!directory);
-       root_inode_num = build_default_directory_structure(mountpoint, sehnd);
-#else
-       if (directory)
-               root_inode_num = build_directory_structure(directory, mountpoint, 0,
-                       fs_config_func, sehnd, verbose, fixed_time);
-       else
-               root_inode_num = build_default_directory_structure(mountpoint, sehnd);
-#endif
+       root_inode_num = build_directory_structure(directory, "", 0,
+               fs_config_func, verbose, fixed_time);
 
        root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
        inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
 
-#ifndef USE_MINGW
-       if (sehnd) {
-               char *secontext = NULL;
-
-               if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) {
-                       error("cannot lookup security context for %s", mountpoint);
-               }
-               if (secontext) {
-                       if (verbose) {
-                               printf("Labeling %s as %s\n", mountpoint, secontext);
-                       }
-                       inode_set_selinux(root_inode_num, secontext);
-               }
-               freecon(secontext);
-       }
-#endif
-
        ext4_update_free();
 
        ext4_queue_sb();
 
        if (block_list_file) {
-               size_t dirlen = directory ? strlen(directory) : 0;
+               size_t dirlen = strlen(directory);
                struct block_allocation* p = get_saved_allocation_chain();
                while (p) {
-                       if (directory && strncmp(p->filename, directory, dirlen) == 0) {
-                               // substitute mountpoint for the leading directory in the filename, in the output file
-                               fprintf(block_list_file, "%s%s", mountpoint, p->filename + dirlen);
+                       if (strncmp(p->filename, directory, dirlen) == 0) {
+                               fprintf(block_list_file, "%s", p->filename + dirlen);
                        } else {
                                fprintf(block_list_file, "%s", p->filename);
                        }
@@ -664,7 +515,6 @@ int make_ext4fs_internal(int fd, const char *_directory,
        sparse_file_destroy(ext4_sparse_file);
        ext4_sparse_file = NULL;
 
-       free(mountpoint);
        free(directory);
 
        return 0;