file.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, 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 http://curl.haxx.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. * $Id$
  22. ***************************************************************************/
  23. #include "setup.h"
  24. #ifndef CURL_DISABLE_FILE
  25. /* -- WIN32 approved -- */
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <stdarg.h>
  29. #include <stdlib.h>
  30. #include <ctype.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <errno.h>
  34. #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
  35. #include <time.h>
  36. #include <io.h>
  37. #include <fcntl.h>
  38. #else
  39. #ifdef HAVE_SYS_SOCKET_H
  40. #include <sys/socket.h>
  41. #endif
  42. #ifdef HAVE_NETINET_IN_H
  43. #include <netinet/in.h>
  44. #endif
  45. #include <sys/time.h>
  46. #ifdef HAVE_UNISTD_H
  47. #include <unistd.h>
  48. #endif
  49. #ifdef HAVE_NETDB_H
  50. #include <netdb.h>
  51. #endif
  52. #ifdef HAVE_ARPA_INET_H
  53. #include <arpa/inet.h>
  54. #endif
  55. #ifdef HAVE_NET_IF_H
  56. #include <net/if.h>
  57. #endif
  58. #include <sys/ioctl.h>
  59. #include <signal.h>
  60. #ifdef HAVE_SYS_PARAM_H
  61. #include <sys/param.h>
  62. #endif
  63. #ifdef HAVE_SYS_STAT_H
  64. #include <sys/stat.h>
  65. #endif
  66. #ifdef HAVE_FCNTL_H
  67. #include <fcntl.h>
  68. #endif
  69. #endif
  70. #include "urldata.h"
  71. #include <curl/curl.h>
  72. #include "progress.h"
  73. #include "sendf.h"
  74. #include "escape.h"
  75. #include "file.h"
  76. #include "speedcheck.h"
  77. #include "getinfo.h"
  78. #include "transfer.h" /* for Curl_readwrite_init() */
  79. #define _MPRINTF_REPLACE /* use our functions only */
  80. #include <curl/mprintf.h>
  81. /* The last #include file should be: */
  82. #ifdef CURLDEBUG
  83. #include "memdebug.h"
  84. #endif
  85. /* Emulate a connect-then-transfer protocol. We connect to the file here */
  86. CURLcode Curl_file_connect(struct connectdata *conn)
  87. {
  88. char *real_path = curl_unescape(conn->path, 0);
  89. struct FILEPROTO *file;
  90. int fd;
  91. #if defined(WIN32) || defined(__EMX__)
  92. int i;
  93. char *actual_path;
  94. #endif
  95. file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1);
  96. if(!file)
  97. return CURLE_OUT_OF_MEMORY;
  98. conn->proto.file = file;
  99. #if defined(WIN32) || defined(__EMX__)
  100. /* If the first character is a slash, and there's
  101. something that looks like a drive at the beginning of
  102. the path, skip the slash. If we remove the initial
  103. slash in all cases, paths without drive letters end up
  104. relative to the current directory which isn't how
  105. browsers work.
  106. Some browsers accept | instead of : as the drive letter
  107. separator, so we do too.
  108. On other platforms, we need the slash to indicate an
  109. absolute pathname. On Windows, absolute paths start
  110. with a drive letter.
  111. */
  112. actual_path = real_path;
  113. if ((actual_path[0] == '/') &&
  114. actual_path[1] &&
  115. (actual_path[2] == ':' || actual_path[2] == '|'))
  116. {
  117. actual_path[2] = ':';
  118. actual_path++;
  119. }
  120. /* change path separators from '/' to '\\' for Windows and OS/2 */
  121. for (i=0; actual_path[i] != '\0'; ++i)
  122. if (actual_path[i] == '/')
  123. actual_path[i] = '\\';
  124. fd = open(actual_path, O_RDONLY | O_BINARY); /* no CR/LF translation! */
  125. #else
  126. fd = open(real_path, O_RDONLY);
  127. #endif
  128. free(real_path);
  129. if(fd == -1) {
  130. failf(conn->data, "Couldn't open file %s", conn->path);
  131. return CURLE_FILE_COULDNT_READ_FILE;
  132. }
  133. file->fd = fd;
  134. return CURLE_OK;
  135. }
  136. #if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
  137. #define lseek(x,y,z) _lseeki64(x, y, z)
  138. #endif
  139. /* This is the do-phase, separated from the connect-phase above */
  140. CURLcode Curl_file(struct connectdata *conn)
  141. {
  142. /* This implementation ignores the host name in conformance with
  143. RFC 1738. Only local files (reachable via the standard file system)
  144. are supported. This means that files on remotely mounted directories
  145. (via NFS, Samba, NT sharing) can be accessed through a file:// URL
  146. */
  147. CURLcode res = CURLE_OK;
  148. struct stat statbuf;
  149. curl_off_t expected_size=0;
  150. bool fstated=FALSE;
  151. ssize_t nread;
  152. struct SessionHandle *data = conn->data;
  153. char *buf = data->state.buffer;
  154. curl_off_t bytecount = 0;
  155. int fd;
  156. struct timeval now = Curl_tvnow();
  157. Curl_readwrite_init(conn);
  158. Curl_initinfo(data);
  159. Curl_pgrsStartNow(data);
  160. /* get the fd from the connection phase */
  161. fd = conn->proto.file->fd;
  162. /* VMS: This only works reliable for STREAMLF files */
  163. if( -1 != fstat(fd, &statbuf)) {
  164. /* we could stat it, then read out the size */
  165. expected_size = statbuf.st_size;
  166. fstated = TRUE;
  167. }
  168. /* If we have selected NOBODY and HEADER, it means that we only want file
  169. information. Which for FILE can't be much more than the file size and
  170. date. */
  171. if(data->set.no_body && data->set.include_header && fstated) {
  172. CURLcode result;
  173. sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
  174. result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
  175. if(result)
  176. return result;
  177. sprintf(buf, "Accept-ranges: bytes\r\n");
  178. result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
  179. if(result)
  180. return result;
  181. #ifdef HAVE_STRFTIME
  182. if(fstated) {
  183. struct tm *tm;
  184. time_t clock = (time_t)statbuf.st_mtime;
  185. #ifdef HAVE_GMTIME_R
  186. struct tm buffer;
  187. tm = (struct tm *)gmtime_r(&clock, &buffer);
  188. #else
  189. tm = gmtime(&clock);
  190. #endif
  191. /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
  192. strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
  193. tm);
  194. result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
  195. }
  196. #endif
  197. return result;
  198. }
  199. /* Added by Dolbneff A.V & Spiridonoff A.V */
  200. if (conn->resume_from <= expected_size)
  201. expected_size -= conn->resume_from;
  202. else
  203. /* Is this error code suitable in such situation? */
  204. return CURLE_FTP_BAD_DOWNLOAD_RESUME;
  205. if (fstated && (expected_size == 0))
  206. return CURLE_OK;
  207. /* The following is a shortcut implementation of file reading
  208. this is both more efficient than the former call to download() and
  209. it avoids problems with select() and recv() on file descriptors
  210. in Winsock */
  211. if(fstated)
  212. Curl_pgrsSetDownloadSize(data, expected_size);
  213. if(conn->resume_from)
  214. lseek(fd, conn->resume_from, SEEK_SET);
  215. Curl_pgrsTime(data, TIMER_STARTTRANSFER);
  216. while (res == CURLE_OK) {
  217. nread = read(fd, buf, BUFSIZE-1);
  218. if ( nread > 0)
  219. buf[nread] = 0;
  220. if (nread <= 0)
  221. break;
  222. bytecount += nread;
  223. /* NOTE: The following call to fwrite does CR/LF translation on
  224. Windows systems if the target is stdout. Use -O or -o parameters
  225. to prevent CR/LF translation (this then goes to a binary mode
  226. file descriptor). */
  227. res = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
  228. if(res)
  229. return res;
  230. Curl_pgrsSetDownloadCounter(data, bytecount);
  231. if(Curl_pgrsUpdate(conn))
  232. res = CURLE_ABORTED_BY_CALLBACK;
  233. else
  234. res = Curl_speedcheck (data, now);
  235. }
  236. if(Curl_pgrsUpdate(conn))
  237. res = CURLE_ABORTED_BY_CALLBACK;
  238. close(fd);
  239. return res;
  240. }
  241. #endif