mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #6299
6299: Show error message when downloaded map cannot be saved r=def- a=Robyt3 Check if deleting the old map file or renaming the temporary downloaded map fails. If so, show an error message which indicates that the user should delete the map file manually. Sometimes downloaded map files seem to end up with wrong permissions, ownership or with read-only flag set, which makes the client unable to delete them. ![screenshot_2023-01-22_17-19-12](https://user-images.githubusercontent.com/23437060/213927019-ff49cb72-f60a-4c1a-b48b-d34e40d1420e.png) Closes #5825. ## Checklist - [X] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
commit
b8e7160555
|
@ -2333,6 +2333,21 @@ int fs_removedir(const char *path)
|
|||
#endif
|
||||
}
|
||||
|
||||
int fs_is_file(const char *path)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
WCHAR wPath[IO_MAX_PATH_LENGTH];
|
||||
dbg_assert(MultiByteToWideChar(CP_UTF8, 0, path, -1, wPath, std::size(wPath)) > 0, "MultiByteToWideChar failure");
|
||||
DWORD attributes = GetFileAttributesW(wPath);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
|
||||
#else
|
||||
struct stat sb;
|
||||
if(stat(path, &sb) == -1)
|
||||
return 0;
|
||||
return S_ISREG(sb.st_mode) ? 1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int fs_is_dir(const char *path)
|
||||
{
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
|
|
|
@ -1786,18 +1786,24 @@ int str_time_float(float secs, int format, char *buffer, int buffer_size);
|
|||
*/
|
||||
void str_escape(char **dst, const char *src, const char *end);
|
||||
|
||||
/* Group: Filesystem */
|
||||
/**
|
||||
* @defgroup Filesystem
|
||||
*
|
||||
* Utilities for accessing the file system.
|
||||
*/
|
||||
|
||||
/*
|
||||
Function: fs_listdir
|
||||
Lists the files in a directory
|
||||
|
||||
Parameters:
|
||||
dir - Directory to list
|
||||
cb - Callback function to call for each entry
|
||||
type - Type of the directory
|
||||
user - Pointer to give to the callback
|
||||
*/
|
||||
/**
|
||||
* Lists the files and folders in a directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param dir Directory to list.
|
||||
* @param cb Callback function to call for each entry.
|
||||
* @param type Type of the directory.
|
||||
* @param user Pointer to give to the callback.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
typedef int (*FS_LISTDIR_CALLBACK)(const char *name, int is_dir, int dir_type, void *user);
|
||||
void fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user);
|
||||
|
||||
|
@ -1808,174 +1814,207 @@ typedef struct
|
|||
time_t m_TimeModified; // seconds since UNIX Epoch
|
||||
} CFsFileInfo;
|
||||
|
||||
/*
|
||||
Function: fs_listdir_fileinfo
|
||||
Lists the files in a directory and gets additional file information
|
||||
|
||||
Parameters:
|
||||
dir - Directory to list
|
||||
cb - Callback function to call for each entry
|
||||
type - Type of the directory
|
||||
user - Pointer to give to the callback
|
||||
*/
|
||||
/**
|
||||
* Lists the files and folders in a directory and gets additional file information.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param dir Directory to list.
|
||||
* @param cb Callback function to call for each entry.
|
||||
* @param type Type of the directory.
|
||||
* @param user Pointer to give to the callback.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
typedef int (*FS_LISTDIR_CALLBACK_FILEINFO)(const CFsFileInfo *info, int is_dir, int dir_type, void *user);
|
||||
void fs_listdir_fileinfo(const char *dir, FS_LISTDIR_CALLBACK_FILEINFO cb, int type, void *user);
|
||||
|
||||
/*
|
||||
Function: fs_makedir
|
||||
Creates a directory
|
||||
|
||||
Parameters:
|
||||
path - Directory to create
|
||||
|
||||
Returns:
|
||||
Returns 0 on success. Negative value on failure.
|
||||
|
||||
Remarks:
|
||||
Does not create several directories if needed. "a/b/c" will result
|
||||
in a failure if b or a does not exist.
|
||||
*/
|
||||
/**
|
||||
* Creates a directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path Directory to create.
|
||||
*
|
||||
* @return 0 on success. Negative value on failure.
|
||||
*
|
||||
* @remark Does not create several directories if needed. "a/b/c" will
|
||||
* result in a failure if b or a does not exist.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_makedir(const char *path);
|
||||
|
||||
/*
|
||||
Function: fs_removedir
|
||||
Removes a directory
|
||||
|
||||
Parameters:
|
||||
path - Directory to remove
|
||||
|
||||
Returns:
|
||||
Returns 0 on success. Negative value on failure.
|
||||
|
||||
Remarks:
|
||||
Cannot remove a non-empty directory.
|
||||
*/
|
||||
/**
|
||||
* Removes a directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path Directory to remove.
|
||||
*
|
||||
* @return 0 on success. Negative value on failure.
|
||||
*
|
||||
* @remark Cannot remove a non-empty directory.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_removedir(const char *path);
|
||||
|
||||
/*
|
||||
Function: fs_makedir_rec_for
|
||||
Recursively create directories for a file
|
||||
|
||||
Parameters:
|
||||
path - File for which to create directories
|
||||
|
||||
Returns:
|
||||
Returns 0 on success. Negative value on failure.
|
||||
*/
|
||||
/**
|
||||
* Recursively create directories for a file.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path - File for which to create directories.
|
||||
*
|
||||
* @return 0 on success. Negative value on failure.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_makedir_rec_for(const char *path);
|
||||
|
||||
/*
|
||||
Function: fs_storage_path
|
||||
Fetches per user configuration directory.
|
||||
|
||||
Returns:
|
||||
Returns 0 on success. Negative value on failure.
|
||||
|
||||
Remarks:
|
||||
- Returns ~/.appname on UNIX based systems
|
||||
- Returns ~/Library/Applications Support/appname on macOS
|
||||
- Returns %APPDATA%/Appname on Windows based systems
|
||||
*/
|
||||
/**
|
||||
* Fetches per user configuration directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param appname Name of the application.
|
||||
* @param path Buffer that will receive the storage path.
|
||||
* @param max Size of the buffer.
|
||||
*
|
||||
* @return 0 on success. Negative value on failure.
|
||||
*
|
||||
* @remark Returns ~/.appname on UNIX based systems.
|
||||
* @remark Returns ~/Library/Applications Support/appname on macOS.
|
||||
* @remark Returns %APPDATA%/Appname on Windows based systems.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_storage_path(const char *appname, char *path, int max);
|
||||
|
||||
/*
|
||||
Function: fs_is_dir
|
||||
Checks if directory exists
|
||||
/**
|
||||
* Checks if a file exists.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path the path to check.
|
||||
*
|
||||
* @return 1 if a file with the given path exists,
|
||||
* 0 on failure or if the file does not exist.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_is_file(const char *path);
|
||||
|
||||
Returns:
|
||||
Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
/**
|
||||
* Checks if a folder exists.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path the path to check.
|
||||
*
|
||||
* @return 1 if a folder with the given path exists,
|
||||
* 0 on failure or if the folder does not exist.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_is_dir(const char *path);
|
||||
|
||||
/*
|
||||
Function: fs_is_relative_path
|
||||
Checks whether a given path is relative or absolute.
|
||||
|
||||
Returns:
|
||||
Returns 1 if relative, 0 if absolute.
|
||||
*/
|
||||
/**
|
||||
* Checks whether a given path is relative or absolute.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path Path to check.
|
||||
*
|
||||
* @return 1 if relative, 0 if absolute.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_is_relative_path(const char *path);
|
||||
|
||||
/*
|
||||
Function: fs_chdir
|
||||
Changes current working directory
|
||||
|
||||
Returns:
|
||||
Returns 0 on success, 1 on failure.
|
||||
*/
|
||||
/**
|
||||
* Changes the current working directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path New working directory path.
|
||||
*
|
||||
* @return 0 on success, 1 on failure.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_chdir(const char *path);
|
||||
|
||||
/*
|
||||
Function: fs_getcwd
|
||||
Gets the current working directory.
|
||||
|
||||
Returns:
|
||||
Returns a pointer to the buffer on success, 0 on failure.
|
||||
*/
|
||||
/**
|
||||
* Gets the current working directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param buffer Buffer that will receive the current working directory.
|
||||
* @param buffer_size Size of the buffer.
|
||||
*
|
||||
* @return Pointer to the buffer on success, nullptr on failure.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
char *fs_getcwd(char *buffer, int buffer_size);
|
||||
|
||||
/*
|
||||
Function: fs_parent_dir
|
||||
Get the parent directory of a directory
|
||||
|
||||
Parameters:
|
||||
path - The directory string
|
||||
|
||||
Returns:
|
||||
Returns 0 on success, 1 on failure.
|
||||
|
||||
Remarks:
|
||||
- The string is treated as zero-terminated string.
|
||||
*/
|
||||
/**
|
||||
* Get the parent directory of a directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param path Path of the directory. The parent will be store in this buffer as well.
|
||||
*
|
||||
* @return 0 on success, 1 on failure.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_parent_dir(char *path);
|
||||
|
||||
/*
|
||||
Function: fs_remove
|
||||
Deletes the file with the specified name.
|
||||
|
||||
Parameters:
|
||||
filename - The file to delete
|
||||
|
||||
Returns:
|
||||
Returns 0 on success, 1 on failure.
|
||||
|
||||
Remarks:
|
||||
- The strings are treated as zero-terminated strings.
|
||||
- Returns an error if the path specifies a directory name.
|
||||
*/
|
||||
/**
|
||||
* Deletes a file.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param filename Path of the file to delete.
|
||||
*
|
||||
* @return 0 on success, 1 on failure.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
* @remark Returns an error if the path specifies a directory name.
|
||||
*/
|
||||
int fs_remove(const char *filename);
|
||||
|
||||
/*
|
||||
Function: fs_rename
|
||||
Renames the file or directory. If the paths differ the file will be moved.
|
||||
|
||||
Parameters:
|
||||
oldname - The current name
|
||||
newname - The new name
|
||||
|
||||
Returns:
|
||||
Returns 0 on success, 1 on failure.
|
||||
|
||||
Remarks:
|
||||
- The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
/**
|
||||
* Renames the file or directory. If the paths differ the file will be moved.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param oldname The current path of a file or directory.
|
||||
* @param newname The new path for the file or directory.
|
||||
*
|
||||
* @return 0 on success, 1 on failure.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
*/
|
||||
int fs_rename(const char *oldname, const char *newname);
|
||||
|
||||
/*
|
||||
Function: fs_file_time
|
||||
Gets the creation and the last modification date of a file.
|
||||
|
||||
Parameters:
|
||||
name - The filename.
|
||||
created - Pointer to time_t
|
||||
modified - Pointer to time_t
|
||||
|
||||
Returns:
|
||||
0 on success, non-zero on failure
|
||||
|
||||
Remarks:
|
||||
- Returned time is in seconds since UNIX Epoch
|
||||
*/
|
||||
/**
|
||||
* Gets the creation and the last modification date of a file or directory.
|
||||
*
|
||||
* @ingroup Filesystem
|
||||
*
|
||||
* @param name Path of a file or directory.
|
||||
* @param created Pointer where the creation time will be stored.
|
||||
* @param modified Pointer where the modification time will be stored.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*
|
||||
* @remark The strings are treated as zero-terminated strings.
|
||||
* @remark Returned time is in seconds since UNIX Epoch.
|
||||
*/
|
||||
int fs_file_time(const char *name, time_t *created, time_t *modified);
|
||||
|
||||
/*
|
||||
|
|
|
@ -2284,8 +2284,18 @@ void CClient::FinishMapDownload()
|
|||
m_MapdownloadTotalsize = -1;
|
||||
SHA256_DIGEST *pSha256 = m_MapdownloadSha256Present ? &m_MapdownloadSha256 : 0;
|
||||
|
||||
Storage()->RemoveFile(m_aMapdownloadFilename, IStorage::TYPE_SAVE);
|
||||
Storage()->RenameFile(m_aMapdownloadFilenameTemp, m_aMapdownloadFilename, IStorage::TYPE_SAVE);
|
||||
bool FileSuccess = true;
|
||||
if(Storage()->FileExists(m_aMapdownloadFilename, IStorage::TYPE_SAVE))
|
||||
FileSuccess &= Storage()->RemoveFile(m_aMapdownloadFilename, IStorage::TYPE_SAVE);
|
||||
FileSuccess &= Storage()->RenameFile(m_aMapdownloadFilenameTemp, m_aMapdownloadFilename, IStorage::TYPE_SAVE);
|
||||
if(!FileSuccess)
|
||||
{
|
||||
ResetMapDownload();
|
||||
char aError[128 + IO_MAX_PATH_LENGTH];
|
||||
str_format(aError, sizeof(aError), Localize("Could not save downloaded map. Try manually deleting this file: %s"), m_aMapdownloadFilename);
|
||||
DisconnectWithReason(aError);
|
||||
return;
|
||||
}
|
||||
|
||||
// load map
|
||||
const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, pSha256, m_MapdownloadCrc);
|
||||
|
|
|
@ -433,6 +433,44 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
bool GenericExists(const char *pFilename, int Type, F &&CheckFunction)
|
||||
{
|
||||
TranslateType(Type, pFilename);
|
||||
|
||||
char aBuffer[IO_MAX_PATH_LENGTH];
|
||||
if(Type == TYPE_ALL)
|
||||
{
|
||||
// check all available directories
|
||||
for(int i = TYPE_SAVE; i < m_NumPaths; ++i)
|
||||
{
|
||||
if(CheckFunction(GetPath(i, pFilename, aBuffer, sizeof(aBuffer))))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if(Type == TYPE_ABSOLUTE || (Type >= TYPE_SAVE && Type < m_NumPaths))
|
||||
{
|
||||
// check wanted directory
|
||||
return CheckFunction(GetPath(Type, pFilename, aBuffer, sizeof(aBuffer)));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_assert(false, "Type invalid");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileExists(const char *pFilename, int Type) override
|
||||
{
|
||||
return GenericExists(pFilename, Type, fs_is_file);
|
||||
}
|
||||
|
||||
bool FolderExists(const char *pFilename, int Type) override
|
||||
{
|
||||
return GenericExists(pFilename, Type, fs_is_dir);
|
||||
}
|
||||
|
||||
bool ReadFile(const char *pFilename, int Type, void **ppResult, unsigned *pResultLen) override
|
||||
{
|
||||
IOHANDLE File = OpenFile(pFilename, IOFLAG_READ, Type);
|
||||
|
|
|
@ -25,15 +25,15 @@ public:
|
|||
/**
|
||||
* Translates to TYPE_SAVE if a path is relative
|
||||
* and to TYPE_ABSOLUTE if a path is absolute.
|
||||
* Only usable with OpenFile, ReadFile, ReadFileStr
|
||||
* and GetCompletePath.
|
||||
* Only usable with OpenFile, ReadFile, ReadFileStr,
|
||||
* GetCompletePath, FileExists and FolderExists.
|
||||
*/
|
||||
TYPE_SAVE_OR_ABSOLUTE = -3,
|
||||
/**
|
||||
* Translates to TYPE_ALL if a path is relative
|
||||
* and to TYPE_ABSOLUTE if a path is absolute.
|
||||
* Only usable with OpenFile, ReadFile, ReadFileStr
|
||||
* and GetCompletePath.
|
||||
* Only usable with OpenFile, ReadFile, ReadFileStr,
|
||||
* GetCompletePath, FileExists and FolderExists.
|
||||
*/
|
||||
TYPE_ALL_OR_ABSOLUTE = -4,
|
||||
|
||||
|
@ -45,6 +45,8 @@ public:
|
|||
virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0;
|
||||
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_CALLBACK_FILEINFO pfnCallback, void *pUser) = 0;
|
||||
virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = nullptr, int BufferSize = 0) = 0;
|
||||
virtual bool FileExists(const char *pFilename, int Type) = 0;
|
||||
virtual bool FolderExists(const char *pFilename, int Type) = 0;
|
||||
virtual bool ReadFile(const char *pFilename, int Type, void **ppResult, unsigned *pResultLen) = 0;
|
||||
virtual char *ReadFileStr(const char *pFilename, int Type) = 0;
|
||||
virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize) = 0;
|
||||
|
|
Loading…
Reference in a new issue