33# if defined(__APPLE__)
34# include <CoreFoundation/CoreFoundation.h>
35# include <objc/message.h>
36# include <objc/runtime.h>
39# 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;
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};
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};
235 input.size = fread(in_buf, 1, in_len, file);
236 if (
input.size == 0) {
245 if (ZSTD_isError(
ret)) {
254 return ZSTD_isError(
ret) ? 0 :
output.pos;
261 return header[0] == 0x1f && header[1] == 0x8b && header[2] == 0x08;
281 uint32_t
magic = *((uint32_t *)header);
282 if (
magic == 0xFD2FB528) {
285 if ((
magic >> 4) == 0x184D2A5) {
298 else if (errno != ENOENT) {
310 writable =
BLI_access(parent, X_OK | W_OK) == 0;
359 "Paths must not end with a slash!");
362 "Paths containing \"..\" components must be normalized first!");
366 if (dirname_parent_end) {
367 const char dirname_parent_end_value = *dirname_parent_end;
368 *dirname_parent_end =
'\0';
384 *dirname_parent_end = dirname_parent_end_value;
401 if (mkdir(
dirname, 0777) != 0) {
425 char *dirname_mut = dirname_static_buf;
428 if (
len >=
sizeof(dirname_static_buf)) {
438 dirname_mut[
len] =
'\0';
445 if (dirname_mut != dirname_static_buf) {
500 return urename(from, to,
false);
502# if defined(__APPLE__)
503 int ret = renamex_np(from, to, RENAME_EXCL);
504 if (!(
ret < 0 && errno == ENOTSUP)) {
509# if defined(__GLIBC_PREREQ)
510# if __GLIBC_PREREQ(2, 28)
512 int ret = renameat2(AT_FDCWD, from, AT_FDCWD, to, RENAME_NOREPLACE);
513 if (!(
ret < 0 && errno == EINVAL)) {
524 return rename(from, to);
543 return urename(from, to,
true);
545 return rename(from, to);
551static void callLocalErrorCallBack(
const char *err)
556FILE *
BLI_fopen(
const char *filepath,
const char *mode)
560 return ufopen(filepath, mode);
563void BLI_get_short_name(
char short_name[256],
const char *filepath)
565 wchar_t short_name_16[256];
570 GetShortPathNameW(filepath_16, short_name_16, 256);
572 for (
i = 0;
i < 256;
i++) {
573 short_name[
i] = char(short_name_16[
i]);
579void *
BLI_gzopen(
const char *filepath,
const char *mode)
586 if (mode[0] ==
'w') {
587 FILE *file =
ufopen(filepath,
"a");
588 if (file ==
nullptr) {
596# if ZLIB_VERNUM >= 0x1270
599 gzfile = gzopen_w(filepath_16, mode);
604 char short_name[256];
605 BLI_get_short_name(short_name, filepath);
606 gzfile = gzopen(short_name, mode);
624 return uaccess(filepath, mode);
627static bool delete_soft(
const wchar_t *path_16,
const char **r_error_message)
634 HRESULT hr = CoInitializeEx(
nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
640 hr = CoCreateInstance(
641 CLSID_FileOperation,
nullptr, CLSCTX_ALL, IID_IFileOperation, (
void **)&pfo);
648 hr = pfo->SetOperationFlags(FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING);
651 hr = SHCreateItemFromParsingName(path_16,
nullptr, IID_IShellItem, (
void **)&psi);
654 hr = pfo->DeleteItem(psi,
nullptr);
657 hr = pfo->PerformOperations();
660 *r_error_message =
"Failed to prepare delete operation";
664 *r_error_message =
"Failed to prepare delete operation";
669 *r_error_message =
"Failed to parse path";
673 *r_error_message =
"Failed to set operation flags";
678 *r_error_message =
"Failed to create FileOperation instance";
683 *r_error_message =
"Failed to initialize COM";
689static bool delete_unique(
const char *path,
const bool dir)
696 err = !RemoveDirectoryW(path_16);
698 printf(
"Unable to remove directory\n");
702 err = !DeleteFileW(path_16);
704 callLocalErrorCallBack(
"Unable to delete file");
713static bool delete_recursive(
const char *dir)
717 uint filelist_num,
i;
732 if (delete_recursive(
path)) {
737 if (delete_unique(fl->
path,
false)) {
744 if (!err && delete_unique(dir,
true)) {
760 BLI_assert(!(dir ==
false && recursive ==
true));
763 err = delete_recursive(
path);
766 err = delete_unique(
path, dir);
783 err = delete_soft(file_16, r_error_message);
798 const char *path_dst,
804 if (filename_src != path_src) {
805 const size_t path_dst_len = strlen(path_dst);
808 size_t buf_size_needed = path_dst_len + strlen(filename_src) + 1;
809 char *path_dst_with_filename = (buf_size_needed <= buf_size) ?
812 BLI_string_join(path_dst_with_filename, buf_size_needed, path_dst, filename_src);
813 return path_dst_with_filename;
823 path_src, path_dst, path_dst_buf,
sizeof(path_dst_buf));
829 err = !MoveFileW(path_src_16, path_dst_with_filename_16);
834 callLocalErrorCallBack(
"Unable to move file");
835 printf(
" Move from '%s' to '%s' failed\n", path_src, path_dst_with_filename);
838 if (!
ELEM(path_dst_with_filename, path_dst_buf, path_dst)) {
845int BLI_copy(
const char *path_src,
const char *path_dst)
849 path_src, path_dst, path_dst_buf,
sizeof(path_dst_buf));
854 err = !CopyFileW(path_src_16, path_dst_with_filename_16,
false);
859 callLocalErrorCallBack(
"Unable to copy file!");
860 printf(
" Copy from '%s' to '%s' failed\n", path_src, path_dst_with_filename);
863 if (!
ELEM(path_dst_with_filename, path_dst_buf, path_dst)) {
871int BLI_create_symlink(
const char *path_src,
const char *path_dst)
874 callLocalErrorCallBack(
"Linking files is unsupported on Windows");
899 const int path_len = strlen(
path);
935 str_len_alloc = std::max(str_len + 1, str_len_alloc);
936 buf->
str =
static_cast<char *
>(malloc(str_len_alloc));
937 memcpy(buf->
str,
str, str_len);
938 buf->
str[str_len] =
'\0';
955 bool has_slash = (buf->
str_len > 0 &&
957 const size_t filename_len = strlen(filename);
958 const size_t len = buf->
str_len + (has_slash ? 0 : 1) + filename_len;
961 buf->
str =
static_cast<char *
>(realloc(
static_cast<void *
>(buf->
str),
len + 1));
964 if (has_slash ==
false) {
967 memcpy(buf->
str + buf->
str_len, filename, filename_len + 1);
995 dirent **dirlist =
nullptr;
1004 ret = lstat(src_buf->
str, &st);
1013 if (callback_file !=
nullptr) {
1014 ret = callback_file(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1022 dirlist_num = scandir(src_buf->
str, &dirlist,
nullptr, alphasort);
1023 if (dirlist_num < 0) {
1030 if (callback_dir_pre !=
nullptr) {
1031 ret = callback_dir_pre(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1043 const size_t src_len = src_buf->
str_len;
1044 const size_t dst_len = dst_buf ? dst_buf->
str_len : 0;
1046 for (
int i = 0;
i < dirlist_num;
i++) {
1063 lstat(src_buf->
str, &st_dir);
1064 is_dir =
S_ISDIR(st_dir.st_mode);
1067 is_dir = (
dirent->d_type == DT_DIR);
1073 src_buf, dst_buf, callback_dir_pre, callback_file, callback_dir_post);
1075 else if (callback_file !=
nullptr) {
1076 ret = callback_file(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1094 if (callback_dir_post !=
nullptr) {
1095 ret = callback_dir_post(src_buf->
str, dst_buf ? dst_buf->
str :
nullptr);
1102 if (dirlist !=
nullptr) {
1103 for (
int i = 0;
i < dirlist_num;
i++) {
1129 const char *path_dst,
1135 StrBuf src_buf_stack = {};
1136 StrBuf dst_buf_stack = {};
1137 StrBuf *src_buf = &src_buf_stack;
1138 StrBuf *dst_buf = path_dst ? &dst_buf_stack :
nullptr;
1141 const size_t str_len_over_alloc = 0;
1143 const size_t str_len_over_alloc =
FILE_MAX;
1152 src_buf, dst_buf, callback_dir_pre, callback_file, callback_dir_post);
1187 return fopen(filepath, mode);
1194 return gzopen(filepath, mode);
1201 return open(filepath,
oflag, pmode);
1208 return access(filepath, mode);
1215 BLI_assert(!(dir ==
false && recursive ==
true));
1223 return remove(path);
1232 const char *args[5];
1233 const char *process_failed;
1237 const char *xdg_current_desktop = [] {
1239 const char *key =
"ORIGINAL_XDG_CURRENT_DESKTOP";
1240 const char *value = getenv(key);
1241 return value ? value : getenv(key + 9);
1243 const char *xdg_session_desktop = getenv(
"XDG_SESSION_DESKTOP");
1246 (xdg_session_desktop &&
STREQ(xdg_session_desktop,
"KDE")))
1248 args[0] =
"kioclient5";
1251 args[3] =
"trash:/";
1253 process_failed =
"kioclient5 reported failure";
1260 process_failed =
"gio reported failure";
1264 const int errno_prev = errno;
1269 *r_error_message = errno ? strerror(errno) :
"unable to fork process";
1275 execvp(args[0], (
char **)args);
1290 waitpid(pid, &wstatus, 0);
1293 if (WIFEXITED(wstatus)) {
1294 const int errno_child = WEXITSTATUS(wstatus);
1296 *r_error_message = process_failed;
1300 errno = errno_child;
1305 "Blender may not support moving files or directories to trash on your system.";
1323 struct stat st_a, st_b;
1325 if (lstat(path_a, &st_a)) {
1329 if (lstat(path_b, &st_b)) {
1333 return st_a.st_dev == st_b.st_dev && st_a.st_ino == st_b.st_ino;
1341 if (chown(filepath, st->st_uid, st->st_gid)) {
1346 if (chmod(filepath, st->st_mode)) {
1361 fprintf(stderr,
"%s: '%s' is the same as '%s'\n", __func__, from, to);
1365 if (lstat(from, &st)) {
1371 if (mkdir(to, st.st_mode)) {
1377 if (chown(to, st.st_uid, st.st_gid)) {
1387 FILE *from_stream, *to_stream;
1393 fprintf(stderr,
"%s: '%s' is the same as '%s'\n", __func__, from, to);
1397 if (lstat(from, &st)) {
1402 if (S_ISLNK(st.st_mode)) {
1409 if ((st.st_size + 1) <
sizeof(buf)) {
1418 link_len = readlink(from, link_buffer, st.st_size + 1);
1429 link_buffer[link_len] =
'\0';
1431 if (symlink(link_buffer, to)) {
1445 if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
1447 if (mknod(to, st.st_mode, st.st_rdev)) {
1459 fprintf(stderr,
"Copying of this kind of files isn't supported yet\n");
1463 from_stream = fopen(from,
"rb");
1469 to_stream = fopen(to,
"wb");
1472 fclose(from_stream);
1476 while ((
len = fread(buf, 1,
sizeof(buf), from_stream)) > 0) {
1477 fwrite(buf, 1,
len, to_stream);
1481 fclose(from_stream);
1492 int ret = rename(from, to);
1503 int ret = rename(from, to);
1525 const char *path_dst,
1530 char *path_src_no_slash =
BLI_strdup(path_src);
1533 if (filename_src != path_src_no_slash) {
1534 const size_t buf_size_needed = strlen(path_dst) + 1 + strlen(filename_src) + 1;
1535 char *path_dst_with_filename = (buf_size_needed <= buf_size) ?
1538 BLI_path_join(path_dst_with_filename, buf_size_needed, path_dst, filename_src);
1539 path_dst = path_dst_with_filename;
1546int BLI_copy(
const char *path_src,
const char *path_dst)
1550 path_src, path_dst, path_dst_buf,
sizeof(path_dst_buf));
1556 if (!
ELEM(path_dst_with_filename, path_dst_buf, path_dst)) {
1564int BLI_create_symlink(
const char *path_src,
const char *path_dst)
1566 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
char * STRNCPY(char(&dst)[N], const char *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
#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)
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 bool dir_create_recursive(const char *dirname, const int len)
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)
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)
int(*)(const char *from, const char *to) RecursiveOp_Callback
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)
bool BLI_file_external_operation_execute(const char *filepath, FileExternalOperation operation)
static void strbuf_trim(StrBuf *buf, size_t len)
@ RecursiveOp_Callback_StopRecurs
@ RecursiveOp_Callback_OK
@ RecursiveOp_Callback_Error
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_calloc_arrayN(size_t len, size_t size, 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)