Fix T60682: adds macOS alias redirection for directories

This adds support for macOS aliases in addition to symlinks. It also adds
support for hidden, readonly and system file attributes.

Contributed by Ankit (ankitm) with modifications by me.

Differential Revision: https://developer.blender.org/D6679
This commit is contained in:
2020-03-26 17:52:41 +01:00
parent d1972e50cb
commit afb1a64ccb
7 changed files with 153 additions and 21 deletions

View File

@@ -147,6 +147,7 @@ int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONN
bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_file_touch(const char *file) ATTR_NONNULL();
bool BLI_file_alias_target(char *target, const char *filepath);
#if 0 /* UNUSED */
int BLI_file_gzip(const char *from, const char *to) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();

View File

@@ -277,6 +277,13 @@ if(WIN32)
)
endif()
if(APPLE)
list(APPEND SRC
intern/storage_apple.mm
)
endif()
if(UNIX AND NOT APPLE)
list(APPEND LIB
bf_intern_libc_compat

View File

@@ -226,11 +226,12 @@ size_t BLI_file_size(const char *path)
return stats.st_size;
}
#ifndef __APPLE__
eFileAttributes BLI_file_attributes(const char *path)
{
int ret = 0;
#ifdef WIN32
# ifdef WIN32
wchar_t wline[FILE_MAXDIR];
BLI_strncpy_wchar_from_utf8(wline, path, ARRAY_SIZE(wline));
DWORD attr = GetFileAttributesW(wline);
@@ -265,19 +266,9 @@ eFileAttributes BLI_file_attributes(const char *path)
ret |= FILE_ATTR_REPARSE_POINT;
}
#endif
# endif
#ifdef __APPLE__
/* TODO:
* If Hidden (Invisible) set FILE_ATTR_HIDDEN
* If Locked set FILE_ATTR_READONLY
* If Restricted set FILE_ATTR_RESTRICTED
*/
#endif
#ifdef __linux__
# ifdef __linux__
UNUSED_VARS(path);
/* TODO:
@@ -285,10 +276,23 @@ eFileAttributes BLI_file_attributes(const char *path)
* If Archived set FILE_ATTR_ARCHIVE
*/
#endif
# endif
return ret;
}
#endif
/**
* Returns the target path of a file-based redirection, like Mac Alias or Win32 Shortcut file.
*/
#ifndef __APPLE__
bool BLI_file_alias_target(char UNUSED(target[FILE_MAXDIR]), const char *UNUSED(filepath))
{
/* TODO: Find target in Win32 Shortcut - Shell Link (.lnk) file.
* Format: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/ */
return false;
}
#endif
/**
* Returns the st_mode from stat-ing the specified path name, or 0 if stat fails

View File

@@ -0,0 +1,96 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup bli
*
* macOS specific implementations for storage.c.
*/
#import <Foundation/Foundation.h>
#include "BLI_fileops.h"
#include "BLI_path_util.h"
bool BLI_file_alias_target(char targetpath[FILE_MAXDIR], const char *filepath)
{
@autoreleasepool {
NSError *error = nil;
NSURL *shortcutURL = [[NSURL alloc] initFileURLWithFileSystemRepresentation:filepath
isDirectory:NO
relativeToURL:nil];
NSURL *targetURL = [NSURL URLByResolvingAliasFileAtURL:shortcutURL
options:NSURLBookmarkResolutionWithoutUI
error:&error];
BOOL isSame = [shortcutURL isEqual:targetURL] and
([[[shortcutURL path] stringByStandardizingPath]
isEqualToString:[[targetURL path] stringByStandardizingPath]]);
if (targetURL == nil) {
return false;
}
else if (isSame) {
[targetURL getFileSystemRepresentation:targetpath maxLength:FILE_MAXDIR];
return false;
}
else if (![targetURL getFileSystemRepresentation:targetpath maxLength:FILE_MAXDIR]) {
return false;
}
NSNumber *targetIsDirectory = 0;
[targetURL getResourceValue:&targetIsDirectory forKey:NSURLIsDirectoryKey error:nil];
}
return true;
}
eFileAttributes BLI_file_attributes(const char *path)
{
int ret = 0;
@autoreleasepool {
NSURL *fileURL = [[NSURL alloc] initFileURLWithFileSystemRepresentation:path
isDirectory:NO
relativeToURL:nil];
NSArray *resourceKeys =
@[ NSURLIsAliasFileKey, NSURLIsHiddenKey, NSURLIsReadableKey, NSURLIsWritableKey ];
NSDictionary *resourceKeyValues = [fileURL resourceValuesForKeys:resourceKeys error:nil];
const bool is_alias = [resourceKeyValues[(void)(@"@%"), NSURLIsAliasFileKey] boolValue];
const bool is_hidden = [resourceKeyValues[(void)(@"@%"), NSURLIsHiddenKey] boolValue];
const bool is_readable = [resourceKeyValues[(void)(@"@%"), NSURLIsReadableKey] boolValue];
const bool is_writable = [resourceKeyValues[(void)(@"@%"), NSURLIsWritableKey] boolValue];
if (is_alias) {
ret |= FILE_ATTR_ALIAS;
}
if (is_hidden) {
ret |= FILE_ATTR_HIDDEN;
}
if (is_readable && !is_writable) {
ret |= FILE_ATTR_READONLY;
}
if (is_readable) {
ret |= FILE_ATTR_SYSTEM;
}
}
return (eFileAttributes)ret;
}

View File

@@ -1634,7 +1634,9 @@ static int file_exec(bContext *C, wmOperator *exec_op)
BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath);
BLI_add_slash(sfile->params->dir);
}
if (file->redirection_path) {
STRNCPY(sfile->params->dir, file->redirection_path);
}
ED_file_change_dir(C);
}
/* opening file - sends events now, so things get handled on windowqueue level */

View File

@@ -210,12 +210,13 @@ typedef struct FileListInternEntry {
int blentype;
char *relpath;
/** Optional argument for shortcuts, aliases etc. */
char *redirection_path;
/** not strictly needed, but used during sorting, avoids to have to recompute it there... */
char *name;
/** Defined in BLI_fileops.h */
eFileAttributes attributes;
BLI_stat_t st;
} FileListInternEntry;
@@ -961,12 +962,12 @@ ImBuf *filelist_getimage(struct FileList *filelist, const int index)
return file->image;
}
static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char *relpath)
static ImBuf *filelist_geticon_image_ex(FileDirEntry *file)
{
ImBuf *ibuf = NULL;
if (typeflag & FILE_TYPE_DIR) {
if (FILENAME_IS_PARENT(relpath)) {
if (file->typeflag & FILE_TYPE_DIR) {
if (FILENAME_IS_PARENT(file->relpath)) {
ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
}
else {
@@ -983,8 +984,7 @@ static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char
ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
{
FileDirEntry *file = filelist_geticon_get_file(filelist, index);
return filelist_geticon_image_ex(file->typeflag, file->relpath);
return filelist_geticon_image_ex(file);
}
static int filelist_geticon_ex(FileDirEntry *file,
@@ -1170,6 +1170,9 @@ static void filelist_entry_clear(FileDirEntry *entry)
if (entry->relpath) {
MEM_freeN(entry->relpath);
}
if (entry->redirection_path) {
MEM_freeN(entry->redirection_path);
}
if (entry->image) {
IMB_freeImBuf(entry->image);
}
@@ -1239,6 +1242,9 @@ static void filelist_intern_entry_free(FileListInternEntry *entry)
if (entry->relpath) {
MEM_freeN(entry->relpath);
}
if (entry->redirection_path) {
MEM_freeN(entry->redirection_path);
}
if (entry->name) {
MEM_freeN(entry->name);
}
@@ -1690,6 +1696,9 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
ret->blentype = entry->blentype;
ret->typeflag = entry->typeflag;
ret->attributes = entry->attributes;
if (entry->redirection_path) {
ret->redirection_path = BLI_strdup(entry->redirection_path);
}
BLI_addtail(&cache->cached_entries, ret);
return ret;
}
@@ -2523,6 +2532,16 @@ static int filelist_readjob_list_dir(const char *root,
/* Set file attributes. */
entry->attributes = BLI_file_attributes(path);
if (entry->attributes & FILE_ATTR_ALIAS) {
entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__);
if (BLI_file_alias_target(entry->redirection_path, path)) {
if (BLI_is_dir(entry->redirection_path)) {
entry->typeflag = FILE_TYPE_DIR;
}
else
entry->typeflag = ED_path_extension_type(entry->redirection_path);
}
}
#ifndef WIN32
/* Set linux-style dot files hidden too. */

View File

@@ -955,7 +955,10 @@ typedef struct FileDirEntry {
/** ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */
int blentype;
/* Path to item that is relative to current folder root. */
char *relpath;
/** Optional argument for shortcuts, aliases etc. */
char *redirection_path;
/** TODO: make this a real ID pointer? */
void *poin;