| File: | utils/file.c |
| Warning: | line 349, column 7 The 1st argument to 'fstatat' is between -99 and -1 but should be a valid file descriptor or AT_FDCWD |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright 2014 vincent Sanders <vince@netsurf-browser.org> | |||
| 3 | * | |||
| 4 | * This file is part of NetSurf, http://www.netsurf-browser.org/ | |||
| 5 | * | |||
| 6 | * NetSurf is free software; you can redistribute it and/or modify | |||
| 7 | * it under the terms of the GNU General Public License as published by | |||
| 8 | * the Free Software Foundation; version 2 of the License. | |||
| 9 | * | |||
| 10 | * NetSurf is distributed in the hope that it will be useful, | |||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 13 | * GNU General Public License for more details. | |||
| 14 | * | |||
| 15 | * You should have received a copy of the GNU General Public License | |||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 17 | */ | |||
| 18 | ||||
| 19 | /** \file | |||
| 20 | * Table operations for files with posix compliant path separator. | |||
| 21 | */ | |||
| 22 | ||||
| 23 | #include <stdarg.h> | |||
| 24 | #include <string.h> | |||
| 25 | #include <stdio.h> | |||
| 26 | #include <sys/types.h> | |||
| 27 | #include <sys/stat.h> | |||
| 28 | #include <unistd.h> | |||
| 29 | #include <fcntl.h> | |||
| 30 | #include <errno(*__errno_location ()).h> | |||
| 31 | ||||
| 32 | #include "desktop/gui_internal.h" | |||
| 33 | ||||
| 34 | #include "utils/utils.h" | |||
| 35 | #include "utils/corestrings.h" | |||
| 36 | #include "utils/url.h" | |||
| 37 | #include "utils/nsurl.h" | |||
| 38 | #include "utils/string.h" | |||
| 39 | #include "utils/file.h" | |||
| 40 | #include "utils/dirent.h" | |||
| 41 | ||||
| 42 | #ifdef nsamiga | |||
| 43 | #include "frontends/amiga/os3support.h" | |||
| 44 | #endif | |||
| 45 | ||||
| 46 | /** | |||
| 47 | * Generate a posix path from one or more component elemnts. | |||
| 48 | * | |||
| 49 | * If a string is allocated it must be freed by the caller. | |||
| 50 | * | |||
| 51 | * @param[in,out] str pointer to string pointer if this is NULL enough | |||
| 52 | * storage will be allocated for the complete path. | |||
| 53 | * @param[in,out] size The size of the space available if \a str not | |||
| 54 | * NULL on input and if not NULL set to the total | |||
| 55 | * output length on output. | |||
| 56 | * @param[in] nelm The number of elements. | |||
| 57 | * @param[in] ap The elements of the path as string pointers. | |||
| 58 | * @return NSERROR_OK and the complete path is written to str | |||
| 59 | * or error code on faliure. | |||
| 60 | */ | |||
| 61 | static nserror posix_vmkpath(char **str, size_t *size, size_t nelm, va_list ap) | |||
| 62 | { | |||
| 63 | return vsnstrjoin(str, size, '/', nelm, ap); | |||
| 64 | } | |||
| 65 | ||||
| 66 | /** | |||
| 67 | * Get the basename of a file using posix path handling. | |||
| 68 | * | |||
| 69 | * This gets the last element of a path and returns it. | |||
| 70 | * | |||
| 71 | * @param[in] path The path to extract the name from. | |||
| 72 | * @param[in,out] str Pointer to string pointer if this is NULL enough | |||
| 73 | * storage will be allocated for the path element. | |||
| 74 | * @param[in,out] size The size of the space available if \a | |||
| 75 | * str not NULL on input and set to the total | |||
| 76 | * output length on output. | |||
| 77 | * @return NSERROR_OK and the complete path is written to str | |||
| 78 | * or error code on faliure. | |||
| 79 | */ | |||
| 80 | static nserror posix_basename(const char *path, char **str, size_t *size) | |||
| 81 | { | |||
| 82 | const char *leafname; | |||
| 83 | char *fname; | |||
| 84 | ||||
| 85 | if (path == NULL((void*)0)) { | |||
| 86 | return NSERROR_BAD_PARAMETER; | |||
| 87 | } | |||
| 88 | ||||
| 89 | leafname = strrchr(path, '/'); | |||
| 90 | if (!leafname) { | |||
| 91 | leafname = path; | |||
| 92 | } else { | |||
| 93 | leafname += 1; | |||
| 94 | } | |||
| 95 | ||||
| 96 | fname = strdup(leafname); | |||
| 97 | if (fname == NULL((void*)0)) { | |||
| 98 | return NSERROR_NOMEM; | |||
| 99 | } | |||
| 100 | ||||
| 101 | *str = fname; | |||
| 102 | if (size != NULL((void*)0)) { | |||
| 103 | *size = strlen(fname); | |||
| 104 | } | |||
| 105 | return NSERROR_OK; | |||
| 106 | } | |||
| 107 | ||||
| 108 | /** | |||
| 109 | * Create a path from a nsurl using posix file handling. | |||
| 110 | * | |||
| 111 | * @param[in] url The url to encode. | |||
| 112 | * @param[out] path_out A string containing the result path which should | |||
| 113 | * be freed by the caller. | |||
| 114 | * @return NSERROR_OK and the path is written to \a path or error code | |||
| 115 | * on faliure. | |||
| 116 | */ | |||
| 117 | static nserror posix_nsurl_to_path(struct nsurl *url, char **path_out) | |||
| 118 | { | |||
| 119 | lwc_string *urlpath; | |||
| 120 | char *path; | |||
| 121 | bool_Bool match; | |||
| 122 | lwc_string *scheme; | |||
| 123 | nserror res; | |||
| 124 | ||||
| 125 | if ((url == NULL((void*)0)) || (path_out == NULL((void*)0))) { | |||
| 126 | return NSERROR_BAD_PARAMETER; | |||
| 127 | } | |||
| 128 | ||||
| 129 | scheme = nsurl_get_component(url, NSURL_SCHEME); | |||
| 130 | ||||
| 131 | if (lwc_string_caseless_isequal(scheme, corestring_lwc_file,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (scheme); lwc_string *__lwc_str2 = (corestring_lwc_file); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1 ); } if (__lwc_err == lwc_error_ok && __lwc_str2-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) | |||
| 132 | &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1 = (scheme); lwc_string *__lwc_str2 = (corestring_lwc_file); _Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1 ); } if (__lwc_err == lwc_error_ok && __lwc_str2-> insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string (__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = ( __lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err ; }) != lwc_error_ok) | |||
| 133 | { | |||
| 134 | return NSERROR_BAD_PARAMETER; | |||
| 135 | } | |||
| 136 | lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); if (__lwc_s != ((void*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) || ((__lwc_s ->refcnt == 1) && (__lwc_s->insensitive == __lwc_s ))) lwc_string_destroy(__lwc_s); } }; | |||
| 137 | if (match == false0) { | |||
| 138 | return NSERROR_BAD_PARAMETER; | |||
| 139 | } | |||
| 140 | ||||
| 141 | urlpath = nsurl_get_component(url, NSURL_PATH); | |||
| 142 | if (urlpath == NULL((void*)0)) { | |||
| 143 | return NSERROR_BAD_PARAMETER; | |||
| 144 | } | |||
| 145 | ||||
| 146 | res = url_unescape(lwc_string_data(urlpath)({((urlpath != ((void*)0)) ? (void) (0) : __assert_fail ("urlpath != NULL" , "utils/file.c", 146, __extension__ __PRETTY_FUNCTION__)); ( const char *)((urlpath)+1);}), | |||
| 147 | lwc_string_length(urlpath)({((urlpath != ((void*)0)) ? (void) (0) : __assert_fail ("urlpath != NULL" , "utils/file.c", 147, __extension__ __PRETTY_FUNCTION__)); ( urlpath)->len;}), | |||
| 148 | NULL((void*)0), | |||
| 149 | &path); | |||
| 150 | lwc_string_unref(urlpath){ lwc_string *__lwc_s = (urlpath); if (__lwc_s != ((void*)0)) { __lwc_s->refcnt--; if ((__lwc_s->refcnt == 0) || ((__lwc_s ->refcnt == 1) && (__lwc_s->insensitive == __lwc_s ))) lwc_string_destroy(__lwc_s); } }; | |||
| 151 | if (res != NSERROR_OK) { | |||
| 152 | return res; | |||
| 153 | } | |||
| 154 | ||||
| 155 | *path_out = path; | |||
| 156 | ||||
| 157 | return NSERROR_OK; | |||
| 158 | } | |||
| 159 | ||||
| 160 | /** | |||
| 161 | * Create a nsurl from a path using posix file handling. | |||
| 162 | * | |||
| 163 | * Perform the necessary operations on a path to generate a nsurl. | |||
| 164 | * | |||
| 165 | * @param[in] path The path to convert. | |||
| 166 | * @param[out] url_out pointer to recive the nsurl, The returned url | |||
| 167 | * should be unreferenced by the caller. | |||
| 168 | * @return NSERROR_OK and the url is placed in \a url or error code on | |||
| 169 | * faliure. | |||
| 170 | */ | |||
| 171 | static nserror posix_path_to_nsurl(const char *path, struct nsurl **url_out) | |||
| 172 | { | |||
| 173 | nserror ret; | |||
| 174 | int urllen; | |||
| 175 | char *urlstr; | |||
| 176 | char *escpath; /* escaped version of the path */ | |||
| 177 | char *escpaths; | |||
| 178 | ||||
| 179 | if ((path == NULL((void*)0)) || (url_out == NULL((void*)0)) || (*path == 0)) { | |||
| 180 | return NSERROR_BAD_PARAMETER; | |||
| 181 | } | |||
| 182 | ||||
| 183 | /* escape the path so it can be placed in a url */ | |||
| 184 | ret = url_escape(path, false0, "/", &escpath); | |||
| 185 | if (ret != NSERROR_OK) { | |||
| 186 | return ret; | |||
| 187 | } | |||
| 188 | /* remove unecessary / as file: paths are already absolute */ | |||
| 189 | escpaths = escpath; | |||
| 190 | while (*escpaths == '/') { | |||
| 191 | escpaths++; | |||
| 192 | } | |||
| 193 | ||||
| 194 | /* build url as a string for nsurl constructor */ | |||
| 195 | urllen = strlen(escpaths) + FILE_SCHEME_PREFIX_LEN8 + 1; | |||
| 196 | urlstr = malloc(urllen); | |||
| 197 | if (urlstr == NULL((void*)0)) { | |||
| 198 | free(escpath); | |||
| 199 | return NSERROR_NOMEM; | |||
| 200 | } | |||
| 201 | ||||
| 202 | snprintf(urlstr, urllen, "%s%s", FILE_SCHEME_PREFIX"file:///", escpaths); | |||
| 203 | free(escpath); | |||
| 204 | ||||
| 205 | ret = nsurl_create(urlstr, url_out); | |||
| 206 | free(urlstr); | |||
| 207 | ||||
| 208 | return ret; | |||
| 209 | } | |||
| 210 | ||||
| 211 | /** | |||
| 212 | * Ensure that all directory elements needed to store a filename exist. | |||
| 213 | * | |||
| 214 | * @param fname The filename to ensure the path to exists. | |||
| 215 | * @return NSERROR_OK on success or error code on failure. | |||
| 216 | */ | |||
| 217 | static nserror posix_mkdir_all(const char *fname) | |||
| 218 | { | |||
| 219 | char *dname; | |||
| 220 | char *sep; | |||
| 221 | struct stat sb; | |||
| 222 | ||||
| 223 | dname = strdup(fname); | |||
| 224 | ||||
| 225 | sep = strrchr(dname, '/'); | |||
| 226 | if (sep == NULL((void*)0)) { | |||
| 227 | /* no directory separator path is just filename so its ok */ | |||
| 228 | free(dname); | |||
| 229 | return NSERROR_OK; | |||
| 230 | } | |||
| 231 | ||||
| 232 | *sep = 0; /* null terminate directory path */ | |||
| 233 | ||||
| 234 | if (stat(dname, &sb) == 0) { | |||
| 235 | free(dname); | |||
| 236 | if (S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) { | |||
| 237 | /* path to file exists and is a directory */ | |||
| 238 | return NSERROR_OK; | |||
| 239 | } | |||
| 240 | return NSERROR_NOT_DIRECTORY; | |||
| 241 | } | |||
| 242 | *sep = '/'; /* restore separator */ | |||
| 243 | ||||
| 244 | sep = dname; | |||
| 245 | while (*sep == '/') { | |||
| 246 | sep++; | |||
| 247 | } | |||
| 248 | while ((sep = strchr(sep, '/')) != NULL((void*)0)) { | |||
| 249 | *sep = 0; | |||
| 250 | if (stat(dname, &sb) != 0) { | |||
| 251 | if (nsmkdir(dname, S_IRWXU)mkdir((dname), ((0400|0200|0100))) != 0) { | |||
| 252 | /* could not create path element */ | |||
| 253 | free(dname); | |||
| 254 | return NSERROR_NOT_FOUND; | |||
| 255 | } | |||
| 256 | } else { | |||
| 257 | if (! S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) { | |||
| 258 | /* path element not a directory */ | |||
| 259 | free(dname); | |||
| 260 | return NSERROR_NOT_DIRECTORY; | |||
| 261 | } | |||
| 262 | } | |||
| 263 | *sep = '/'; /* restore separator */ | |||
| 264 | /* skip directory separators */ | |||
| 265 | while (*sep == '/') { | |||
| 266 | sep++; | |||
| 267 | } | |||
| 268 | } | |||
| 269 | ||||
| 270 | free(dname); | |||
| 271 | return NSERROR_OK; | |||
| 272 | } | |||
| 273 | ||||
| 274 | /** | |||
| 275 | * default to using the posix file handling | |||
| 276 | */ | |||
| 277 | static struct gui_file_table file_table = { | |||
| 278 | .mkpath = posix_vmkpath, | |||
| 279 | .basename = posix_basename, | |||
| 280 | .nsurl_to_path = posix_nsurl_to_path, | |||
| 281 | .path_to_nsurl = posix_path_to_nsurl, | |||
| 282 | .mkdir_all = posix_mkdir_all, | |||
| 283 | }; | |||
| 284 | ||||
| 285 | struct gui_file_table *default_file_table = &file_table; | |||
| 286 | ||||
| 287 | /* exported interface documented in utils/file.h */ | |||
| 288 | nserror netsurf_mkpath(char **str, size_t *size, size_t nelm, ...) | |||
| 289 | { | |||
| 290 | va_list ap; | |||
| 291 | nserror ret; | |||
| 292 | ||||
| 293 | va_start(ap, nelm)__builtin_va_start(ap, nelm); | |||
| 294 | ret = guit->file->mkpath(str, size, nelm, ap); | |||
| 295 | va_end(ap)__builtin_va_end(ap); | |||
| 296 | ||||
| 297 | return ret; | |||
| 298 | } | |||
| 299 | ||||
| 300 | /* exported interface documented in utils/file.h */ | |||
| 301 | nserror netsurf_nsurl_to_path(struct nsurl *url, char **path_out) | |||
| 302 | { | |||
| 303 | return guit->file->nsurl_to_path(url, path_out); | |||
| 304 | } | |||
| 305 | ||||
| 306 | /* exported interface documented in utils/file.h */ | |||
| 307 | nserror netsurf_path_to_nsurl(const char *path, struct nsurl **url) | |||
| 308 | { | |||
| 309 | return guit->file->path_to_nsurl(path, url); | |||
| 310 | } | |||
| 311 | ||||
| 312 | /* exported interface documented in utils/file.h */ | |||
| 313 | nserror netsurf_mkdir_all(const char *fname) | |||
| 314 | { | |||
| 315 | return guit->file->mkdir_all(fname); | |||
| 316 | } | |||
| 317 | ||||
| 318 | /* exported interface documented in utils/file.h */ | |||
| 319 | nserror | |||
| 320 | netsurf_recursive_rm(const char *path) | |||
| ||||
| 321 | { | |||
| 322 | DIR *parent; | |||
| 323 | struct dirent *entry; | |||
| 324 | nserror ret = NSERROR_OK; | |||
| 325 | struct stat ent_stat; /* stat result of leaf entry */ | |||
| 326 | ||||
| 327 | parent = opendir(path); | |||
| 328 | if (parent
| |||
| 329 | switch (errno(*__errno_location ())) { | |||
| 330 | case ENOENT2: | |||
| 331 | return NSERROR_NOT_FOUND; | |||
| 332 | default: | |||
| 333 | return NSERROR_UNKNOWN; | |||
| 334 | } | |||
| 335 | } | |||
| 336 | ||||
| 337 | while ((entry = readdir(parent))) { | |||
| 338 | char *leafpath = NULL((void*)0); | |||
| 339 | ||||
| 340 | if (strcmp(entry->d_name, ".") == 0 || | |||
| 341 | strcmp(entry->d_name, "..") == 0) | |||
| 342 | continue; | |||
| 343 | ||||
| 344 | ret = netsurf_mkpath(&leafpath, NULL((void*)0), 2, path, entry->d_name); | |||
| 345 | if (ret != NSERROR_OK) | |||
| 346 | goto out; | |||
| 347 | ||||
| 348 | #if (defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)) | |||
| 349 | if (fstatat(dirfd(parent), entry->d_name, &ent_stat, | |||
| ||||
| 350 | AT_SYMLINK_NOFOLLOW0x100) != 0) { | |||
| 351 | #else | |||
| 352 | if (stat(leafpath, &ent_stat) != 0) { | |||
| 353 | #endif | |||
| 354 | free(leafpath); | |||
| 355 | goto out_via_errno; | |||
| 356 | } | |||
| 357 | if (S_ISDIR(ent_stat.st_mode)((((ent_stat.st_mode)) & 0170000) == (0040000))) { | |||
| 358 | ret = netsurf_recursive_rm(leafpath); | |||
| 359 | if (ret != NSERROR_OK) { | |||
| 360 | free(leafpath); | |||
| 361 | goto out; | |||
| 362 | } | |||
| 363 | } else { | |||
| 364 | #if (defined(HAVE_DIRFD) && defined(HAVE_UNLINKAT)) | |||
| 365 | if (unlinkat(dirfd(parent), entry->d_name, 0) != 0) { | |||
| 366 | #else | |||
| 367 | if (unlink(leafpath) != 0) { | |||
| 368 | #endif | |||
| 369 | free(leafpath); | |||
| 370 | goto out_via_errno; | |||
| 371 | } | |||
| 372 | } | |||
| 373 | ||||
| 374 | free(leafpath); | |||
| 375 | } | |||
| 376 | ||||
| 377 | if (rmdir(path) != 0) { | |||
| 378 | goto out_via_errno; | |||
| 379 | } | |||
| 380 | ||||
| 381 | goto out; | |||
| 382 | ||||
| 383 | out_via_errno: | |||
| 384 | switch (errno(*__errno_location ())) { | |||
| 385 | case ENOENT2: | |||
| 386 | ret = NSERROR_NOT_FOUND; | |||
| 387 | break; | |||
| 388 | default: | |||
| 389 | ret = NSERROR_UNKNOWN; | |||
| 390 | } | |||
| 391 | out: | |||
| 392 | closedir(parent); | |||
| 393 | ||||
| 394 | return ret; | |||
| 395 | } |