32# if defined(__APPLE__)
33# include <CoreFoundation/CoreFoundation.h>
34# include <objc/message.h>
35# include <objc/runtime.h>
38# include <sys/param.h>
53#define FILE_MAX_STATIC_BUF 256
110 std::min<size_t>(nbytes, INT_MAX)
115 if (nbytes_read == nbytes) {
117 return nbytes_read_total + nbytes_read;
119 if (nbytes_read == 0) {
121 return nbytes_read_total;
123 if (nbytes_read < 0) {
128 if (
UNLIKELY(nbytes_read > nbytes)) {
140 buf = (
void *)(((
char *)buf) + nbytes_read);
141 nbytes_read_total += nbytes_read;
142 nbytes -= nbytes_read;
149 const char *opstring = windows_operation_string(operation);
160 const char *opstring = windows_operation_string(operation);
174 void *buf,
size_t len, FILE *file,
size_t file_offset,
int compression_level)
176 fseek(file, file_offset, SEEK_SET);
178 ZSTD_CCtx *ctx = ZSTD_createCCtx();
179 ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, compression_level);
181 ZSTD_inBuffer input = {buf,
len, 0};
183 size_t out_len = ZSTD_CStreamOutSize();
185 size_t total_written = 0;
188 while (input.pos < input.size) {
189 ZSTD_outBuffer output = {out_buf, out_len, 0};
190 size_t ret = ZSTD_compressStream2(ctx, &output, &input, ZSTD_e_continue);
191 if (ZSTD_isError(
ret)) {
194 if (fwrite(out_buf, 1, output.pos, file) != output.pos) {
197 total_written += output.pos;
203 ZSTD_outBuffer output = {out_buf, out_len, 0};
204 ret = ZSTD_compressStream2(ctx, &output, &input, ZSTD_e_end);
205 if (ZSTD_isError(
ret)) {
208 if (fwrite(out_buf, 1, output.pos, file) != output.pos) {
211 total_written += output.pos;
217 return ZSTD_isError(
ret) ? 0 : total_written;
222 fseek(file, file_offset, SEEK_SET);
224 ZSTD_DCtx *ctx = ZSTD_createDCtx();
226 size_t in_len = ZSTD_DStreamInSize();
228 ZSTD_inBuffer input = {in_buf, in_len, 0};
230 ZSTD_outBuffer output = {buf,
len, 0};
234 while (output.pos < output.size && !ZSTD_isError(
ret)) {
235 input.size = fread(in_buf, 1, in_len, file);
236 if (input.size == 0) {
242 while (input.pos < input.size && output.pos < output.size) {
243 ret = ZSTD_decompressStream(ctx, &output, &input);
245 if (ZSTD_isError(
ret)) {
254 return ZSTD_isError(
ret) ? 0 : output.pos;
261 return header[0] == 0x1f && header[1] == 0x8b && header[2] == 0x08;
282 if (
magic == 0xFD2FB528) {
285 if ((
magic >> 4) == 0x184D2A5) {
298 else if (errno != ENOENT) {
310 writable =
BLI_access(parent, X_OK | W_OK) == 0;
350 "Paths must not end with a slash!");
353 "Paths containing \"..\" components must be normalized first!");
357 if (dirname_parent_end) {
358 const char dirname_parent_end_value = *dirname_parent_end;
359 *dirname_parent_end =
'\0';
375 *dirname_parent_end = dirname_parent_end_value;
383 if (mkdir(
dirname, 0777) != 0) {
402 char *dirname_mut = dirname_static_buf;
405 if (
len >=
sizeof(dirname_static_buf)) {
406 dirname_mut = MEM_cnew_array<char>(
len + 1, __func__);
415 dirname_mut[
len] =
'\0';
422 if (dirname_mut != dirname_static_buf) {
477 return urename(from, to,
false);
479# if defined(__APPLE__)
480 int ret = renamex_np(from, to, RENAME_EXCL);
481 if (!(
ret < 0 && errno == ENOTSUP)) {
486# if defined(__GLIBC_PREREQ)
487# if __GLIBC_PREREQ(2, 28)
489 int ret = renameat2(AT_FDCWD, from, AT_FDCWD, to, RENAME_NOREPLACE);
490 if (!(
ret < 0 && errno == EINVAL)) {
501 return rename(from, to);
520 return urename(from, to,
true);
522 return rename(from, to);
528static void callLocalErrorCallBack(
const char *err)
533FILE *
BLI_fopen(
const char *filepath,
const char *mode)
537 return ufopen(filepath, mode);
540void BLI_get_short_name(
char short_name[256],
const char *filepath)
542 wchar_t short_name_16[256];
547 GetShortPathNameW(filepath_16, short_name_16, 256);
549 for (i = 0; i < 256; i++) {
550 short_name[i] = char(short_name_16[i]);
556void *
BLI_gzopen(
const char *filepath,
const char *mode)
563 if (mode[0] ==
'w') {
564 FILE *file =
ufopen(filepath,
"a");
574# if ZLIB_VERNUM >= 0x1270
577 gzfile = gzopen_w(filepath_16, mode);
582 char short_name[256];
583 BLI_get_short_name(short_name, filepath);
584 gzfile = gzopen(short_name, mode);
602 return uaccess(filepath, mode);
605static bool delete_soft(
const wchar_t *path_16,
const char **r_error_message)
612 HRESULT hr = CoInitializeEx(
NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
618 hr = CoCreateInstance(
619 CLSID_FileOperation,
NULL, CLSCTX_ALL, IID_IFileOperation, (
void **)&pfo);
626 hr = pfo->SetOperationFlags(FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING);
629 hr = SHCreateItemFromParsingName(path_16,
NULL, IID_IShellItem, (
void **)&psi);
632 hr = pfo->DeleteItem(psi,
NULL);
635 hr = pfo->PerformOperations();
638 *r_error_message =
"Failed to prepare delete operation";
642 *r_error_message =
"Failed to prepare delete operation";
647 *r_error_message =
"Failed to parse path";
651 *r_error_message =
"Failed to set operation flags";
656 *r_error_message =
"Failed to create FileOperation instance";
661 *r_error_message =
"Failed to initialize COM";
667static bool delete_unique(
const char *path,
const bool dir)
674 err = !RemoveDirectoryW(path_16);
676 printf(
"Unable to remove directory\n");
680 err = !DeleteFileW(path_16);
682 callLocalErrorCallBack(
"Unable to delete file");
691static bool delete_recursive(
const char *dir)
695 uint filelist_num, i;
710 if (delete_recursive(
path)) {
715 if (delete_unique(fl->
path,
false)) {
722 if (!err && delete_unique(dir,
true)) {
738 BLI_assert(!(dir ==
false && recursive ==
true));
741 err = delete_recursive(
path);
744 err = delete_unique(
path, dir);
761 err = delete_soft(file_16, r_error_message);
776 const char *path_dst,
782 if (filename_src != path_src) {
783 const size_t path_dst_len = strlen(path_dst);
786 size_t buf_size_needed = path_dst_len + strlen(filename_src) + 1;
787 char *path_dst_with_filename = (buf_size_needed <= buf_size) ?
789 MEM_cnew_array<char>(buf_size_needed, __func__);
790 BLI_string_join(path_dst_with_filename, buf_size_needed, path_dst, filename_src);
791 return path_dst_with_filename;
801 path_src, path_dst, path_dst_buf,
sizeof(path_dst_buf));
807 err = !MoveFileW(path_src_16, path_dst_with_filename_16);
812 callLocalErrorCallBack(
"Unable to move file");
813 printf(
" Move from '%s' to '%s' failed\n", path_src, path_dst_with_filename);
816 if (!
ELEM(path_dst_with_filename, path_dst_buf, path_dst)) {
817 MEM_freeN((
void *)path_dst_with_filename);
823int BLI_copy(
const char *path_src,
const char *path_dst)
827 path_src, path_dst, path_dst_buf,
sizeof(path_dst_buf));
832 err = !CopyFileW(path_src_16, path_dst_with_filename_16,
false);
837 callLocalErrorCallBack(
"Unable to copy file!");
838 printf(
" Copy from '%s' to '%s' failed\n", path_src, path_dst_with_filename);
841 if (!
ELEM(path_dst_with_filename, path_dst_buf, path_dst)) {
842 MEM_freeN((
void *)path_dst_with_filename);
849int BLI_create_symlink(
const char *path_src,
const char *path_dst)
852 callLocalErrorCallBack(
"Linking files is unsupported on Windows");
877 const int path_len = strlen(
path);
913 str_len_alloc = std::max(str_len + 1, str_len_alloc);
914 buf->
str =
static_cast<char *
>(malloc(str_len_alloc));
915 memcpy(buf->
str,
str, str_len);
916 buf->
str[str_len] =
'\0';
933 bool has_slash = (buf->
str_len > 0 &&
935 const size_t filename_len = strlen(filename);
936 const size_t len = buf->
str_len + (has_slash ? 0 : 1) + filename_len;
939 buf->
str =
static_cast<char *
>(realloc(
static_cast<void *
>(buf->
str),
len + 1));
942 if (has_slash ==
false) {
945 memcpy(buf->
str + buf->
str_len, filename, filename_len + 1);
973 dirent **dirlist =
nullptr;
982 ret = lstat(src_buf->
str, &st);
991 if (callback_file !=
nullptr) {
992 ret = callback_file(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1000 dirlist_num = scandir(src_buf->
str, &dirlist,
nullptr, alphasort);
1001 if (dirlist_num < 0) {
1008 if (callback_dir_pre !=
nullptr) {
1009 ret = callback_dir_pre(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1021 const size_t src_len = src_buf->
str_len;
1022 const size_t dst_len = dst_buf ? dst_buf->
str_len : 0;
1024 for (
int i = 0; i < dirlist_num; i++) {
1041 lstat(src_buf->
str, &st_dir);
1042 is_dir =
S_ISDIR(st_dir.st_mode);
1045 is_dir = (
dirent->d_type == DT_DIR);
1051 src_buf, dst_buf, callback_dir_pre, callback_file, callback_dir_post);
1053 else if (callback_file !=
nullptr) {
1054 ret = callback_file(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1072 if (callback_dir_post !=
nullptr) {
1073 ret = callback_dir_post(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1080 if (dirlist !=
nullptr) {
1081 for (
int i = 0; i < dirlist_num; i++) {
1107 const char *path_dst,
1113 StrBuf src_buf_stack = {};
1114 StrBuf dst_buf_stack = {};
1115 StrBuf *src_buf = &src_buf_stack;
1116 StrBuf *dst_buf = path_dst ? &dst_buf_stack :
nullptr;
1119 const size_t str_len_over_alloc = 0;
1121 const size_t str_len_over_alloc =
FILE_MAX;
1130 src_buf, dst_buf, callback_dir_pre, callback_file, callback_dir_post);
1165 return fopen(filepath, mode);
1172 return gzopen(filepath, mode);
1179 return open(filepath,
oflag, pmode);
1186 return access(filepath, mode);
1193 BLI_assert(!(dir ==
false && recursive ==
true));
1201 return remove(path);
1210 const char *args[5];
1211 const char *process_failed;
1215 const char *xdg_current_desktop = getenv(
"XDG_CURRENT_DESKTOP");
1216 const char *xdg_session_desktop = getenv(
"XDG_SESSION_DESKTOP");
1219 (xdg_session_desktop &&
STREQ(xdg_session_desktop,
"KDE")))
1221 args[0] =
"kioclient5";
1224 args[3] =
"trash:/";
1226 process_failed =
"kioclient5 reported failure";
1233 process_failed =
"gio reported failure";
1237 const int errno_prev = errno;
1242 *r_error_message = errno ? strerror(errno) :
"unable to fork process";
1248 execvp(args[0], (
char **)args);
1263 waitpid(pid, &wstatus, 0);
1266 if (WIFEXITED(wstatus)) {
1267 const int errno_child = WEXITSTATUS(wstatus);
1269 *r_error_message = process_failed;
1273 errno = errno_child;
1278 "Blender may not support moving files or directories to trash on your system.";
1296 struct stat st_a, st_b;
1298 if (lstat(path_a, &st_a)) {
1302 if (lstat(path_b, &st_b)) {
1306 return st_a.st_dev == st_b.st_dev && st_a.st_ino == st_b.st_ino;
1314 if (chown(filepath, st->st_uid, st->st_gid)) {
1319 if (chmod(filepath, st->st_mode)) {
1334 fprintf(stderr,
"%s: '%s' is the same as '%s'\n", __func__, from, to);
1338 if (lstat(from, &st)) {
1344 if (mkdir(to, st.st_mode)) {
1350 if (chown(to, st.st_uid, st.st_gid)) {
1360 FILE *from_stream, *to_stream;
1366 fprintf(stderr,
"%s: '%s' is the same as '%s'\n", __func__, from, to);
1370 if (lstat(from, &st)) {
1375 if (S_ISLNK(st.st_mode)) {
1382 if ((st.st_size + 1) <
sizeof(buf)) {
1387 link_buffer = MEM_cnew_array<char>(st.st_size + 2,
"copy_single_file link_buffer");
1391 link_len = readlink(from, link_buffer, st.st_size + 1);
1402 link_buffer[link_len] =
'\0';
1404 if (symlink(link_buffer, to)) {
1418 if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
1420 if (mknod(to, st.st_mode, st.st_rdev)) {
1432 fprintf(stderr,
"Copying of this kind of files isn't supported yet\n");
1436 from_stream = fopen(from,
"rb");
1442 to_stream = fopen(to,
"wb");
1445 fclose(from_stream);
1449 while ((
len = fread(buf, 1,
sizeof(buf), from_stream)) > 0) {
1450 fwrite(buf, 1,
len, to_stream);
1454 fclose(from_stream);
1465 int ret = rename(from, to);
1476 int ret = rename(from, to);
1498 const char *path_dst,
1503 char *path_src_no_slash =
BLI_strdup(path_src);
1506 if (filename_src != path_src_no_slash) {
1507 const size_t buf_size_needed = strlen(path_dst) + 1 + strlen(filename_src) + 1;
1508 char *path_dst_with_filename = (buf_size_needed <= buf_size) ?
1510 MEM_cnew_array<char>(buf_size_needed, __func__);
1511 BLI_path_join(path_dst_with_filename, buf_size_needed, path_dst, filename_src);
1512 path_dst = path_dst_with_filename;
1519int BLI_copy(
const char *path_src,
const char *path_dst)
1523 path_src, path_dst, path_dst_buf,
sizeof(path_dst_buf));
1529 if (!
ELEM(path_dst_with_filename, path_dst_buf, path_dst)) {
1530 MEM_freeN((
void *)path_dst_with_filename);
1537int BLI_create_symlink(
const char *path_src,
const char *path_dst)
1539 return symlink(path_dst, path_src);
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
@ FILE_EXTERNAL_OPERATION_FOLDER_OPEN
@ FILE_EXTERNAL_OPERATION_FOLDER_CMD
@ FILE_EXTERNAL_OPERATION_OPEN
@ FILE_EXTERNAL_OPERATION_PRINT
@ FILE_EXTERNAL_OPERATION_INSTALL
@ FILE_EXTERNAL_OPERATION_PLAY
@ FILE_EXTERNAL_OPERATION_BROWSE
@ FILE_EXTERNAL_OPERATION_PREVIEW
@ FILE_EXTERNAL_OPERATION_RUNAS
@ FILE_EXTERNAL_OPERATION_FOLDER_FIND
@ FILE_EXTERNAL_OPERATION_NEW
@ FILE_EXTERNAL_OPERATION_EDIT
@ FILE_EXTERNAL_OPERATION_PROPERTIES
@ FILE_EXTERNAL_OPERATION_FIND
@ FILE_EXTERNAL_OPERATION_SHOW
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
Some types for dealing with directories.
void BLI_kdtree_nd_ free(KDTree *tree)
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define BLI_path_join(...)
#define FILENAME_IS_CURRPAR(_n)
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
BLI_INLINE bool BLI_path_slash_is_native_compat(const char ch)
const char * BLI_path_parent_dir_end(const char *path, size_t path_len) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_win32_drive_only(const char *path)
void BLI_path_slash_rstrip(char *path) ATTR_NONNULL(1)
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
#define STRNCPY(dst, src)
bool bool int bool BLI_string_elem_split_by_delim(const char *haystack, const char delim, const char *needle) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define BLI_string_join(...)
Compatibility-like things for windows.
bool BLI_windows_external_operation_supported(const char *filepath, const char *operation)
const char * dirname(char *path)
bool BLI_windows_external_operation_execute(const char *filepath, const char *operation)
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define FILE_MAX_STATIC_BUF
static int recursive_operation_impl(StrBuf *src_buf, StrBuf *dst_buf, RecursiveOp_Callback callback_dir_pre, RecursiveOp_Callback callback_file, RecursiveOp_Callback callback_dir_post)
@ RecursiveOp_Callback_StopRecurs
@ RecursiveOp_Callback_OK
@ RecursiveOp_Callback_Error
static size_t path_len_no_trailing_slash(const char *path)
static void strbuf_append_path(StrBuf *buf, const char *filename)
int BLI_access(const char *filepath, int mode)
static bool check_the_same(const char *path_a, const char *path_b)
static int move_callback_pre(const char *from, const char *to)
static bool path_has_trailing_slash(const char *path)
size_t BLI_file_unzstd_to_mem_at_pos(void *buf, size_t len, FILE *file, size_t file_offset)
int(* RecursiveOp_Callback)(const char *from, const char *to)
bool BLI_file_magic_is_gzip(const char header[4])
static int delete_callback_post(const char *from, const char *)
FILE * BLI_fopen(const char *filepath, const char *mode)
bool BLI_file_external_operation_supported(const char *filepath, FileExternalOperation operation)
static void strbuf_free(StrBuf *buf)
bool BLI_dir_create_recursive(const char *dirname)
int BLI_open(const char *filepath, int oflag, int pmode)
static const char * path_destination_ensure_filename(const char *path_src, const char *path_dst, char *buf, size_t buf_size)
bool BLI_file_is_writable(const char *filepath)
bool BLI_file_magic_is_zstd(const char header[4])
static int copy_single_file(const char *from, const char *to)
bool BLI_file_ensure_parent_dir_exists(const char *filepath)
static int recursive_operation(const char *path_src, const char *path_dst, RecursiveOp_Callback callback_dir_pre, RecursiveOp_Callback callback_file, RecursiveOp_Callback callback_dir_post)
int BLI_copy(const char *path_src, const char *path_dst)
bool BLI_file_touch(const char *filepath)
static int move_single_file(const char *from, const char *to)
int BLI_delete_soft(const char *filepath, const char **r_error_message)
int BLI_delete(const char *path, bool dir, bool recursive)
static int delete_single_file(const char *from, const char *)
size_t BLI_file_zstd_from_mem_at_pos(void *buf, size_t len, FILE *file, size_t file_offset, int compression_level)
static void strbuf_init(StrBuf *buf, const char *str, size_t str_len, size_t str_len_alloc)
static int set_permissions(const char *filepath, const struct stat *st)
void * BLI_gzopen(const char *filepath, const char *mode)
int BLI_path_move(const char *path_src, const char *path_dst)
int BLI_rename_overwrite(const char *from, const char *to)
static bool dir_create_recursive(char *dirname, int len)
bool BLI_file_external_operation_execute(const char *filepath, FileExternalOperation operation)
static void strbuf_trim(StrBuf *buf, size_t len)
int64_t BLI_read(int fd, void *buf, size_t nbytes)
int BLI_rename(const char *from, const char *to)
static int copy_callback_pre(const char *from, const char *to)
void *(* MEM_mallocN)(size_t len, const char *str)
void MEM_freeN(void *vmemh)
static int magic(const Tex *tex, const float texvec[3], TexResult *texres)
int urename(const char *oldname, const char *newname, const bool do_replace)
FILE * ufopen(const char *filename, const char *mode)
int umkdir(const char *pathname)
int uopen(const char *filename, int oflag, int pmode)
int uaccess(const char *filename, int mode)
#define UTF16_ENCODE(in8str)
#define UTF16_UN_ENCODE(in8str)