Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion tsk/fs/ifind_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "tsk_fs_i.h"
#include "tsk_hfs.h"
#include "tsk_logical_fs.h" // for the logical-FS path probe


/*******************************************************************************
Expand Down Expand Up @@ -179,6 +180,67 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
char *strtok_last;
*a_result = 0;

#ifdef TSK_WIN32
// Logical file systems are backed by a directory tree on the host OS, so on
// Windows we can resolve paths much faster by leveraging Win32 APIs and the
// logical-FS-specific caches instead of going through the generic dir-open-meta
// walk. The optimization is gated on both the FS type and TSK_WIN32 because
// the host-side enumeration this relies on is only implemented for Windows.
if (a_fs != NULL && a_fs->ftype == TSK_FS_TYPE_LOGICAL) {
// Both logical-FS helpers below need the path in UTF-16 with backslash
// separators. Convert once here so we don't duplicate the work in each
// helper. UTF-16 needs at most as many code units as UTF-8 has bytes
// (ASCII = 1:1, multi-byte sequences collapse), so the input byte length
// is always a safe upper bound for the wide-char allocation.
size_t a_path_len = strlen(a_path);
TSK_TCHAR *a_path_wide = (TSK_TCHAR *)tsk_malloc(sizeof(TSK_TCHAR) * (a_path_len + 1));
if (a_path_wide == NULL) {
return -1;
}

UTF8 *utf8_src = (UTF8 *)a_path;
UTF16 *utf16_dst = (UTF16 *)a_path_wide;
TSKConversionResult cnv = tsk_UTF8toUTF16(
(const UTF8 **)&utf8_src, &utf8_src[a_path_len],
&utf16_dst, &utf16_dst[a_path_len], TSKlenientConversion);
if (cnv != TSKconversionOK) {
free(a_path_wide);
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_FS_UNICODE);
tsk_error_set_errstr("tsk_fs_path2inum: UTF-8 to UTF-16 conversion failed for path: %s", a_path);
return -1;
}

// tsk_UTF8toUTF16 advances utf16_dst past the last written code unit.
// Null-terminate at that position. We allocated (a_path_len + 1) wchars
// so this write is always in-bounds.
*utf16_dst = L'\0';

// Convert forward slashes to backslashes (logical-FS internals use
// backslashes; the \\?\ long-path namespace requires backslashes).
for (TSK_TCHAR *p = a_path_wide; *p != L'\0'; p++) {
if (*p == L'/') *p = L'\\';
}

TSK_LOGICAL_PATH_TYPE path_type = tsk_logical_fs_check_path(a_fs, a_path_wide);

if (path_type == TSK_LOGICAL_PATH_NOT_FOUND) {
// Path doesn't exist on the host filesystem - skip the expensive walk
free(a_path_wide);
return 1;
}

// Path exists. Dispatch to the logical-FS-specific resolver, which uses
// get_inum_from_directory_path (cache-aware) for directories and the
// sorted-file-list lookup for files.
int8_t ret = tsk_logical_fs_path2inum(a_fs, a_path_wide, path_type, a_result);

free(a_path_wide);
return ret;
}
#endif


// copy path to a buffer that we can modify
clen = strlen(a_path) + 1;
if ((cpath = (char *) tsk_malloc(clen)) == NULL) {
Expand Down Expand Up @@ -446,7 +508,11 @@ tsk_fs_ifind_path(TSK_FS_INFO * fs, TSK_TCHAR * tpath, TSK_INUM_T * result)
free(cpath);
return -1;
}
return tsk_fs_path2inum(fs, cpath, result, NULL);
// tsk_fs_path2inum does not take ownership of cpath - it makes its own
// internal copy. Free our buffer before returning to avoid a leak.
int8_t ret = tsk_fs_path2inum(fs, cpath, result, NULL);
free(cpath);
return ret;
}
#else
return tsk_fs_path2inum(fs, (const char *) tpath, result, NULL);
Expand Down
Loading