mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-12-24 10:32:32 +00:00
- extfs: replaced get/set_finder_*() functions by get/set_finfo(), helper
files now store complete FInfo/FXInfo
This commit is contained in:
parent
b244cfb633
commit
006472eb44
@ -4,6 +4,8 @@ V0.8 (snapshot) -
|
||||
when reading from CD-ROM [Jürgen Lachmann]
|
||||
- AmigaOS/prefs_editor_amiga.cpp: fixed bug when adding volumes
|
||||
[Jürgen Lachmann]
|
||||
- AmigaOS/Unix/extfs_*.cpp: .finf helper file now stores complete
|
||||
FInfo/FXInfo, replaced get/set_finder_*() functions by get/set_finfo()
|
||||
- Imported some changes from the Windows port, most notably FPU fixes
|
||||
and the 1Hz interrupt [Lauri Pesonen]
|
||||
|
||||
|
@ -77,16 +77,11 @@ void add_path_component(char *path, const char *component)
|
||||
* /path/.finf/file
|
||||
* Resource fork:
|
||||
* /path/.rsrc/file
|
||||
*
|
||||
* The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo
|
||||
* (16+16 bytes)
|
||||
*/
|
||||
|
||||
// Layout of Finder info helper files (all fields big-endian)
|
||||
struct finf_struct {
|
||||
uint32 type;
|
||||
uint32 creator;
|
||||
uint16 flags;
|
||||
uint8 pad0[22]; // total size: 32 bytes to match the size of FInfo+FXInfo
|
||||
};
|
||||
|
||||
static void make_helper_path(const char *src, char *dest, const char *add, bool only_dir = false)
|
||||
{
|
||||
dest[0] = 0;
|
||||
@ -110,6 +105,8 @@ static int create_helper_dir(const char *path, const char *add)
|
||||
{
|
||||
char helper_dir[MAX_PATH_LENGTH];
|
||||
make_helper_path(path, helper_dir, add, true);
|
||||
if (helper_dir[strlen(helper_dir) - 1] == '/') // Remove trailing "/"
|
||||
helper_dir[strlen(helper_dir) - 1] = 0;
|
||||
return mkdir(helper_dir, 0777);
|
||||
}
|
||||
|
||||
@ -187,6 +184,7 @@ static const ext2type e2t_translation[] = {
|
||||
{".tga", 'TPIC', 'ogle'},
|
||||
{".tif", 'TIFF', 'ogle'},
|
||||
{".tiff", 'TIFF', 'ogle'},
|
||||
{".htm", 'TEXT', 'MOSS'},
|
||||
{".html", 'TEXT', 'MOSS'},
|
||||
{".txt", 'TEXT', 'ttxt'},
|
||||
{".rtf", 'TEXT', 'MSWD'},
|
||||
@ -207,110 +205,61 @@ static const ext2type e2t_translation[] = {
|
||||
{".mov", 'MooV', 'TVOD'},
|
||||
{".fli", 'FLI ', 'TVOD'},
|
||||
{".avi", 'VfW ', 'TVOD'},
|
||||
{".qxd", 'XDOC', 'XPR3'},
|
||||
{".hfv", 'DDim', 'ddsk'},
|
||||
{".dsk", 'DDim', 'ddsk'},
|
||||
{".img", 'rohd', 'ddsk'},
|
||||
{NULL, 0, 0} // End marker
|
||||
};
|
||||
|
||||
void get_finder_type(const char *path, uint32 &type, uint32 &creator)
|
||||
void get_finfo(const char *path, uint32 finfo, uint32 fxinfo)
|
||||
{
|
||||
type = 0;
|
||||
creator = 0;
|
||||
// Set default finder info
|
||||
Mac_memset(finfo, 0, SIZEOF_FInfo);
|
||||
if (fxinfo)
|
||||
Mac_memset(fxinfo, 0, SIZEOF_FXInfo);
|
||||
WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS);
|
||||
WriteMacInt32(finfo + fdLocation, (uint32)-1);
|
||||
|
||||
// Open Finder info file
|
||||
// Read Finder info file
|
||||
int fd = open_finf(path, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
|
||||
// Read file
|
||||
finf_struct finf;
|
||||
if (read(fd, &finf, sizeof(finf_struct)) >= 8) {
|
||||
|
||||
// Type/creator are in Finder info file, return them
|
||||
type = ntohl(finf.type);
|
||||
creator = ntohl(finf.creator);
|
||||
ssize_t actual = read(fd, Mac2HostAddr(finfo), SIZEOF_FInfo);
|
||||
if (fxinfo)
|
||||
actual += read(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo);
|
||||
close(fd);
|
||||
if (actual >= SIZEOF_FInfo)
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// No Finder info file, translate file name extension to MacOS type/creator
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) {
|
||||
int path_len = strlen(path);
|
||||
for (int i=0; e2t_translation[i].ext; i++) {
|
||||
int ext_len = strlen(e2t_translation[i].ext);
|
||||
if (path_len < ext_len)
|
||||
continue;
|
||||
if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) {
|
||||
type = e2t_translation[i].type;
|
||||
creator = e2t_translation[i].creator;
|
||||
if (!strcasecmp(path + path_len - ext_len, e2t_translation[i].ext)) {
|
||||
WriteMacInt32(finfo + fdType, e2t_translation[i].type);
|
||||
WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_finder_type(const char *path, uint32 type, uint32 creator)
|
||||
void set_finfo(const char *path, uint32 finfo, uint32 fxinfo)
|
||||
{
|
||||
// Open Finder info file
|
||||
int fd = open_finf(path, O_RDWR);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// Read file
|
||||
finf_struct finf;
|
||||
finf.flags = DEFAULT_FINDER_FLAGS;
|
||||
memset(&finf, 0, sizeof(finf_struct));
|
||||
read(fd, &finf, sizeof(finf_struct));
|
||||
|
||||
// Set Finder flags
|
||||
finf.type = htonl(type);
|
||||
finf.creator = htonl(creator);
|
||||
|
||||
// Update file
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
write(fd, &finf, sizeof(finf_struct));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get/set finder flags for file/dir specified by full path
|
||||
*/
|
||||
|
||||
void get_finder_flags(const char *path, uint16 &flags)
|
||||
{
|
||||
flags = DEFAULT_FINDER_FLAGS; // Default
|
||||
|
||||
// Open Finder info file
|
||||
int fd = open_finf(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// Read Finder flags
|
||||
finf_struct finf;
|
||||
if (read(fd, &finf, sizeof(finf_struct)) >= 10)
|
||||
flags = ntohs(finf.flags);
|
||||
|
||||
// Close file
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void set_finder_flags(const char *path, uint16 flags)
|
||||
{
|
||||
// Open Finder info file
|
||||
int fd = open_finf(path, O_RDWR);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// Read file
|
||||
finf_struct finf;
|
||||
memset(&finf, 0, sizeof(finf_struct));
|
||||
finf.flags = DEFAULT_FINDER_FLAGS;
|
||||
read(fd, &finf, sizeof(finf_struct));
|
||||
|
||||
// Set Finder flags
|
||||
finf.flags = htons(flags);
|
||||
|
||||
// Update file
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
write(fd, &finf, sizeof(finf_struct));
|
||||
// Write file
|
||||
write(fd, Mac2HostAddr(finfo), SIZEOF_FInfo);
|
||||
if (fxinfo)
|
||||
write(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
@ -78,16 +78,11 @@ void add_path_component(char *path, const char *component)
|
||||
* /path/.finf/file
|
||||
* Resource fork:
|
||||
* /path/.rsrc/file
|
||||
*
|
||||
* The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo
|
||||
* (16+16 bytes)
|
||||
*/
|
||||
|
||||
// Layout of Finder info helper files (all fields big-endian)
|
||||
struct finf_struct {
|
||||
uint32 type;
|
||||
uint32 creator;
|
||||
uint16 flags;
|
||||
uint8 pad0[22]; // total size: 32 bytes to match the size of FInfo+FXInfo
|
||||
};
|
||||
|
||||
static void make_helper_path(const char *src, char *dest, const char *add, bool only_dir = false)
|
||||
{
|
||||
dest[0] = 0;
|
||||
@ -115,6 +110,8 @@ static int create_helper_dir(const char *path, const char *add)
|
||||
{
|
||||
char helper_dir[MAX_PATH_LENGTH];
|
||||
make_helper_path(path, helper_dir, add, true);
|
||||
if (helper_dir[strlen(helper_dir) - 1] == '/') // Remove trailing "/"
|
||||
helper_dir[strlen(helper_dir) - 1] = 0;
|
||||
return mkdir(helper_dir, 0777);
|
||||
}
|
||||
|
||||
@ -151,7 +148,7 @@ static int open_rsrc(const char *path, int flag)
|
||||
|
||||
|
||||
/*
|
||||
* Get/set finder type/creator for file specified by full path
|
||||
* Get/set finder info for file/directory specified by full path
|
||||
*/
|
||||
|
||||
struct ext2type {
|
||||
@ -192,6 +189,7 @@ static const ext2type e2t_translation[] = {
|
||||
{".tga", 'TPIC', 'ogle'},
|
||||
{".tif", 'TIFF', 'ogle'},
|
||||
{".tiff", 'TIFF', 'ogle'},
|
||||
{".htm", 'TEXT', 'MOSS'},
|
||||
{".html", 'TEXT', 'MOSS'},
|
||||
{".txt", 'TEXT', 'ttxt'},
|
||||
{".rtf", 'TEXT', 'MSWD'},
|
||||
@ -212,110 +210,61 @@ static const ext2type e2t_translation[] = {
|
||||
{".mov", 'MooV', 'TVOD'},
|
||||
{".fli", 'FLI ', 'TVOD'},
|
||||
{".avi", 'VfW ', 'TVOD'},
|
||||
{".qxd", 'XDOC', 'XPR3'},
|
||||
{".hfv", 'DDim', 'ddsk'},
|
||||
{".dsk", 'DDim', 'ddsk'},
|
||||
{".img", 'rohd', 'ddsk'},
|
||||
{NULL, 0, 0} // End marker
|
||||
};
|
||||
|
||||
void get_finder_type(const char *path, uint32 &type, uint32 &creator)
|
||||
void get_finfo(const char *path, uint32 finfo, uint32 fxinfo)
|
||||
{
|
||||
type = 0;
|
||||
creator = 0;
|
||||
// Set default finder info
|
||||
Mac_memset(finfo, 0, SIZEOF_FInfo);
|
||||
if (fxinfo)
|
||||
Mac_memset(fxinfo, 0, SIZEOF_FXInfo);
|
||||
WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS);
|
||||
WriteMacInt32(finfo + fdLocation, (uint32)-1);
|
||||
|
||||
// Open Finder info file
|
||||
// Read Finder info file
|
||||
int fd = open_finf(path, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
|
||||
// Read file
|
||||
finf_struct finf;
|
||||
if (read(fd, &finf, sizeof(finf_struct)) >= 8) {
|
||||
|
||||
// Type/creator are in Finder info file, return them
|
||||
type = ntohl(finf.type);
|
||||
creator = ntohl(finf.creator);
|
||||
ssize_t actual = read(fd, Mac2HostAddr(finfo), SIZEOF_FInfo);
|
||||
if (fxinfo)
|
||||
actual += read(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo);
|
||||
close(fd);
|
||||
if (actual >= SIZEOF_FInfo)
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// No Finder info file, translate file name extension to MacOS type/creator
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) {
|
||||
int path_len = strlen(path);
|
||||
for (int i=0; e2t_translation[i].ext; i++) {
|
||||
int ext_len = strlen(e2t_translation[i].ext);
|
||||
if (path_len < ext_len)
|
||||
continue;
|
||||
if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) {
|
||||
type = e2t_translation[i].type;
|
||||
creator = e2t_translation[i].creator;
|
||||
WriteMacInt32(finfo + fdType, e2t_translation[i].type);
|
||||
WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_finder_type(const char *path, uint32 type, uint32 creator)
|
||||
void set_finfo(const char *path, uint32 finfo, uint32 fxinfo)
|
||||
{
|
||||
// Open Finder info file
|
||||
int fd = open_finf(path, O_RDWR);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// Read file
|
||||
finf_struct finf;
|
||||
finf.flags = DEFAULT_FINDER_FLAGS;
|
||||
memset(&finf, 0, sizeof(finf_struct));
|
||||
read(fd, &finf, sizeof(finf_struct));
|
||||
|
||||
// Set Finder flags
|
||||
finf.type = htonl(type);
|
||||
finf.creator = htonl(creator);
|
||||
|
||||
// Update file
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
write(fd, &finf, sizeof(finf_struct));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get/set finder flags for file/dir specified by full path
|
||||
*/
|
||||
|
||||
void get_finder_flags(const char *path, uint16 &flags)
|
||||
{
|
||||
flags = DEFAULT_FINDER_FLAGS; // Default
|
||||
|
||||
// Open Finder info file
|
||||
int fd = open_finf(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// Read Finder flags
|
||||
finf_struct finf;
|
||||
if (read(fd, &finf, sizeof(finf_struct)) >= 10)
|
||||
flags = ntohs(finf.flags);
|
||||
|
||||
// Close file
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void set_finder_flags(const char *path, uint16 flags)
|
||||
{
|
||||
// Open Finder info file
|
||||
int fd = open_finf(path, O_RDWR);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// Read file
|
||||
finf_struct finf;
|
||||
memset(&finf, 0, sizeof(finf_struct));
|
||||
finf.flags = DEFAULT_FINDER_FLAGS;
|
||||
read(fd, &finf, sizeof(finf_struct));
|
||||
|
||||
// Set Finder flags
|
||||
finf.flags = htons(flags);
|
||||
|
||||
// Update file
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
write(fd, &finf, sizeof(finf_struct));
|
||||
// Write file
|
||||
write(fd, Mac2HostAddr(finfo), SIZEOF_FInfo);
|
||||
if (fxinfo)
|
||||
write(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ enum {
|
||||
fsHFSProcStub = 6,
|
||||
fsDrvStatus = 12, // Drive Status record
|
||||
fsFSD = 42, // File system descriptor
|
||||
fsPB = 238, // IOParam (for mounting and renaming)
|
||||
fsPB = 238, // IOParam (for mounting and renaming), also used for temporary storage
|
||||
fsVMI = 288, // VoumeMountInfoHeader (for mounting)
|
||||
fsParseRec = 296, // ParsePathRec struct
|
||||
fsReturn = 306, // Area for return data of 68k routines
|
||||
@ -1253,14 +1253,7 @@ read_next_de:
|
||||
#endif
|
||||
WriteMacInt32(pb + ioFlMdDat, st.st_mtime + TIME_OFFSET);
|
||||
|
||||
Mac_memset(pb + ioFlFndrInfo, 0, SIZEOF_FInfo);
|
||||
uint32 type, creator; // pb may point to kernel space, but stack is switched
|
||||
get_finder_type(full_path, type, creator);
|
||||
WriteMacInt32(pb + ioFlFndrInfo + fdType, type);
|
||||
WriteMacInt32(pb + ioFlFndrInfo + fdCreator, creator);
|
||||
uint16 fflags;
|
||||
get_finder_flags(full_path, fflags);
|
||||
WriteMacInt16(pb + ioFlFndrInfo + fdFlags, fflags);
|
||||
get_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0);
|
||||
|
||||
WriteMacInt16(pb + ioFlStBlk, 0);
|
||||
WriteMacInt32(pb + ioFlLgLen, st.st_size);
|
||||
@ -1272,7 +1265,6 @@ read_next_de:
|
||||
|
||||
if (hfs) {
|
||||
WriteMacInt32(pb + ioFlBkDat, 0);
|
||||
Mac_memset(pb + ioFlXFndrInfo, 0, SIZEOF_FXInfo);
|
||||
WriteMacInt32(pb + ioFlParID, fs_item->parent_id);
|
||||
WriteMacInt32(pb + ioFlClpSiz, 0);
|
||||
}
|
||||
@ -1297,9 +1289,9 @@ static int16 fs_set_file_info(uint32 pb, bool hfs, uint32 dirID)
|
||||
if (S_ISDIR(st.st_mode))
|
||||
return fnfErr;
|
||||
|
||||
// Set attributes
|
||||
set_finder_type(full_path, ReadMacInt32(pb + ioFlFndrInfo + fdType), ReadMacInt32(pb + ioFlFndrInfo + fdCreator));
|
||||
set_finder_flags(full_path, ReadMacInt16(pb + ioFlFndrInfo + fdFlags));
|
||||
// Set Finder info
|
||||
set_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0);
|
||||
|
||||
//!! times
|
||||
return noErr;
|
||||
}
|
||||
@ -1389,12 +1381,10 @@ read_next_de:
|
||||
}
|
||||
WriteMacInt32(pb + ioFlMdDat, mtime + TIME_OFFSET);
|
||||
WriteMacInt32(pb + ioFlBkDat, 0);
|
||||
|
||||
get_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo);
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
Mac_memset(pb + ioDrUsrWds, 0, SIZEOF_DInfo);
|
||||
Mac_memset(pb + ioDrFndrInfo, 0, SIZEOF_DXInfo);
|
||||
uint16 fflags; // pb may point to kernel space, but stack is switched
|
||||
get_finder_flags(full_path, fflags);
|
||||
WriteMacInt16(pb + ioDrUsrWds + frFlags, fflags);
|
||||
|
||||
// Determine number of files in directory (cached)
|
||||
int count;
|
||||
@ -1419,15 +1409,6 @@ read_next_de:
|
||||
}
|
||||
WriteMacInt16(pb + ioDrNmFls, count);
|
||||
} else {
|
||||
Mac_memset(pb + ioFlFndrInfo, 0, SIZEOF_FInfo);
|
||||
Mac_memset(pb + ioFlXFndrInfo, 0, SIZEOF_FXInfo);
|
||||
uint32 type, creator; // pb may point to kernel space, but stack is switched
|
||||
get_finder_type(full_path, type, creator);
|
||||
WriteMacInt32(pb + ioFlFndrInfo + fdType, type);
|
||||
WriteMacInt32(pb + ioFlFndrInfo + fdCreator, creator);
|
||||
uint16 fflags;
|
||||
get_finder_flags(full_path, fflags);
|
||||
WriteMacInt16(pb + ioFlFndrInfo + fdFlags, fflags);
|
||||
WriteMacInt16(pb + ioFlStBlk, 0);
|
||||
WriteMacInt32(pb + ioFlLgLen, st.st_size);
|
||||
WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
|
||||
@ -1456,13 +1437,9 @@ static int16 fs_set_cat_info(uint32 pb)
|
||||
if (stat(full_path, &st) < 0)
|
||||
return errno2oserr();
|
||||
|
||||
// Set attributes
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
set_finder_flags(full_path, ReadMacInt16(pb + ioDrUsrWds + frFlags));
|
||||
} else {
|
||||
set_finder_type(full_path, ReadMacInt32(pb + ioFlFndrInfo + fdType), ReadMacInt32(pb + ioFlFndrInfo + fdCreator));
|
||||
set_finder_flags(full_path, ReadMacInt16(pb + ioFlFndrInfo + fdFlags));
|
||||
}
|
||||
// Set Finder info
|
||||
set_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo);
|
||||
|
||||
//!! times
|
||||
return noErr;
|
||||
}
|
||||
@ -1548,9 +1525,10 @@ static int16 fs_open(uint32 pb, uint32 dirID, uint32 vcb, bool resource_fork)
|
||||
WriteMacInt32(fcb + fcbCrPs, 0);
|
||||
WriteMacInt32(fcb + fcbVPtr, vcb);
|
||||
WriteMacInt32(fcb + fcbClmpSize, CLUMP_SIZE);
|
||||
uint32 type, creator; // BeOS: fcb may point to kernel space, but stack is switched
|
||||
get_finder_type(full_path, type, creator);
|
||||
WriteMacInt32(fcb + fcbFType, type);
|
||||
|
||||
get_finfo(full_path, fs_data + fsPB, 0);
|
||||
WriteMacInt32(fcb + fcbFType, ReadMacInt32(fs_data + fsPB + fdType));
|
||||
|
||||
WriteMacInt32(fcb + fcbCatPos, fd);
|
||||
WriteMacInt32(fcb + fcbDirID, fs_item->parent_id);
|
||||
cstr2pstr((char *)Mac2HostAddr(fcb + fcbCName), fs_item->name);
|
||||
|
@ -33,10 +33,8 @@ extern int16 ExtFSHFS(uint32 vcb, uint16 selectCode, uint32 paramBlock, uint32 g
|
||||
extern void extfs_init(void);
|
||||
extern void extfs_exit(void);
|
||||
extern void add_path_component(char *path, const char *component);
|
||||
extern void get_finder_type(const char *path, uint32 &type, uint32 &creator);
|
||||
extern void set_finder_type(const char *path, uint32 type, uint32 creator);
|
||||
extern void get_finder_flags(const char *path, uint16 &flags);
|
||||
extern void set_finder_flags(const char *path, uint16 flags);
|
||||
extern void get_finfo(const char *path, uint32 finfo, uint32 fxinfo);
|
||||
extern void set_finfo(const char *path, uint32 finfo, uint32 fxinfo);
|
||||
extern uint32 get_rfork_size(const char *path);
|
||||
extern int open_rfork(const char *path, int flag);
|
||||
extern void close_rfork(const char *path, int fd);
|
||||
|
Loading…
Reference in New Issue
Block a user