22
22
#include < Common/escapeForFileName.h>
23
23
#include < Common/typeid_cast.h>
24
24
#include < Common/parseGlobs.h>
25
+ #include < Common/filesystemHelpers.h>
25
26
#include < Storages/ColumnsDescription.h>
26
27
#include < Storages/StorageInMemoryMetadata.h>
27
28
@@ -120,8 +121,8 @@ void checkCreationIsAllowed(ContextPtr context_global, const std::string & db_di
120
121
return ;
121
122
122
123
// / "/dev/null" is allowed for perf testing
123
- if (!startsWith (table_path, db_dir_path) && table_path != " /dev/null" )
124
- throw Exception (" File is not inside " + db_dir_path, ErrorCodes::DATABASE_ACCESS_DENIED );
124
+ if (!fileOrSymlinkPathStartsWith (table_path, db_dir_path) && table_path != " /dev/null" )
125
+ throw Exception (ErrorCodes::DATABASE_ACCESS_DENIED, " File `{}` is not inside `{}` " , table_path, db_dir_path );
125
126
126
127
if (fs::exists (table_path) && fs::is_directory (table_path))
127
128
throw Exception (" File must not be a directory" , ErrorCodes::INCORRECT_FILE_NAME);
@@ -136,7 +137,10 @@ Strings StorageFile::getPathsList(const String & table_path, const String & user
136
137
fs_table_path = user_files_absolute_path / fs_table_path;
137
138
138
139
Strings paths;
139
- const String path = fs::weakly_canonical (fs_table_path);
140
+ // / Do not use fs::canonical or fs::weakly_canonical.
141
+ // / Otherwise it will not allow to work with symlinks in `user_files_path` directory.
142
+ String path = fs::absolute (fs_table_path);
143
+ path = fs::path (path).lexically_normal (); // / Normalize path.
140
144
if (path.find_first_of (" *?{" ) == std::string::npos)
141
145
{
142
146
std::error_code error;
0 commit comments