curl_fopen.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. #if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \
  26. !defined(CURL_DISABLE_HSTS)
  27. #include "urldata.h"
  28. #include "rand.h"
  29. #include "curl_fopen.h"
  30. /* The last 2 #include files should be in this order */
  31. #include "curl_memory.h"
  32. #include "memdebug.h"
  33. /*
  34. The dirslash() function breaks a null-terminated pathname string into
  35. directory and filename components then returns the directory component up
  36. to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
  37. this instead returns a "" string.
  38. This function returns a pointer to malloc'ed memory.
  39. The input path to this function is expected to have a filename part.
  40. */
  41. #ifdef _WIN32
  42. #define PATHSEP "\\"
  43. #define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
  44. #elif defined(MSDOS) || defined(OS2)
  45. #define PATHSEP "\\"
  46. #define IS_SEP(x) ((x) == '\\')
  47. #else
  48. #define PATHSEP "/"
  49. #define IS_SEP(x) ((x) == '/')
  50. #endif
  51. static char *dirslash(const char *path)
  52. {
  53. size_t n;
  54. struct dynbuf out;
  55. DEBUGASSERT(path);
  56. curlx_dyn_init(&out, CURL_MAX_INPUT_LENGTH);
  57. n = strlen(path);
  58. if(n) {
  59. /* find the rightmost path separator, if any */
  60. while(n && !IS_SEP(path[n-1]))
  61. --n;
  62. /* skip over all the path separators, if any */
  63. while(n && IS_SEP(path[n-1]))
  64. --n;
  65. }
  66. if(curlx_dyn_addn(&out, path, n))
  67. return NULL;
  68. /* if there was a directory, append a single trailing slash */
  69. if(n && curlx_dyn_addn(&out, PATHSEP, 1))
  70. return NULL;
  71. return curlx_dyn_ptr(&out);
  72. }
  73. /*
  74. * Curl_fopen() opens a file for writing with a temp name, to be renamed
  75. * to the final name when completed. If there is an existing file using this
  76. * name at the time of the open, this function will clone the mode from that
  77. * file. if 'tempname' is non-NULL, it needs a rename after the file is
  78. * written.
  79. */
  80. CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
  81. FILE **fh, char **tempname)
  82. {
  83. CURLcode result = CURLE_WRITE_ERROR;
  84. unsigned char randbuf[41];
  85. char *tempstore = NULL;
  86. struct_stat sb;
  87. int fd = -1;
  88. char *dir = NULL;
  89. *tempname = NULL;
  90. *fh = curlx_fopen(filename, FOPEN_WRITETEXT);
  91. if(!*fh)
  92. goto fail;
  93. if(
  94. #ifdef UNDER_CE
  95. /* !checksrc! disable BANNEDFUNC 1 */
  96. stat(filename, &sb) == -1
  97. #else
  98. fstat(fileno(*fh), &sb) == -1
  99. #endif
  100. || !S_ISREG(sb.st_mode)) {
  101. return CURLE_OK;
  102. }
  103. curlx_fclose(*fh);
  104. *fh = NULL;
  105. result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
  106. if(result)
  107. goto fail;
  108. dir = dirslash(filename);
  109. if(dir) {
  110. /* The temp filename should not end up too long for the target file
  111. system */
  112. tempstore = curl_maprintf("%s%s.tmp", dir, randbuf);
  113. free(dir);
  114. }
  115. if(!tempstore) {
  116. result = CURLE_OUT_OF_MEMORY;
  117. goto fail;
  118. }
  119. result = CURLE_WRITE_ERROR;
  120. #if (defined(ANDROID) || defined(__ANDROID__)) && \
  121. (defined(__i386__) || defined(__arm__))
  122. fd = curlx_open(tempstore, O_WRONLY | O_CREAT | O_EXCL,
  123. (mode_t)(0600 | sb.st_mode));
  124. #else
  125. fd = curlx_open(tempstore, O_WRONLY | O_CREAT | O_EXCL,
  126. 0600 | sb.st_mode);
  127. #endif
  128. if(fd == -1)
  129. goto fail;
  130. *fh = curlx_fdopen(fd, FOPEN_WRITETEXT);
  131. if(!*fh)
  132. goto fail;
  133. *tempname = tempstore;
  134. return CURLE_OK;
  135. fail:
  136. if(fd != -1) {
  137. close(fd);
  138. unlink(tempstore);
  139. }
  140. free(tempstore);
  141. return result;
  142. }
  143. #endif /* ! disabled */