]> wimlib.net Git - wimlib/blobdiff - src/unix_capture.c
unix_capture.c: mark regular files as sparse when appropriate
[wimlib] / src / unix_capture.c
index f7dd5074e7df7208d4cfc4d8d05a34bfb5e7fd39..1c207cb80eeab1d12d36775e9e901519849a9b2f 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
  *
  * This file is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the Free
 #include <unistd.h>
 
 #include "wimlib/blob_table.h"
-#include "wimlib/capture.h"
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/reparse.h"
+#include "wimlib/scan.h"
 #include "wimlib/timestamp.h"
 #include "wimlib/unix_data.h"
 
@@ -100,13 +100,21 @@ my_fdopendir(int *dirfd_p)
 #endif
 
 static int
-unix_scan_regular_file(const char *path, u64 size, struct wim_inode *inode,
+unix_scan_regular_file(const char *path, u64 blocks, u64 size,
+                      struct wim_inode *inode,
                       struct list_head *unhashed_blobs)
 {
        struct blob_descriptor *blob = NULL;
        struct wim_inode_stream *strm;
 
-       inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
+       /*
+        * Set FILE_ATTRIBUTE_SPARSE_FILE if the file uses less disk space than
+        * expected given its size.
+        */
+       if (blocks < DIV_ROUND_UP(size, 512))
+               inode->i_attributes = FILE_ATTRIBUTE_SPARSE_FILE;
+       else
+               inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
 
        if (size) {
                blob = new_blob_descriptor();
@@ -136,13 +144,13 @@ static int
 unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret,
                                 char *path, size_t path_len,
                                 int dirfd, const char *relpath,
-                                struct capture_params *params);
+                                struct scan_params *params);
 
 static int
 unix_scan_directory(struct wim_dentry *dir_dentry,
                    char *full_path, size_t full_path_len,
                    int parent_dirfd, const char *dir_relpath,
-                   struct capture_params *params)
+                   struct scan_params *params)
 {
 
        int dirfd;
@@ -180,13 +188,12 @@ unix_scan_directory(struct wim_dentry *dir_dentry,
                        break;
                }
 
-               if (entry->d_name[0] == '.' &&
-                   (entry->d_name[1] == '\0' ||
-                    (entry->d_name[1] == '.' && entry->d_name[2] == '\0')))
+               name_len = strlen(entry->d_name);
+
+               if (should_ignore_filename(entry->d_name, name_len))
                        continue;
 
                full_path[full_path_len] = '/';
-               name_len = strlen(entry->d_name);
                memcpy(&full_path[full_path_len + 1], entry->d_name, name_len + 1);
                ret = unix_build_dentry_tree_recursive(&child,
                                                       full_path,
@@ -197,8 +204,7 @@ unix_scan_directory(struct wim_dentry *dir_dentry,
                full_path[full_path_len] = '\0';
                if (ret)
                        break;
-               if (child)
-                       dentry_add_child(dir_dentry, child);
+               attach_scanned_tree(dir_dentry, child, params->blob_table);
        }
        closedir(dir);
        return ret;
@@ -279,7 +285,7 @@ unix_relativize_link_target(char *target, u64 ino, u64 dev)
 
 static noinline_for_stack int
 unix_scan_symlink(const char *full_path, int dirfd, const char *relpath,
-                 struct wim_inode *inode, struct capture_params *params)
+                 struct wim_inode *inode, struct scan_params *params)
 {
        char orig_target[REPARSE_POINT_MAX_SIZE];
        char *target = orig_target;
@@ -315,15 +321,20 @@ unix_scan_symlink(const char *full_path, int dirfd, const char *relpath,
                        inode->i_rp_flags &= ~WIM_RP_FLAG_NOT_FIXED;
                        status = WIMLIB_SCAN_DENTRY_FIXED_SYMLINK;
                }
-               ret = do_capture_progress(params, status, NULL);
+               ret = do_scan_progress(params, status, NULL);
                if (ret)
                        return ret;
        }
 
        /* Translate the UNIX symlink target into a Windows reparse point.  */
        ret = wim_inode_set_symlink(inode, target, params->blob_table);
-       if (ret)
+       if (unlikely(ret)) {
+               if (ret == WIMLIB_ERR_INVALID_UTF8_STRING) {
+                       ERROR("\"%s\": target of symbolic link is not valid "
+                             "UTF-8.  This is not supported.", full_path);
+               }
                return ret;
+       }
 
        /* On Windows, a reparse point can be set on both directory and
         * non-directory files.  Usually, a link that is intended to point to a
@@ -340,7 +351,7 @@ static int
 unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret,
                                 char *full_path, size_t full_path_len,
                                 int dirfd, const char *relpath,
-                                struct capture_params *params)
+                                struct scan_params *params)
 {
        struct wim_dentry *tree = NULL;
        struct wim_inode *inode = NULL;
@@ -382,18 +393,22 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret,
                                goto out;
                        }
                        params->progress.scan.cur_path = full_path;
-                       ret = do_capture_progress(params,
-                                                 WIMLIB_SCAN_DENTRY_UNSUPPORTED,
-                                                 NULL);
+                       ret = do_scan_progress(params,
+                                              WIMLIB_SCAN_DENTRY_UNSUPPORTED,
+                                              NULL);
                        goto out;
                }
        }
 
        ret = inode_table_new_dentry(params->inode_table, relpath,
-                                    stbuf.st_ino, stbuf.st_dev,
-                                    S_ISDIR(stbuf.st_mode), &tree);
-       if (ret)
+                                    stbuf.st_ino, stbuf.st_dev, false, &tree);
+       if (unlikely(ret)) {
+               if (ret == WIMLIB_ERR_INVALID_UTF8_STRING) {
+                       ERROR("\"%s\": filename is not valid UTF-8.  "
+                             "This is not supported.", full_path);
+               }
                goto out;
+       }
 
        inode = tree->d_inode;
 
@@ -430,8 +445,9 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret,
        }
 
        if (S_ISREG(stbuf.st_mode)) {
-               ret = unix_scan_regular_file(full_path, stbuf.st_size,
-                                            inode, params->unhashed_blobs);
+               ret = unix_scan_regular_file(full_path, stbuf.st_blocks,
+                                            stbuf.st_size, inode,
+                                            params->unhashed_blobs);
        } else if (S_ISDIR(stbuf.st_mode)) {
                ret = unix_scan_directory(tree, full_path, full_path_len,
                                          dirfd, relpath, params);
@@ -446,14 +462,14 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret,
 out_progress:
        params->progress.scan.cur_path = full_path;
        if (likely(tree))
-               ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_OK, inode);
+               ret = do_scan_progress(params, WIMLIB_SCAN_DENTRY_OK, inode);
        else
-               ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL);
+               ret = do_scan_progress(params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL);
 out:
        if (unlikely(ret)) {
                free_dentry_tree(tree, params->blob_table);
                tree = NULL;
-               ret = report_capture_error(params, ret, full_path);
+               ret = report_scan_error(params, ret, full_path);
        }
        *tree_ret = tree;
        return ret;
@@ -464,13 +480,12 @@ out:
  *     Builds a tree of WIM dentries from an on-disk directory tree (UNIX
  *     version; no NTFS-specific data is captured).
  *
- * @root_ret:   Place to return a pointer to the root of the dentry tree.  Only
- *             modified if successful.  Set to NULL if the file or directory was
- *             excluded from capture.
+ * @root_ret:   Place to return a pointer to the root of the dentry tree.  Set
+ *             to NULL if the file or directory was excluded from capture.
  *
  * @root_disk_path:  The path to the root of the directory tree on disk.
  *
- * @params:     See doc for `struct capture_params'.
+ * @params:     See doc for `struct scan_params'.
  *
  * @return:    0 on success, nonzero on failure.  It is a failure if any of
  *             the files cannot be `stat'ed, or if any of the needed
@@ -481,8 +496,7 @@ out:
  */
 int
 unix_build_dentry_tree(struct wim_dentry **root_ret,
-                      const char *root_disk_path,
-                      struct capture_params *params)
+                      const char *root_disk_path, struct scan_params *params)
 {
        size_t path_len;
        size_t path_bufsz;