Simple Directmedia Layer
at main 221 lines 6.4 kB view raw
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#if defined(SDL_FSOPS_POSIX) 25 26/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 27// System dependent filesystem routines 28 29#include "../SDL_sysfilesystem.h" 30 31#include <stdio.h> 32#include <string.h> 33#include <errno.h> 34#include <dirent.h> 35#include <sys/stat.h> 36#include <unistd.h> 37 38bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata) 39{ 40 SDL_EnumerationResult result = SDL_ENUM_CONTINUE; 41 42 DIR *dir = opendir(path); 43 if (!dir) { 44 return SDL_SetError("Can't open directory: %s", strerror(errno)); 45 } 46 47 struct dirent *ent; 48 while ((result == SDL_ENUM_CONTINUE) && ((ent = readdir(dir)) != NULL)) 49 { 50 const char *name = ent->d_name; 51 if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) { 52 continue; 53 } 54 result = cb(userdata, dirname, name); 55 } 56 57 closedir(dir); 58 59 return (result != SDL_ENUM_FAILURE); 60} 61 62bool SDL_SYS_RemovePath(const char *path) 63{ 64 int rc = remove(path); 65 if (rc < 0) { 66 if (errno == ENOENT) { 67 // It's already gone, this is a success 68 return true; 69 } 70 return SDL_SetError("Can't remove path: %s", strerror(errno)); 71 } 72 return true; 73} 74 75bool SDL_SYS_RenamePath(const char *oldpath, const char *newpath) 76{ 77 if (rename(oldpath, newpath) < 0) { 78 return SDL_SetError("Can't rename path: %s", strerror(errno)); 79 } 80 return true; 81} 82 83bool SDL_SYS_CopyFile(const char *oldpath, const char *newpath) 84{ 85 char *buffer = NULL; 86 SDL_IOStream *input = NULL; 87 SDL_IOStream *output = NULL; 88 const size_t maxlen = 4096; 89 size_t len; 90 bool result = false; 91 92 input = SDL_IOFromFile(oldpath, "rb"); 93 if (!input) { 94 goto done; 95 } 96 97 output = SDL_IOFromFile(newpath, "wb"); 98 if (!output) { 99 goto done; 100 } 101 102 buffer = (char *)SDL_malloc(maxlen); 103 if (!buffer) { 104 goto done; 105 } 106 107 while ((len = SDL_ReadIO(input, buffer, maxlen)) > 0) { 108 if (SDL_WriteIO(output, buffer, len) < len) { 109 goto done; 110 } 111 } 112 if (SDL_GetIOStatus(input) != SDL_IO_STATUS_EOF) { 113 goto done; 114 } 115 116 SDL_CloseIO(input); 117 input = NULL; 118 119 if (!SDL_FlushIO(output)) { 120 goto done; 121 } 122 123 result = SDL_CloseIO(output); 124 output = NULL; // it's gone, even if it failed. 125 126done: 127 if (output) { 128 SDL_CloseIO(output); 129 } 130 if (input) { 131 SDL_CloseIO(input); 132 } 133 SDL_free(buffer); 134 135 return result; 136} 137 138bool SDL_SYS_CreateDirectory(const char *path) 139{ 140 const int rc = mkdir(path, 0770); 141 if (rc < 0) { 142 const int origerrno = errno; 143 if (origerrno == EEXIST) { 144 struct stat statbuf; 145 if ((stat(path, &statbuf) == 0) && (S_ISDIR(statbuf.st_mode))) { 146 return true; // it already exists and it's a directory, consider it success. 147 } 148 } 149 return SDL_SetError("Can't create directory: %s", strerror(origerrno)); 150 } 151 return true; 152} 153 154bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info) 155{ 156 struct stat statbuf; 157 const int rc = stat(path, &statbuf); 158 if (rc < 0) { 159 return SDL_SetError("Can't stat: %s", strerror(errno)); 160 } else if (S_ISREG(statbuf.st_mode)) { 161 info->type = SDL_PATHTYPE_FILE; 162 info->size = (Uint64) statbuf.st_size; 163 } else if (S_ISDIR(statbuf.st_mode)) { 164 info->type = SDL_PATHTYPE_DIRECTORY; 165 info->size = 0; 166 } else { 167 info->type = SDL_PATHTYPE_OTHER; 168 info->size = (Uint64) statbuf.st_size; 169 } 170 171#if defined(HAVE_ST_MTIM) 172 // POSIX.1-2008 standard 173 info->create_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_ctim.tv_sec) + statbuf.st_ctim.tv_nsec; 174 info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_mtim.tv_sec) + statbuf.st_mtim.tv_nsec; 175 info->access_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_atim.tv_sec) + statbuf.st_atim.tv_nsec; 176#elif defined(SDL_PLATFORM_APPLE) 177 /* Apple platform stat structs use 'st_*timespec' naming. */ 178 info->create_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_ctimespec.tv_sec) + statbuf.st_ctimespec.tv_nsec; 179 info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_mtimespec.tv_sec) + statbuf.st_mtimespec.tv_nsec; 180 info->access_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_atimespec.tv_sec) + statbuf.st_atimespec.tv_nsec; 181#else 182 info->create_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_ctime); 183 info->modify_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_mtime); 184 info->access_time = (SDL_Time)SDL_SECONDS_TO_NS(statbuf.st_atime); 185#endif 186 return true; 187} 188 189// Note that this isn't actually part of filesystem, not fsops, but everything that uses posix fsops uses this implementation, even with separate filesystem code. 190char *SDL_SYS_GetCurrentDirectory(void) 191{ 192 size_t buflen = 64; 193 char *buf = NULL; 194 195 while (true) { 196 void *ptr = SDL_realloc(buf, buflen); 197 if (!ptr) { 198 SDL_free(buf); 199 return NULL; 200 } 201 buf = (char *) ptr; 202 203 if (getcwd(buf, buflen) != NULL) { 204 break; // we got it! 205 } 206 207 if (errno == ERANGE) { 208 buflen *= 2; // try again with a bigger buffer. 209 continue; 210 } 211 212 SDL_free(buf); 213 SDL_SetError("getcwd failed: %s", strerror(errno)); 214 return NULL; 215 } 216 217 return buf; 218} 219 220#endif // SDL_FSOPS_POSIX 221