]> wimlib.net Git - wimlib/blobdiff - src/capture_common.c
Report every link in scan progress
[wimlib] / src / capture_common.c
index e088afcbd0cddcc5502bc15045df9a2a00dfb4dc..8279497113280b9a82e53882ceee0d08ce9a802a 100644 (file)
@@ -67,20 +67,26 @@ do_capture_progress(struct capture_params *params, int status,
                break;
        }
        params->progress.scan.status = status;
                break;
        }
        params->progress.scan.status = status;
-       if (status == WIMLIB_SCAN_DENTRY_OK && inode->i_nlink == 1) {
-
-               /* Successful scan, and visiting inode for the first time  */
-
-               /* Tally size of all streams.  */
-               for (unsigned i = 0; i < inode->i_num_streams; i++) {
-                       const struct blob_descriptor *blob =
-                               stream_blob_resolved(&inode->i_streams[i]);
-                       if (blob)
-                               params->progress.scan.num_bytes_scanned += blob->size;
+       if (status == WIMLIB_SCAN_DENTRY_OK) {
+
+               /* The first time the inode is seen, tally all its streams.  */
+               if (inode->i_nlink == 1) {
+                       for (unsigned i = 0; i < inode->i_num_streams; i++) {
+                               const struct blob_descriptor *blob =
+                                       stream_blob_resolved(&inode->i_streams[i]);
+                               if (blob)
+                                       params->progress.scan.num_bytes_scanned += blob->size;
+                       }
                }
 
                }
 
-               /* Tally the file itself.  */
-               if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
+               /* Tally the file itself, counting every hard link.  It's
+                * debatable whether every link should be counted, but counting
+                * every link makes the statistics consistent with the ones
+                * placed in the FILECOUNT and DIRCOUNT elements of the WIM
+                * file's XML document.  It also avoids possible user confusion
+                * if the number of files reported were to be lower than that
+                * displayed by some other software such as file browsers.  */
+               if (inode_is_directory(inode))
                        params->progress.scan.num_dirs_scanned++;
                else
                        params->progress.scan.num_nondirs_scanned++;
                        params->progress.scan.num_dirs_scanned++;
                else
                        params->progress.scan.num_nondirs_scanned++;
@@ -135,7 +141,7 @@ mangle_pat(tchar *pat, const tchar *path, unsigned long line_no)
         * Note: we expect that this function produces patterns that can be used
         * for both filesystem paths and WIM paths, so the desired path
         * separators must be the same.  */
         * Note: we expect that this function produces patterns that can be used
         * for both filesystem paths and WIM paths, so the desired path
         * separators must be the same.  */
-       BUILD_BUG_ON(OS_PREFERRED_PATH_SEPARATOR != WIM_PATH_SEPARATOR);
+       STATIC_ASSERT(OS_PREFERRED_PATH_SEPARATOR == WIM_PATH_SEPARATOR);
        do_canonicalize_path(pat, pat);
 
        /* Relative patterns can only match file names, so they must be
        do_canonicalize_path(pat, pat);
 
        /* Relative patterns can only match file names, so they must be
@@ -285,30 +291,19 @@ try_exclude(const tchar *full_path, const struct capture_params *params)
        }
 
        if (unlikely(params->add_flags & WIMLIB_ADD_FLAG_TEST_FILE_EXCLUSION)) {
        }
 
        if (unlikely(params->add_flags & WIMLIB_ADD_FLAG_TEST_FILE_EXCLUSION)) {
+
                union wimlib_progress_info info;
                union wimlib_progress_info info;
+               tchar *cookie;
 
                info.test_file_exclusion.path = full_path;
                info.test_file_exclusion.will_exclude = false;
 
 
                info.test_file_exclusion.path = full_path;
                info.test_file_exclusion.will_exclude = false;
 
-       #ifdef __WIN32__
-               /* Hack for Windows...  */
-
-               wchar_t *p_question_mark = NULL;
-
-               if (!wcsncmp(full_path, L"\\??\\", 4)) {
-                       /* Trivial transformation:  NT namespace => Win32 namespace  */
-                       p_question_mark = (wchar_t *)&full_path[1];
-                       *p_question_mark = L'\\';
-               }
-       #endif
+               cookie = progress_get_win32_path(full_path);
 
                ret = call_progress(params->progfunc, WIMLIB_PROGRESS_MSG_TEST_FILE_EXCLUSION,
                                    &info, params->progctx);
 
 
                ret = call_progress(params->progfunc, WIMLIB_PROGRESS_MSG_TEST_FILE_EXCLUSION,
                                    &info, params->progctx);
 
-       #ifdef __WIN32__
-               if (p_question_mark)
-                       *p_question_mark = L'?';
-       #endif
+               progress_put_win32_path(cookie);
 
                if (ret)
                        return ret;
 
                if (ret)
                        return ret;
@@ -318,3 +313,51 @@ try_exclude(const tchar *full_path, const struct capture_params *params)
 
        return 0;
 }
 
        return 0;
 }
+
+/*
+ * Determine whether a directory entry of the specified name should be ignored.
+ * This is a lower level function which runs prior to try_exclude().  It handles
+ * the standard '.' and '..' entries, which show up in directory listings but
+ * should not be archived.  It also checks for odd filenames that usually should
+ * not exist but could cause problems if archiving them were to be attempted.
+ */
+bool
+should_ignore_filename(const tchar *name, const int name_nchars)
+{
+       if (name_nchars <= 0) {
+               WARNING("Ignoring empty filename");
+               return true;
+       }
+
+       if (name[0] == T('.') &&
+           (name_nchars == 1 || (name_nchars == 2 && name[1] == T('.'))))
+               return true;
+
+       for (int i = 0; i < name_nchars; i++) {
+               if (name[i] == T('\0')) {
+                       WARNING("Ignoring filename containing embedded null character");
+                       return true;
+               }
+               if (name[i] == OS_PREFERRED_PATH_SEPARATOR) {
+                       WARNING("Ignoring filename containing embedded path separator");
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+/* Attach a newly scanned directory tree to its parent directory, with duplicate
+ * handling.  */
+void
+attach_scanned_tree(struct wim_dentry *parent, struct wim_dentry *child,
+                   struct blob_table *blob_table)
+{
+       struct wim_dentry *duplicate;
+
+       if (child && (duplicate = dentry_add_child(parent, child))) {
+               WARNING("Duplicate file path: \"%"TS"\".  Only capturing "
+                       "the first version.", dentry_full_path(duplicate));
+               free_dentry_tree(child, blob_table);
+       }
+}