From 3c2b97abe0bb936ea8dd37c56b1b27a63c46b9e7 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sat, 28 Sep 2013 15:25:41 +0000 Subject: [PATCH] [WININET] * Sync with Wine 1.7.1. CORE-7469 svn path=/trunk/; revision=60428 --- reactos/dll/win32/wininet/CMakeLists.txt | 5 +- reactos/dll/win32/wininet/cookie.c | 30 +- reactos/dll/win32/wininet/http.c | 595 ++-- reactos/dll/win32/wininet/internet.c | 75 +- reactos/dll/win32/wininet/internet.h | 25 +- reactos/dll/win32/wininet/netconnection.c | 868 +++--- reactos/dll/win32/wininet/rsrc.rc | 2 + reactos/dll/win32/wininet/urlcache.c | 3181 +++++++++------------ reactos/dll/win32/wininet/version.rc | 2 +- reactos/media/doc/README.WINE | 2 +- 10 files changed, 2206 insertions(+), 2579 deletions(-) diff --git a/reactos/dll/win32/wininet/CMakeLists.txt b/reactos/dll/win32/wininet/CMakeLists.txt index 9819057ae5d..f7e449c3e02 100644 --- a/reactos/dll/win32/wininet/CMakeLists.txt +++ b/reactos/dll/win32/wininet/CMakeLists.txt @@ -20,13 +20,10 @@ list(APPEND SOURCE urlcache.c utility.c wininet_main.c - rsrc.rc - version.rc ${CMAKE_CURRENT_BINARY_DIR}/wininet_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/wininet.def) -add_library(wininet SHARED ${SOURCE}) - +add_library(wininet SHARED ${SOURCE} rsrc.rc) set_module_type(wininet win32dll) target_link_libraries(wininet wine ${PSEH_LIB} zlib) add_delay_importlibs(wininet secur32 crypt32 cryptui) diff --git a/reactos/dll/win32/wininet/cookie.c b/reactos/dll/win32/wininet/cookie.c index 443d7a6eadd..642e00908fa 100644 --- a/reactos/dll/win32/wininet/cookie.c +++ b/reactos/dll/win32/wininet/cookie.c @@ -238,6 +238,7 @@ static BOOL load_persistent_cookie(LPCWSTR domain, LPCWSTR path) heap_free(name); heap_free(data); } + heap_free(str); heap_free(name); heap_free(data); @@ -537,8 +538,11 @@ static void COOKIE_deleteDomain(cookie_domain *deadDomain) DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD *size) { + static const WCHAR empty_path[] = { '/',0 }; + unsigned cnt = 0, len, name_len, domain_count = 0, cookie_count = 0; - WCHAR *ptr = cookie_data; + WCHAR *ptr, subpath[INTERNET_MAX_PATH_LENGTH]; + const WCHAR *p; cookie_domain *domain; FILETIME tm; @@ -546,8 +550,30 @@ DWORD get_cookie(const WCHAR *host, const WCHAR *path, WCHAR *cookie_data, DWORD EnterCriticalSection(&cookie_cs); - load_persistent_cookie(host, path); + len = strlenW(host); + p = host+len; + while(p>host && p[-1]!='.') p--; + while(p != host) { + p--; + while(p>host && p[-1]!='.') p--; + if(p == host) break; + + load_persistent_cookie(p, empty_path); + } + + len = strlenW(path); + assert(len+1 < INTERNET_MAX_PATH_LENGTH); + memcpy(subpath, path, (len+1)*sizeof(WCHAR)); + ptr = subpath+len; + do { + *ptr = 0; + load_persistent_cookie(host, subpath); + + ptr--; + while(ptr>subpath && ptr[-1]!='/') ptr--; + }while(ptr != subpath); + ptr = cookie_data; LIST_FOR_EACH_ENTRY(domain, &domain_list, cookie_domain, entry) { struct list *cursor, *cursor2; diff --git a/reactos/dll/win32/wininet/http.c b/reactos/dll/win32/wininet/http.c index 6ba6d264a29..d1fc6d52983 100644 --- a/reactos/dll/win32/wininet/http.c +++ b/reactos/dll/win32/wininet/http.c @@ -148,6 +148,8 @@ static const WCHAR szVia[] = { 'V','i','a',0 }; static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 }; static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 }; +static const WCHAR emptyW[] = {0}; + #define HTTP_REFERER szReferer #define HTTP_ACCEPT szAccept #define HTTP_USERAGENT szUser_Agent @@ -214,7 +216,7 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; -static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear); +static DWORD HTTP_GetResponseHeaders(http_request_t *req, INT *len); static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier); static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer); static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr); @@ -597,62 +599,10 @@ static DWORD init_gzip_stream(http_request_t *req) #endif -/*********************************************************************** - * HTTP_Tokenize (internal) - * - * Tokenize a string, allocating memory for the tokens. - */ -static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string) -{ - LPWSTR * token_array; - int tokens = 0; - int i; - LPCWSTR next_token; - - if (string) - { - /* empty string has no tokens */ - if (*string) - tokens++; - /* count tokens */ - for (i = 0; string[i]; i++) - { - if (!strncmpW(string+i, token_string, strlenW(token_string))) - { - DWORD j; - tokens++; - /* we want to skip over separators, but not the null terminator */ - for (j = 0; j < strlenW(token_string) - 1; j++) - if (!string[i+j]) - break; - i += j; - } - } - } - - /* add 1 for terminating NULL */ - token_array = heap_alloc((tokens+1) * sizeof(*token_array)); - token_array[tokens] = NULL; - if (!tokens) - return token_array; - for (i = 0; i < tokens; i++) - { - int len; - next_token = strstrW(string, token_string); - if (!next_token) next_token = string+strlenW(string); - len = next_token - string; - token_array[i] = heap_alloc((len+1)*sizeof(WCHAR)); - memcpy(token_array[i], string, len*sizeof(WCHAR)); - token_array[i][len] = '\0'; - string = next_token+strlenW(token_string); - } - return token_array; -} - /*********************************************************************** * HTTP_FreeTokens (internal) * - * Frees memory returned from HTTP_Tokenize. + * Frees table of pointers. */ static void HTTP_FreeTokens(LPWSTR * token_array) { @@ -696,20 +646,21 @@ static void HTTP_FixURL(http_request_t *request) } } -static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *request, LPCWSTR verb, LPCWSTR path, LPCWSTR version ) +static WCHAR* build_request_header(http_request_t *request, const WCHAR *verb, + const WCHAR *path, const WCHAR *version, BOOL use_cr) { LPWSTR requestString; DWORD len, n; LPCWSTR *req; UINT i; - LPWSTR p; static const WCHAR szSpace[] = { ' ',0 }; static const WCHAR szColon[] = { ':',' ',0 }; - static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0}; + static const WCHAR szCr[] = { '\r',0 }; + static const WCHAR szLf[] = { '\n',0 }; /* allocate space for an array of all the string pointers to be added */ - len = (request->nCustHeaders)*4 + 10; + len = (request->nCustHeaders)*5 + 10; req = heap_alloc(len*sizeof(LPCWSTR)); /* add the verb, path and HTTP version string */ @@ -719,42 +670,90 @@ static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *request, LPCWSTR ve req[n++] = path; req[n++] = szSpace; req[n++] = version; + if (use_cr) + req[n++] = szCr; + req[n++] = szLf; /* Append custom request headers */ for (i = 0; i < request->nCustHeaders; i++) { if (request->custHeaders[i].wFlags & HDR_ISREQUEST) { - req[n++] = szCrLf; req[n++] = request->custHeaders[i].lpszField; req[n++] = szColon; req[n++] = request->custHeaders[i].lpszValue; + if (use_cr) + req[n++] = szCr; + req[n++] = szLf; TRACE("Adding custom header %s (%s)\n", debugstr_w(request->custHeaders[i].lpszField), debugstr_w(request->custHeaders[i].lpszValue)); } } - - if( n >= len ) - ERR("oops. buffer overrun\n"); - + if (use_cr) + req[n++] = szCr; + req[n++] = szLf; req[n] = NULL; + requestString = HTTP_build_req( req, 4 ); heap_free( req ); - - /* - * Set (header) termination string for request - * Make sure there's exactly two new lines at the end of the request - */ - p = &requestString[strlenW(requestString)-1]; - while ( (*p == '\n') || (*p == '\r') ) - p--; - strcpyW( p+1, sztwocrlf ); - return requestString; } +static WCHAR* build_response_header(http_request_t *request, BOOL use_cr) +{ + static const WCHAR colonW[] = { ':',' ',0 }; + static const WCHAR crW[] = { '\r',0 }; + static const WCHAR lfW[] = { '\n',0 }; + static const WCHAR status_fmt[] = { ' ','%','u',' ',0 }; + + const WCHAR **req; + WCHAR *ret, buf[14]; + DWORD i, n = 0; + + req = heap_alloc((request->nCustHeaders*5+8)*sizeof(WCHAR*)); + if(!req) + return NULL; + + if (request->status_code) + { + req[n++] = request->version; + sprintfW(buf, status_fmt, request->status_code); + req[n++] = buf; + req[n++] = request->statusText; + if (use_cr) + req[n++] = crW; + req[n++] = lfW; + } + + for(i = 0; i < request->nCustHeaders; i++) + { + if(!(request->custHeaders[i].wFlags & HDR_ISREQUEST) + && strcmpW(request->custHeaders[i].lpszField, szStatus)) + { + req[n++] = request->custHeaders[i].lpszField; + req[n++] = colonW; + req[n++] = request->custHeaders[i].lpszValue; + if(use_cr) + req[n++] = crW; + req[n++] = lfW; + + TRACE("Adding custom header %s (%s)\n", + debugstr_w(request->custHeaders[i].lpszField), + debugstr_w(request->custHeaders[i].lpszValue)); + } + } + if(use_cr) + req[n++] = crW; + req[n++] = lfW; + req[n] = NULL; + + ret = HTTP_build_req(req, 0); + heap_free(req); + return ret; +} + static void HTTP_ProcessCookies( http_request_t *request ) { int HeaderIndex; @@ -1714,6 +1713,88 @@ static WCHAR *build_proxy_path_url(http_request_t *req) return url; } +static BOOL HTTP_DomainMatches(LPCWSTR server, LPCWSTR domain) +{ + static const WCHAR localW[] = { '<','l','o','c','a','l','>',0 }; + BOOL ret = FALSE; + + if (!strcmpiW( domain, localW ) && !strchrW( server, '.' )) + ret = TRUE; + else if (*domain == '*') + { + if (domain[1] == '.') + { + LPCWSTR dot; + + /* For a hostname to match a wildcard, the last domain must match + * the wildcard exactly. E.g. if the wildcard is *.a.b, and the + * hostname is www.foo.a.b, it matches, but a.b does not. + */ + dot = strchrW( server, '.' ); + if (dot) + { + int len = strlenW( dot + 1 ); + + if (len > strlenW( domain + 2 )) + { + LPCWSTR ptr; + + /* The server's domain is longer than the wildcard, so it + * could be a subdomain. Compare the last portion of the + * server's domain. + */ + ptr = dot + len + 1 - strlenW( domain + 2 ); + if (!strcmpiW( ptr, domain + 2 )) + { + /* This is only a match if the preceding character is + * a '.', i.e. that it is a matching domain. E.g. + * if domain is '*.b.c' and server is 'www.ab.c' they + * do not match. + */ + ret = *(ptr - 1) == '.'; + } + } + else + ret = !strcmpiW( dot + 1, domain + 2 ); + } + } + } + else + ret = !strcmpiW( server, domain ); + return ret; +} + +static BOOL HTTP_ShouldBypassProxy(appinfo_t *lpwai, LPCWSTR server) +{ + LPCWSTR ptr; + BOOL ret = FALSE; + + if (!lpwai->proxyBypass) return FALSE; + ptr = lpwai->proxyBypass; + do { + LPCWSTR tmp = ptr; + + ptr = strchrW( ptr, ';' ); + if (!ptr) + ptr = strchrW( tmp, ' ' ); + if (ptr) + { + if (ptr - tmp < INTERNET_MAX_HOST_NAME_LENGTH) + { + WCHAR domain[INTERNET_MAX_HOST_NAME_LENGTH]; + + memcpy( domain, tmp, (ptr - tmp) * sizeof(WCHAR) ); + domain[ptr - tmp] = 0; + ret = HTTP_DomainMatches( server, domain ); + } + ptr += 1; + } + else if (*tmp) + ret = HTTP_DomainMatches( server, tmp ); + } while (ptr && !ret); + return ret; +} + /*********************************************************************** * HTTP_DealWithProxy */ @@ -1863,7 +1944,6 @@ static void HTTPREQ_Destroy(object_header_t *hdr) heap_free(request->path); heap_free(request->verb); - heap_free(request->rawHeaders); heap_free(request->version); heap_free(request->statusText); @@ -1965,6 +2045,45 @@ static void HTTPREQ_CloseConnection(object_header_t *hdr) http_release_netconn(req, drain_content(req, FALSE)); } +static DWORD str_to_buffer(const WCHAR *str, void *buffer, DWORD *size, BOOL unicode) +{ + int len; + if (unicode) + { + WCHAR *buf = buffer; + + if (str) len = strlenW(str); + else len = 0; + if (*size < (len + 1) * sizeof(WCHAR)) + { + *size = (len + 1) * sizeof(WCHAR); + return ERROR_INSUFFICIENT_BUFFER; + } + if (str) strcpyW(buf, str); + else buf[0] = 0; + + *size = len; + return ERROR_SUCCESS; + } + else + { + char *buf = buffer; + + if (str) len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); + else len = 1; + if (*size < len) + { + *size = len; + return ERROR_INSUFFICIENT_BUFFER; + } + if (str) WideCharToMultiByte(CP_ACP, 0, str, -1, buf, *size, NULL, NULL); + else buf[0] = 0; + + *size = len - 1; + return ERROR_SUCCESS; + } +} + static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode) { http_request_t *req = (http_request_t*)hdr; @@ -1991,7 +2110,7 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe info->Flags |= IDSI_FLAG_KEEP_ALIVE; if (req->proxy) info->Flags |= IDSI_FLAG_PROXY; - if (req->netconn->secure) + if (req->netconn && req->netconn->secure) info->Flags |= IDSI_FLAG_SECURE; return ERROR_SUCCESS; @@ -2028,8 +2147,6 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe case INTERNET_OPTION_URL: { WCHAR url[INTERNET_MAX_URL_LENGTH]; HTTPHEADERW *host; - DWORD len; - WCHAR *pch; static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0}; @@ -2038,29 +2155,21 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe host = HTTP_GetHeader(req, hostW); strcpyW(url, httpW); strcatW(url, host->lpszValue); - if (NULL != (pch = strchrW(url + strlenW(httpW), ':'))) - *pch = 0; strcatW(url, req->path); TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url)); - - if(unicode) { - len = (strlenW(url)+1) * sizeof(WCHAR); - if(*size < len) - return ERROR_INSUFFICIENT_BUFFER; - - *size = len; - strcpyW(buffer, url); - return ERROR_SUCCESS; - }else { - len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL); - if(len > *size) - return ERROR_INSUFFICIENT_BUFFER; - - *size = len; - return ERROR_SUCCESS; - } + return str_to_buffer(url, buffer, size, unicode); } + case INTERNET_OPTION_USER_AGENT: + return str_to_buffer(req->session->appInfo->agent, buffer, size, unicode); + case INTERNET_OPTION_USERNAME: + return str_to_buffer(req->session->userName, buffer, size, unicode); + case INTERNET_OPTION_PASSWORD: + return str_to_buffer(req->session->password, buffer, size, unicode); + case INTERNET_OPTION_PROXY_USERNAME: + return str_to_buffer(req->session->appInfo->proxyUsername, buffer, size, unicode); + case INTERNET_OPTION_PROXY_PASSWORD: + return str_to_buffer(req->session->appInfo->proxyPassword, buffer, size, unicode); case INTERNET_OPTION_CACHE_TIMESTAMPS: { INTERNET_CACHE_ENTRY_INFOW *info; @@ -2129,6 +2238,9 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: { PCCERT_CONTEXT context; + if(!req->netconn) + return ERROR_INTERNET_INVALID_OPERATION; + if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) { *size = sizeof(INTERNET_CERTIFICATE_INFOA); return ERROR_INSUFFICIENT_BUFFER; @@ -2182,7 +2294,7 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe if(req->proxy) flags |= INTERNET_REQFLAG_VIA_PROXY; - if(!req->rawHeaders) + if(!req->status_code) flags |= INTERNET_REQFLAG_NO_HEADERS; TRACE("INTERNET_OPTION_REQUEST_FLAGS returning %x\n", flags); @@ -2248,6 +2360,17 @@ static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, heap_free(req->session->password); if (!(req->session->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; return ERROR_SUCCESS; + + case INTERNET_OPTION_PROXY_USERNAME: + heap_free(req->session->appInfo->proxyUsername); + if (!(req->session->appInfo->proxyUsername = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + + case INTERNET_OPTION_PROXY_PASSWORD: + heap_free(req->session->appInfo->proxyPassword); + if (!(req->session->appInfo->proxyPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + case INTERNET_OPTION_HTTP_DECODING: if(size != sizeof(BOOL)) return ERROR_INVALID_PARAMETER; @@ -2268,12 +2391,15 @@ static void commit_cache_entry(http_request_t *req) req->hCacheFile = NULL; if(HTTP_GetRequestURL(req, url)) { - DWORD headersLen; + WCHAR *header; + DWORD header_len; - headersLen = req->rawHeaders ? strlenW(req->rawHeaders) : 0; + header = build_response_header(req, TRUE); + header_len = (header ? strlenW(header) : 0); CommitUrlCacheEntryW(url, req->cacheFile, req->expires, req->last_modified, NORMAL_CACHE_ENTRY, - req->rawHeaders, headersLen, NULL, 0); + header, header_len, NULL, 0); + heap_free(header); } } @@ -2296,9 +2422,30 @@ static void create_cache_entry(http_request_t *req) if(b) { int header_idx = HTTP_GetCustomHeaderIndex(req, szCache_Control, 0, FALSE); - if(header_idx!=-1 && (!strcmpiW(req->custHeaders[header_idx].lpszValue, no_cacheW) - || !strcmpiW(req->custHeaders[header_idx].lpszValue, no_storeW))) - b = FALSE; + if(header_idx != -1) { + WCHAR *ptr; + + for(ptr=req->custHeaders[header_idx].lpszValue; *ptr; ) { + WCHAR *end; + + while(*ptr==' ' || *ptr=='\t') + ptr++; + + end = strchrW(ptr, ','); + if(!end) + end = ptr + strlenW(ptr); + + if(!strncmpiW(ptr, no_cacheW, sizeof(no_cacheW)/sizeof(*no_cacheW)-1) + || !strncmpiW(ptr, no_storeW, sizeof(no_storeW)/sizeof(*no_storeW)-1)) { + b = FALSE; + break; + } + + ptr = end; + if(*ptr == ',') + ptr++; + } + } } if(!b) { @@ -2372,7 +2519,7 @@ static void remove_data( http_request_t *req, int count ) else req->read_pos += count; } -static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) +static DWORD read_line( http_request_t *req, LPSTR buffer, DWORD *len ) { int count, bytes_read, pos = 0; DWORD res; @@ -2395,13 +2542,18 @@ static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) remove_data( req, bytes_read ); if (eol) break; - if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size) + if ((res = read_more_data( req, -1 ))) + { + WARN( "read failed %u\n", res ); + LeaveCriticalSection( &req->read_section ); + return res; + } + if (!req->read_size) { *len = 0; - TRACE( "returning empty string %u\n", res); + TRACE( "returning empty string\n" ); LeaveCriticalSection( &req->read_section ); - INTERNET_SetLastError(res); - return FALSE; + return ERROR_SUCCESS; } } LeaveCriticalSection( &req->read_section ); @@ -2413,7 +2565,7 @@ static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len ) } buffer[*len - 1] = 0; TRACE( "returning %s\n", debugstr_a(buffer)); - return TRUE; + return ERROR_SUCCESS; } /* check if we have reached the end of the data to read (the read section must be held) */ @@ -2498,6 +2650,7 @@ static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD *read, read_mode_t read_mode) { netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; + DWORD res = ERROR_SUCCESS; int len = 0; size = min(size, netconn_stream->content_length-netconn_stream->content_read); @@ -2509,7 +2662,7 @@ static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, } if(size && req->netconn) { - if(NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len) != ERROR_SUCCESS) + if((res = NETCON_recv(req->netconn, buf, size, read_mode == READMODE_SYNC ? MSG_WAITALL : 0, &len))) len = 0; if(!len) netconn_stream->content_length = netconn_stream->content_read; @@ -2517,7 +2670,7 @@ static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, netconn_stream->content_read += *read = len; TRACE("read %u bytes\n", len); - return ERROR_SUCCESS; + return res; } static BOOL netconn_drain_content(data_stream_t *stream, http_request_t *req) @@ -2787,8 +2940,10 @@ static DWORD set_content_length(http_request_t *request) static const WCHAR gzipW[] = {'g','z','i','p',0}; encoding_idx = HTTP_GetCustomHeaderIndex(request, szContent_Encoding, 0, FALSE); - if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW)) + if(encoding_idx != -1 && !strcmpiW(request->custHeaders[encoding_idx].lpszValue, gzipW)) { + HTTP_DeleteCustomHeader(request, encoding_idx); return init_gzip_stream(request); + } } return ERROR_SUCCESS; @@ -3205,7 +3360,7 @@ static DWORD HTTP_HttpOpenRequestW(http_session_t *session, if (session->hostPort == INTERNET_INVALID_PORT_NUMBER) session->hostPort = INTERNET_DEFAULT_HTTP_PORT; - if (hIC->proxy && hIC->proxy[0]) + if (hIC->proxy && hIC->proxy[0] && !HTTP_ShouldBypassProxy(hIC, session->hostName)) HTTP_DealWithProxy( hIC, session, request ); INTERNET_SendCallback(&session->hdr, dwContext, @@ -3382,13 +3537,13 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, DWORD res = ERROR_INVALID_PARAMETER; if (request_only) - headers = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version); + headers = build_request_header(request, request->verb, request->path, request->version, TRUE); else - headers = request->rawHeaders; - - if (headers) - len = strlenW(headers) * sizeof(WCHAR); + headers = build_response_header(request, TRUE); + if (!headers) + return ERROR_OUTOFMEMORY; + len = strlenW(headers) * sizeof(WCHAR); if (len + sizeof(WCHAR) > *lpdwBufferLength) { len += sizeof(WCHAR); @@ -3396,50 +3551,51 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel, } else if (lpBuffer) { - if (headers) - memcpy(lpBuffer, headers, len + sizeof(WCHAR)); - else - { - len = strlenW(szCrLf) * sizeof(WCHAR); - memcpy(lpBuffer, szCrLf, sizeof(szCrLf)); - } + memcpy(lpBuffer, headers, len + sizeof(WCHAR)); TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR))); res = ERROR_SUCCESS; } *lpdwBufferLength = len; - if (request_only) heap_free(headers); + heap_free(headers); return res; } case HTTP_QUERY_RAW_HEADERS: { - LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(request->rawHeaders, szCrLf); - DWORD i, size = 0; - LPWSTR pszString = lpBuffer; + LPWSTR headers; + DWORD len; - for (i = 0; ppszRawHeaderLines[i]; i++) - size += strlenW(ppszRawHeaderLines[i]) + 1; + if (request_only) + headers = build_request_header(request, request->verb, request->path, request->version, FALSE); + else + headers = build_response_header(request, FALSE); + if (!headers) + return ERROR_OUTOFMEMORY; - if (size + 1 > *lpdwBufferLength/sizeof(WCHAR)) + len = strlenW(headers) * sizeof(WCHAR); + if (len > *lpdwBufferLength) { - HTTP_FreeTokens(ppszRawHeaderLines); - *lpdwBufferLength = (size + 1) * sizeof(WCHAR); + *lpdwBufferLength = len; + heap_free(headers); return ERROR_INSUFFICIENT_BUFFER; } - if (pszString) + + if (lpBuffer) { - for (i = 0; ppszRawHeaderLines[i]; i++) + DWORD i; + + TRACE("returning data: %s\n", debugstr_wn(headers, len / sizeof(WCHAR))); + + for (i=0; iwDayOfWeek = tmpTM.tm_wday; STHook->wMonth = tmpTM.tm_mon + 1; STHook->wSecond = tmpTM.tm_sec; - STHook->wYear = tmpTM.tm_year; + STHook->wYear = 1900+tmpTM.tm_year; TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, @@ -3749,6 +3905,8 @@ BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel, DWORD len; WCHAR* bufferW; + TRACE("%p %x\n", hHttpRequest, dwInfoLevel); + if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) || (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)) { @@ -4027,7 +4185,7 @@ static DWORD HTTP_SecureProxyConnect(http_request_t *request) TRACE("\n"); - requestString = HTTP_BuildHeaderRequestString( request, connectW, server->host_port, g_szHttp1_1 ); + requestString = build_request_header( request, connectW, server->host_port, g_szHttp1_1, TRUE ); len = WideCharToMultiByte( CP_ACP, 0, requestString, -1, NULL, 0, NULL, NULL ); @@ -4044,8 +4202,7 @@ static DWORD HTTP_SecureProxyConnect(http_request_t *request) if (res != ERROR_SUCCESS) return res; - responseLen = HTTP_GetResponseHeaders( request, TRUE ); - if (!responseLen) + if (HTTP_GetResponseHeaders( request, &responseLen ) || !responseLen) return ERROR_HTTP_INVALID_HEADER; return ERROR_SUCCESS; @@ -4596,8 +4753,9 @@ static void http_process_keep_alive(http_request_t *req) { int index; - index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE); - if(index != -1) + if ((index = HTTP_GetCustomHeaderIndex(req, szConnection, 0, FALSE)) != -1) + req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive); + else if ((index = HTTP_GetCustomHeaderIndex(req, szProxy_Connection, 0, FALSE)) != -1) req->netconn->keep_alive = !strcmpiW(req->custHeaders[index].lpszValue, szKeepAlive); else req->netconn->keep_alive = !strcmpiW(req->version, g_szHttp1_1); @@ -4703,7 +4861,6 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, LPWSTR requestString = NULL; INT responseLen; BOOL loop_next; - static const WCHAR szPost[] = { 'P','O','S','T',0 }; static const WCHAR szContentLength[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 }; WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ]; @@ -4741,7 +4898,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, static const WCHAR pragma_nocache[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0}; HTTP_HttpAddRequestHeadersW(request, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW); } - if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(request->verb, szPost)) + if ((request->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && strcmpW(request->verb, szGET)) { static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':', ' ','n','o','-','c','a','c','h','e','\r','\n',0}; @@ -4786,11 +4943,11 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, if (request->proxy) { WCHAR *url = build_proxy_path_url(request); - requestString = HTTP_BuildHeaderRequestString(request, request->verb, url, request->version); + requestString = build_request_header(request, request->verb, url, request->version, TRUE); heap_free(url); } else - requestString = HTTP_BuildHeaderRequestString(request, request->verb, request->path, request->version); + requestString = build_request_header(request, request->verb, request->path, request->version, TRUE); TRACE("Request header -> %s\n", debugstr_w(requestString) ); @@ -4840,7 +4997,12 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - responseLen = HTTP_GetResponseHeaders(request, TRUE); + if (HTTP_GetResponseHeaders(request, &responseLen)) + { + http_release_netconn(request, FALSE); + res = ERROR_INTERNET_CONNECTION_ABORTED; + goto lend; + } /* FIXME: We should know that connection is closed before sending * headers. Otherwise wrong callbacks are executed */ if(!responseLen && reusing_connection) { @@ -4942,6 +5104,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders, request->session->appInfo->proxyPassword, NULL)) { + heap_free(requestString); if(!drain_content(request, TRUE)) { FIXME("Could not drain content\n"); http_release_netconn(request, FALSE); @@ -5033,8 +5196,7 @@ static DWORD HTTP_HttpEndRequestW(http_request_t *request, DWORD dwFlags, DWORD_ INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - responseLen = HTTP_GetResponseHeaders(request, TRUE); - if (!responseLen) + if (HTTP_GetResponseHeaders(request, &responseLen) || !responseLen) res = ERROR_HTTP_HEADER_NOT_FOUND; INTERNET_SendCallback(&request->hdr, request->hdr.dwContext, @@ -5533,6 +5695,18 @@ static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buf if (!(ses->password = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; return ERROR_SUCCESS; } + case INTERNET_OPTION_PROXY_USERNAME: + { + heap_free(ses->appInfo->proxyUsername); + if (!(ses->appInfo->proxyUsername = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } + case INTERNET_OPTION_PROXY_PASSWORD: + { + heap_free(ses->appInfo->proxyPassword); + if (!(ses->appInfo->proxyPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; + return ERROR_SUCCESS; + } case INTERNET_OPTION_CONNECT_TIMEOUT: { if (!buffer || size != sizeof(DWORD)) return ERROR_INVALID_PARAMETER; @@ -5611,10 +5785,6 @@ DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName, session->appInfo = hIC; list_add_head( &hIC->hdr.children, &session->hdr.entry ); - if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) { - if(hIC->proxyBypass) - FIXME("Proxy bypass is ignored.\n"); - } session->hostName = heap_strdupW(lpszServerName); if (lpszUserName && lpszUserName[0]) session->userName = heap_strdupW(lpszUserName); @@ -5676,19 +5846,15 @@ static void HTTP_clear_response_headers( http_request_t *request ) * TRUE on success * FALSE on error */ -static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) +static DWORD HTTP_GetResponseHeaders(http_request_t *request, INT *len) { INT cbreaks = 0; WCHAR buffer[MAX_REPLY_LEN]; DWORD buflen = MAX_REPLY_LEN; - BOOL bSuccess = FALSE; INT rc = 0; char bufferA[MAX_REPLY_LEN]; LPWSTR status_code = NULL, status_text = NULL; - DWORD cchMaxRawHeaders = 1024; - LPWSTR lpszRawHeaders = NULL; - LPWSTR temp; - DWORD cchRawHeaders = 0; + DWORD res = ERROR_HTTP_INVALID_SERVER_RESPONSE; BOOL codeHundred = FALSE; TRACE("-->\n"); @@ -5696,20 +5862,19 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) if(!request->netconn) goto lend; + /* clear old response headers (eg. from a redirect response) */ + HTTP_clear_response_headers( request ); + NETCON_set_timeout( request->netconn, FALSE, request->receive_timeout ); do { /* * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code. */ buflen = MAX_REPLY_LEN; - if (!read_line(request, bufferA, &buflen)) + if ((res = read_line(request, bufferA, &buflen))) goto lend; - /* clear old response headers (eg. from a redirect response) */ - if (clear) { - HTTP_clear_response_headers( request ); - clear = FALSE; - } + if (!buflen) goto lend; rc += buflen; MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN ); @@ -5724,9 +5889,8 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) /* split the status code from the status text */ status_text = strchrW( status_code, ' ' ); - if( !status_text ) - goto lend; - *status_text++=0; + if( status_text ) + *status_text++=0; request->status_code = atoiW(status_code); @@ -5746,10 +5910,6 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) request->version = heap_strdupW(g_szHttp1_0); request->statusText = heap_strdupW(szOK); - heap_free(request->rawHeaders); - request->rawHeaders = heap_strdupW(szDefaultHeader); - - bSuccess = TRUE; goto lend; } } while (codeHundred); @@ -5762,32 +5922,18 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) heap_free(request->statusText); request->version = heap_strdupW(buffer); - request->statusText = heap_strdupW(status_text); + request->statusText = heap_strdupW(status_text ? status_text : emptyW); /* Restore the spaces */ *(status_code-1) = ' '; - *(status_text-1) = ' '; - - /* regenerate raw headers */ - lpszRawHeaders = heap_alloc((cchMaxRawHeaders + 1) * sizeof(WCHAR)); - if (!lpszRawHeaders) goto lend; - - while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) - cchMaxRawHeaders *= 2; - temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); - if (temp == NULL) goto lend; - lpszRawHeaders = temp; - memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); - cchRawHeaders += (buflen-1); - memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); - cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; - lpszRawHeaders[cchRawHeaders] = '\0'; + if (status_text) + *(status_text-1) = ' '; /* Parse each response line */ do { - buflen = MAX_REPLY_LEN; - if (read_line(request, bufferA, &buflen)) + buflen = MAX_REPLY_LEN; + if (!read_line(request, bufferA, &buflen) && buflen) { LPWSTR * pFieldAndValue; @@ -5799,59 +5945,26 @@ static INT HTTP_GetResponseHeaders(http_request_t *request, BOOL clear) pFieldAndValue = HTTP_InterpretHttpHeader(buffer); if (pFieldAndValue) { - while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders) - cchMaxRawHeaders *= 2; - temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR)); - if (temp == NULL) goto lend; - lpszRawHeaders = temp; - memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR)); - cchRawHeaders += (buflen-1); - memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf)); - cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1; - lpszRawHeaders[cchRawHeaders] = '\0'; - HTTP_ProcessHeader(request, pFieldAndValue[0], pFieldAndValue[1], HTTP_ADDREQ_FLAG_ADD ); - HTTP_FreeTokens(pFieldAndValue); } } - else - { - cbreaks++; - if (cbreaks >= 2) - break; - } + else + { + cbreaks++; + if (cbreaks >= 2) + break; + } }while(1); - /* make sure the response header is terminated with an empty line. Some apps really - truly care about that empty line being there for some reason. Just add it to the - header. */ - if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders) - { - cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf); - temp = heap_realloc(lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR)); - if (temp == NULL) goto lend; - lpszRawHeaders = temp; - } - - memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf)); - - heap_free(request->rawHeaders); - request->rawHeaders = lpszRawHeaders; - TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders)); - bSuccess = TRUE; + res = ERROR_SUCCESS; lend: + *len = rc; TRACE("<--\n"); - if (bSuccess) - return rc; - else - { - heap_free(lpszRawHeaders); - return 0; - } + return res; } /*********************************************************************** @@ -5967,7 +6080,7 @@ static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR { HTTP_DeleteCustomHeader( request, index ); - if (value) + if (value && value[0]) { HTTPHEADERW hdr; diff --git a/reactos/dll/win32/wininet/internet.c b/reactos/dll/win32/wininet/internet.c index 4dbd83819b5..c1ed10ddea6 100644 --- a/reactos/dll/win32/wininet/internet.c +++ b/reactos/dll/win32/wininet/internet.c @@ -121,6 +121,7 @@ static const WCHAR szInternetSettings[] = 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 }; static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 }; static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 }; +static const WCHAR szProxyOverride[] = { 'P','r','o','x','y','O','v','e','r','r','i','d','e', 0 }; void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size) { @@ -315,6 +316,7 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) break; case DLL_PROCESS_DETACH: + if (lpvReserved) break; collect_connections(COLLECT_CLEANUP); NETCON_unload(); free_urlcache(); @@ -613,9 +615,49 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi ) TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy)); } - RegCloseKey( key ); lpwpi->proxyBypass = NULL; + if (lpwpi->proxyEnabled) + { + if (!(envproxy = getenv( "no_proxy" ))) + { + /* figure out how much memory the proxy setting takes */ + if (!RegQueryValueExW( key, szProxyOverride, NULL, &type, NULL, &len ) && len && (type == REG_SZ)) + { + LPWSTR szProxy; + + if (!(szProxy = heap_alloc(len))) + { + RegCloseKey( key ); + return ERROR_OUTOFMEMORY; + } + RegQueryValueExW( key, szProxyOverride, NULL, &type, (BYTE*)szProxy, &len ); + + lpwpi->proxyBypass = szProxy; + + TRACE("http proxy bypass = %s\n", debugstr_w(lpwpi->proxyBypass)); + } + else + { + TRACE("No proxy bypass server settings in registry.\n"); + } + } + else if (envproxy) + { + WCHAR *envproxyW; + + len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 ); + if (!(envproxyW = heap_alloc(len * sizeof(WCHAR)))) + return ERROR_OUTOFMEMORY; + MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len ); + + lpwpi->proxyBypass = envproxyW; + + TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(lpwpi->proxyBypass)); + } + } + + RegCloseKey( key ); return ERROR_SUCCESS; } @@ -625,7 +667,7 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi ) */ static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai ) { - proxyinfo_t wpi; + proxyinfo_t wpi = {0}; if (INTERNET_LoadProxySettings( &wpi )) return FALSE; @@ -659,13 +701,15 @@ static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai ) lpwai->accessType = INTERNET_OPEN_TYPE_PROXY; lpwai->proxy = heap_strdupW(proxyurl); + lpwai->proxyBypass = heap_strdupW(wpi.proxyBypass); if (UrlComponents.dwUserNameLength) { lpwai->proxyUsername = heap_strdupW(UrlComponents.lpszUserName); lpwai->proxyPassword = heap_strdupW(UrlComponents.lpszPassword); } - TRACE("http proxy = %s\n", debugstr_w(lpwai->proxy)); + TRACE("http proxy = %s bypass = %s\n", debugstr_w(lpwai->proxy), debugstr_w(lpwai->proxyBypass)); + FreeProxyInfo(&wpi); return TRUE; } else @@ -676,6 +720,7 @@ static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai ) } lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT; + FreeProxyInfo(&wpi); return FALSE; } @@ -794,7 +839,7 @@ static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffe /* If the buffer is copied, the returned length doesn't include * the NULL terminator. */ - *size = len * sizeof(WCHAR); + *size = len; }else { if (ai->agent) *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL); @@ -985,6 +1030,11 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, /* Clear any error information */ INTERNET_SetLastError(0); + if((dwAccessType == INTERNET_OPEN_TYPE_PROXY) && !lpszProxy) { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t)); if (!lpwai) { SetLastError(ERROR_OUTOFMEMORY); @@ -1001,9 +1051,10 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType, lpwai->agent = heap_strdupW(lpszAgent); if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG) INTERNET_ConfigureProxy( lpwai ); - else + else if(dwAccessType == INTERNET_OPEN_TYPE_PROXY) { lpwai->proxy = heap_strdupW(lpszProxy); - lpwai->proxyBypass = heap_strdupW(lpszProxyBypass); + lpwai->proxyBypass = heap_strdupW(lpszProxyBypass); + } TRACE("returning %p\n", lpwai); @@ -1591,7 +1642,7 @@ static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp) return INTERNET_SCHEME_UNKNOWN; for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++) - if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp)) + if (!strncmpiW(lpszScheme, url_schemes[i], nMaxCmp)) return INTERNET_SCHEME_FIRST + i; return INTERNET_SCHEME_UNKNOWN; @@ -2954,11 +3005,11 @@ BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption, case INTERNET_OPTION_USER_AGENT: case INTERNET_OPTION_USERNAME: case INTERNET_OPTION_PASSWORD: - wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength, - NULL, 0 ); - wbuffer = heap_alloc(wlen*sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength, - wbuffer, wlen ); + case INTERNET_OPTION_PROXY_USERNAME: + case INTERNET_OPTION_PROXY_PASSWORD: + wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ); + if (!(wbuffer = heap_alloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; + MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen ); break; case INTERNET_OPTION_PER_CONNECTION_OPTION: { unsigned int i; diff --git a/reactos/dll/win32/wininet/internet.h b/reactos/dll/win32/wininet/internet.h index 50bc2bbf4d6..1b6dd262e2d 100644 --- a/reactos/dll/win32/wininet/internet.h +++ b/reactos/dll/win32/wininet/internet.h @@ -91,8 +91,15 @@ typedef struct { int socket; BOOL secure; - void *ssl_s; + CtxtHandle ssl_ctx; + SecPkgContext_StreamSizes ssl_sizes; server_t *server; + char *ssl_buf; + char *extra_buf; + size_t extra_len; + char *peek_msg; + char *peek_msg_mem; + size_t peek_len; DWORD security_flags; BOOL mask_errors; @@ -142,6 +149,21 @@ static inline LPWSTR heap_strdupW(LPCWSTR str) return ret; } +static inline char *heap_strdupA(const char *str) +{ + char *ret = NULL; + + if(str) { + DWORD size = strlen(str)+1; + + ret = heap_alloc(size); + if(ret) + memcpy(ret, str, size); + } + + return ret; +} + static inline LPWSTR heap_strndupW(LPCWSTR str, UINT max_len) { LPWSTR ret; @@ -321,7 +343,6 @@ typedef struct server_t *proxy; LPWSTR path; LPWSTR verb; - LPWSTR rawHeaders; netconn_t *netconn; DWORD security_flags; DWORD connect_timeout; diff --git a/reactos/dll/win32/wininet/netconnection.c b/reactos/dll/win32/wininet/netconnection.c index 6a2ee46c637..96efeafbc5b 100644 --- a/reactos/dll/win32/wininet/netconnection.c +++ b/reactos/dll/win32/wininet/netconnection.c @@ -1,7 +1,8 @@ /* - * Wininet - networking layer. Uses unix sockets or OpenSSL. + * Wininet - networking layer. Uses unix sockets. * * Copyright 2002 TransGaming Technologies Inc. + * Copyright 2013 Jacek Caban for CodeWeavers * * David Hammerton * @@ -61,12 +62,6 @@ #ifdef HAVE_NETINET_TCP_H # include #endif -#ifdef HAVE_OPENSSL_SSL_H -# include -# include -#undef FAR -#undef DSA -#endif #include //#include @@ -102,124 +97,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); /* FIXME!!!!!! * This should use winsock - To use winsock the functions will have to change a bit * as they are designed for unix sockets. - * SSL stuff should use crypt32.dll */ -#ifdef SONAME_LIBSSL - -#include - -static void *OpenSSL_ssl_handle; -static void *OpenSSL_crypto_handle; - -#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER > 0x10000000) -static const SSL_METHOD *meth; -#else -static SSL_METHOD *meth; -#endif -static SSL_CTX *ctx; -static int error_idx; -static int conn_idx; - -#define MAKE_FUNCPTR(f) static typeof(f) * p##f - -/* OpenSSL functions that we use */ -MAKE_FUNCPTR(SSL_library_init); -MAKE_FUNCPTR(SSL_load_error_strings); -MAKE_FUNCPTR(SSLv23_method); -MAKE_FUNCPTR(SSL_CTX_free); -MAKE_FUNCPTR(SSL_CTX_new); -MAKE_FUNCPTR(SSL_CTX_ctrl); -MAKE_FUNCPTR(SSL_new); -MAKE_FUNCPTR(SSL_free); -MAKE_FUNCPTR(SSL_ctrl); -MAKE_FUNCPTR(SSL_set_fd); -MAKE_FUNCPTR(SSL_connect); -MAKE_FUNCPTR(SSL_shutdown); -MAKE_FUNCPTR(SSL_write); -MAKE_FUNCPTR(SSL_read); -MAKE_FUNCPTR(SSL_pending); -MAKE_FUNCPTR(SSL_get_error); -MAKE_FUNCPTR(SSL_get_ex_new_index); -MAKE_FUNCPTR(SSL_get_ex_data); -MAKE_FUNCPTR(SSL_set_ex_data); -MAKE_FUNCPTR(SSL_get_ex_data_X509_STORE_CTX_idx); -MAKE_FUNCPTR(SSL_get_peer_certificate); -MAKE_FUNCPTR(SSL_CTX_get_timeout); -MAKE_FUNCPTR(SSL_CTX_set_timeout); -MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths); -MAKE_FUNCPTR(SSL_CTX_set_verify); -MAKE_FUNCPTR(SSL_get_current_cipher); -MAKE_FUNCPTR(SSL_CIPHER_get_bits); - -/* OpenSSL's libcrypto functions that we use */ -MAKE_FUNCPTR(BIO_new_fp); -MAKE_FUNCPTR(CRYPTO_num_locks); -MAKE_FUNCPTR(CRYPTO_set_id_callback); -MAKE_FUNCPTR(CRYPTO_set_locking_callback); -MAKE_FUNCPTR(ERR_free_strings); -MAKE_FUNCPTR(ERR_get_error); -MAKE_FUNCPTR(ERR_error_string); -MAKE_FUNCPTR(X509_STORE_CTX_get_ex_data); -MAKE_FUNCPTR(X509_STORE_CTX_get_chain); -MAKE_FUNCPTR(i2d_X509); -MAKE_FUNCPTR(sk_num); -MAKE_FUNCPTR(sk_value); -#undef MAKE_FUNCPTR - -static CRITICAL_SECTION *ssl_locks; -static unsigned int num_ssl_locks; - -static unsigned long ssl_thread_id(void) -{ - return GetCurrentThreadId(); -} - -static void ssl_lock_callback(int mode, int type, const char *file, int line) -{ - if (mode & CRYPTO_LOCK) - EnterCriticalSection(&ssl_locks[type]); - else - LeaveCriticalSection(&ssl_locks[type]); -} - -static PCCERT_CONTEXT X509_to_cert_context(X509 *cert) -{ - unsigned char* buffer,*p; - INT len; - BOOL malloced = FALSE; - PCCERT_CONTEXT ret; - - p = NULL; - len = pi2d_X509(cert,&p); - /* - * SSL 0.9.7 and above malloc the buffer if it is null. - * however earlier version do not and so we would need to alloc the buffer. - * - * see the i2d_X509 man page for more details. - */ - if (!p) - { - buffer = heap_alloc(len); - p = buffer; - len = pi2d_X509(cert,&p); - } - else - { - buffer = p; - malloced = TRUE; - } - - ret = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len); - - if (malloced) - free(buffer); - else - heap_free(buffer); - - return ret; -} - static DWORD netconn_verify_cert(netconn_t *conn, PCCERT_CONTEXT cert, HCERTSTORE store) { BOOL ret; @@ -377,238 +256,52 @@ static DWORD netconn_verify_cert(netconn_t *conn, PCCERT_CONTEXT cert, HCERTSTOR return ERROR_SUCCESS; } -static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx) -{ - SSL *ssl; - BOOL ret = FALSE; - HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, - CERT_STORE_CREATE_NEW_FLAG, NULL); - netconn_t *conn; - - ssl = pX509_STORE_CTX_get_ex_data(ctx, - pSSL_get_ex_data_X509_STORE_CTX_idx()); - conn = pSSL_get_ex_data(ssl, conn_idx); - if (store) - { - X509 *cert; - int i; - PCCERT_CONTEXT endCert = NULL; - struct stack_st *chain = (struct stack_st *)pX509_STORE_CTX_get_chain( ctx ); - - ret = TRUE; - for (i = 0; ret && i < psk_num(chain); i++) - { - PCCERT_CONTEXT context; - - cert = (X509 *)psk_value(chain, i); - if ((context = X509_to_cert_context(cert))) - { - ret = CertAddCertificateContextToStore(store, context, - CERT_STORE_ADD_ALWAYS, i ? NULL : &endCert); - CertFreeCertificateContext(context); - } - } - if (!endCert) ret = FALSE; - if (ret) - { - DWORD_PTR err = netconn_verify_cert(conn, endCert, store); - - if (err) - { - pSSL_set_ex_data(ssl, error_idx, (void *)err); - ret = FALSE; - } - } - CertFreeCertificateContext(endCert); - CertCloseStore(store, 0); - } - return ret; -} - -static long get_tls_option(void) { - long tls_option = SSL_OP_NO_SSLv2; /* disable SSLv2 for security reason, secur32/Schannel(GnuTLS) don't support it */ -#ifdef SSL_OP_NO_TLSv1_2 - DWORD type, val, size; - HKEY hkey,tls12_client,tls11_client; - LONG res; - const WCHAR Schannel_Prot[] = { /* SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\SCANNEL\\Protocols */ - 'S','Y','S','T','E','M','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'C','o','n','t','r','o','l','\\', - 'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s','\\', - 'S','C','H','A','N','N','E','L','\\', - 'P','r','o','t','o','c','o','l','s',0 }; - const WCHAR TLS12_Client[] = {'T','L','S',' ','1','.','2','\\','C','l','i','e','n','t',0}; - const WCHAR TLS11_Client[] = {'T','L','S',' ','1','.','1','\\','C','l','i','e','n','t',0}; - const WCHAR DisabledByDefault[] = {'D','i','s','a','b','l','e','d','B','y','D','e','f','a','u','l','t',0}; - - res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - Schannel_Prot, - 0, KEY_READ, &hkey); - if (res != ERROR_SUCCESS) { /* enabled TLSv1.1/1.2 when no registry entry */ - return tls_option; - } - if (RegOpenKeyExW(hkey, TLS12_Client, 0, KEY_READ, &tls12_client) == ERROR_SUCCESS) { - size = sizeof(DWORD); - if (RegQueryValueExW(tls12_client, DisabledByDefault, NULL, &type, (LPBYTE) &val, &size) == ERROR_SUCCESS - && type == REG_DWORD) { - tls_option |= val?SSL_OP_NO_TLSv1_2:0; - } - RegCloseKey(tls12_client); - } - if (RegOpenKeyExW(hkey, TLS11_Client, 0, KEY_READ, &tls11_client) == ERROR_SUCCESS) { - size = sizeof(DWORD); - if (RegQueryValueExW(tls11_client, DisabledByDefault, NULL, &type, (LPBYTE) &val, &size) == ERROR_SUCCESS - && type == REG_DWORD) { - tls_option |= val?SSL_OP_NO_TLSv1_1:0; - } - RegCloseKey(tls11_client); - } - RegCloseKey(hkey); -#endif - return tls_option; -} +static SecHandle cred_handle, compat_cred_handle; +static BOOL cred_handle_initialized, have_compat_cred_handle; -static CRITICAL_SECTION init_ssl_cs; -static CRITICAL_SECTION_DEBUG init_ssl_cs_debug = -{ - 0, 0, &init_ssl_cs, - { &init_ssl_cs_debug.ProcessLocksList, - &init_ssl_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") } +static CRITICAL_SECTION init_sechandle_cs; +static CRITICAL_SECTION_DEBUG init_sechandle_cs_debug = { + 0, 0, &init_sechandle_cs, + { &init_sechandle_cs_debug.ProcessLocksList, + &init_sechandle_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": init_sechandle_cs") } }; -static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 }; +static CRITICAL_SECTION init_sechandle_cs = { &init_sechandle_cs_debug, -1, 0, 0, 0, 0 }; -static DWORD init_openssl(void) +static BOOL ensure_cred_handle(void) { -#ifdef SONAME_LIBCRYPTO - unsigned int i; - - if(OpenSSL_ssl_handle) - return ERROR_SUCCESS; - - OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0); - if(!OpenSSL_ssl_handle) { - ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL); - return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; - } - - OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0); - if(!OpenSSL_crypto_handle) { - ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO); - return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; - } - - /* mmm nice ugly macroness */ -#define DYNSSL(x) \ - p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \ - if (!p##x) { \ - ERR("failed to load symbol %s\n", #x); \ - return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ - } - - DYNSSL(SSL_library_init); - DYNSSL(SSL_load_error_strings); - DYNSSL(SSLv23_method); - DYNSSL(SSL_CTX_free); - DYNSSL(SSL_CTX_new); - DYNSSL(SSL_CTX_ctrl); - DYNSSL(SSL_new); - DYNSSL(SSL_free); - DYNSSL(SSL_ctrl); - DYNSSL(SSL_set_fd); - DYNSSL(SSL_connect); - DYNSSL(SSL_shutdown); - DYNSSL(SSL_write); - DYNSSL(SSL_read); - DYNSSL(SSL_pending); - DYNSSL(SSL_get_error); - DYNSSL(SSL_get_ex_new_index); - DYNSSL(SSL_get_ex_data); - DYNSSL(SSL_set_ex_data); - DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx); - DYNSSL(SSL_get_peer_certificate); - DYNSSL(SSL_CTX_get_timeout); - DYNSSL(SSL_CTX_set_timeout); - DYNSSL(SSL_CTX_set_default_verify_paths); - DYNSSL(SSL_CTX_set_verify); - DYNSSL(SSL_get_current_cipher); - DYNSSL(SSL_CIPHER_get_bits); -#undef DYNSSL - -#define DYNCRYPTO(x) \ - p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \ - if (!p##x) { \ - ERR("failed to load symbol %s\n", #x); \ - return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ - } - - DYNCRYPTO(BIO_new_fp); - DYNCRYPTO(CRYPTO_num_locks); - DYNCRYPTO(CRYPTO_set_id_callback); - DYNCRYPTO(CRYPTO_set_locking_callback); - DYNCRYPTO(ERR_free_strings); - DYNCRYPTO(ERR_get_error); - DYNCRYPTO(ERR_error_string); - DYNCRYPTO(X509_STORE_CTX_get_ex_data); - DYNCRYPTO(X509_STORE_CTX_get_chain); - DYNCRYPTO(i2d_X509); - DYNCRYPTO(sk_num); - DYNCRYPTO(sk_value); -#undef DYNCRYPTO - -#define pSSL_CTX_set_options(ctx,op) \ - pSSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) -#define pSSL_set_options(ssl,op) \ - pSSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL) - - pSSL_library_init(); - pSSL_load_error_strings(); - pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */ - - meth = pSSLv23_method(); - ctx = pSSL_CTX_new(meth); - pSSL_CTX_set_options(ctx, get_tls_option()); - if(!pSSL_CTX_set_default_verify_paths(ctx)) { - ERR("SSL_CTX_set_default_verify_paths failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - return ERROR_OUTOFMEMORY; - } - - error_idx = pSSL_get_ex_new_index(0, (void *)"error index", NULL, NULL, NULL); - if(error_idx == -1) { - ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0)); - return ERROR_OUTOFMEMORY; - } + SECURITY_STATUS res = SEC_E_OK; + + EnterCriticalSection(&init_sechandle_cs); + + if(!cred_handle_initialized) { + SCHANNEL_CRED cred = {SCHANNEL_CRED_VERSION}; + SecPkgCred_SupportedProtocols prots; + + res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, &cred, + NULL, NULL, &cred_handle, NULL); + if(res == SEC_E_OK) { + res = QueryCredentialsAttributesA(&cred_handle, SECPKG_ATTR_SUPPORTED_PROTOCOLS, &prots); + if(res != SEC_E_OK || (prots.grbitProtocol & SP_PROT_TLS1_1PLUS_CLIENT)) { + cred.grbitEnabledProtocols = prots.grbitProtocol & ~SP_PROT_TLS1_1PLUS_CLIENT; + res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, &cred, + NULL, NULL, &compat_cred_handle, NULL); + have_compat_cred_handle = res == SEC_E_OK; + } + } - conn_idx = pSSL_get_ex_new_index(0, (void *)"netconn index", NULL, NULL, NULL); - if(conn_idx == -1) { - ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0)); - return ERROR_OUTOFMEMORY; + cred_handle_initialized = res == SEC_E_OK; } - pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify); + LeaveCriticalSection(&init_sechandle_cs); - pCRYPTO_set_id_callback(ssl_thread_id); - num_ssl_locks = pCRYPTO_num_locks(); - ssl_locks = heap_alloc(num_ssl_locks * sizeof(CRITICAL_SECTION)); - if(!ssl_locks) - return ERROR_OUTOFMEMORY; - - for(i = 0; i < num_ssl_locks; i++) - { - InitializeCriticalSection(&ssl_locks[i]); - ssl_locks[i].DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ssl_locks"); + if(res != SEC_E_OK) { + WARN("Failed: %08x\n", res); + return FALSE; } - pCRYPTO_set_locking_callback(ssl_lock_callback); - return ERROR_SUCCESS; -#else - FIXME("can't use SSL, libcrypto not compiled in.\n"); - return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; -#endif + return TRUE; } -#endif /* SONAME_LIBSSL */ static DWORD create_netconn_socket(server_t *server, netconn_t *netconn, DWORD timeout) { @@ -673,20 +366,6 @@ DWORD create_netconn(BOOL useSSL, server_t *server, DWORD security_flags, BOOL m netconn_t *netconn; int result; -#ifdef SONAME_LIBSSL - if(useSSL) { - DWORD res; - - TRACE("using SSL connection\n"); - - EnterCriticalSection(&init_ssl_cs); - res = init_openssl(); - LeaveCriticalSection(&init_ssl_cs); - if(res != ERROR_SUCCESS) - return res; - } -#endif - netconn = heap_alloc_zero(sizeof(*netconn)); if(!netconn) return ERROR_OUTOFMEMORY; @@ -713,10 +392,16 @@ void free_netconn(netconn_t *netconn) server_release(netconn->server); if (netconn->secure) { -#ifdef SONAME_LIBSSL - pSSL_shutdown(netconn->ssl_s); - pSSL_free(netconn->ssl_s); -#endif + heap_free(netconn->peek_msg_mem); + netconn->peek_msg_mem = NULL; + netconn->peek_msg = NULL; + netconn->peek_len = 0; + heap_free(netconn->ssl_buf); + netconn->ssl_buf = NULL; + heap_free(netconn->extra_buf); + netconn->extra_buf = NULL; + netconn->extra_len = 0; + DeleteSecurityContext(&netconn->ssl_ctx); } closesocket(netconn->socket); @@ -725,29 +410,11 @@ void free_netconn(netconn_t *netconn) void NETCON_unload(void) { -#if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) - if (OpenSSL_crypto_handle) - { - pERR_free_strings(); - wine_dlclose(OpenSSL_crypto_handle, NULL, 0); - } - if (OpenSSL_ssl_handle) - { - if (ctx) - pSSL_CTX_free(ctx); - wine_dlclose(OpenSSL_ssl_handle, NULL, 0); - } - if (ssl_locks) - { - unsigned int i; - for (i = 0; i < num_ssl_locks; i++) - { - ssl_locks[i].DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&ssl_locks[i]); - } - heap_free(ssl_locks); - } -#endif + if(cred_handle_initialized) + FreeCredentialsHandle(&cred_handle); + if(have_compat_cred_handle) + FreeCredentialsHandle(&compat_cred_handle); + DeleteCriticalSection(&init_sechandle_cs); } #ifndef __REACTOS__ @@ -819,48 +486,149 @@ int sock_get_error( int err ) } #endif -#ifdef SONAME_LIBSSL -static DWORD netcon_secure_connect_setup(netconn_t *connection, long tls_option) +static DWORD netcon_secure_connect_setup(netconn_t *connection, BOOL compat_mode) { - void *ssl_s; - DWORD res; + SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; + SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; + SecHandle *cred = &cred_handle; + BYTE *read_buf; + SIZE_T read_buf_size = 2048; + ULONG attrs = 0; + CtxtHandle ctx; + SSIZE_T size; int bits; + const CERT_CONTEXT *cert; + SECURITY_STATUS status; + DWORD res = ERROR_SUCCESS; - ssl_s = pSSL_new(ctx); - if (!ssl_s) - { - ERR("SSL_new failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - return ERROR_OUTOFMEMORY; - } + const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY + |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; - pSSL_set_options(ssl_s, tls_option); - if (!pSSL_set_fd(ssl_s, connection->socket)) - { - ERR("SSL_set_fd failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; - goto fail; - } + if(!ensure_cred_handle()) + return FALSE; - if (!pSSL_set_ex_data(ssl_s, conn_idx, connection)) - { - ERR("SSL_set_ex_data failed: %s\n", - pERR_error_string(pERR_get_error(), 0)); - res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; - goto fail; + if(compat_mode) { + if(!have_compat_cred_handle) + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; + cred = &compat_cred_handle; } - if (pSSL_connect(ssl_s) <= 0) - { - res = (DWORD_PTR)pSSL_get_ex_data(ssl_s, error_idx); - if (!res) + + read_buf = heap_alloc(read_buf_size); + if(!read_buf) + return ERROR_OUTOFMEMORY; + + status = InitializeSecurityContextW(cred, NULL, connection->server->name, isc_req_flags, 0, 0, NULL, 0, + &ctx, &out_desc, &attrs, NULL); + + assert(status != SEC_E_OK); + + while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) { + if(out_buf.cbBuffer) { + assert(status == SEC_I_CONTINUE_NEEDED); + + TRACE("sending %u bytes\n", out_buf.cbBuffer); + + size = send(connection->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); + if(size != out_buf.cbBuffer) { + ERR("send failed\n"); + status = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; + break; + } + + FreeContextBuffer(out_buf.pvBuffer); + out_buf.pvBuffer = NULL; + out_buf.cbBuffer = 0; + } + + if(status == SEC_I_CONTINUE_NEEDED) { + assert(in_bufs[1].cbBuffer < read_buf_size); + + memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); + in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; + + in_bufs[1].BufferType = SECBUFFER_EMPTY; + in_bufs[1].cbBuffer = 0; + in_bufs[1].pvBuffer = NULL; + } + + assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); + assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); + + if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { + BYTE *new_read_buf; + + new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); + if(!new_read_buf) { + status = E_OUTOFMEMORY; + break; + } + + in_bufs[0].pvBuffer = read_buf = new_read_buf; + read_buf_size += 1024; + } + + size = recv(connection->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); + if(size < 1) { + WARN("recv error\n"); res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; - ERR("SSL_connect failed: %d\n", res); - goto fail; + break; + } + + TRACE("recv %lu bytes\n", size); + + in_bufs[0].cbBuffer += size; + in_bufs[0].pvBuffer = read_buf; + status = InitializeSecurityContextW(cred, &ctx, connection->server->name, isc_req_flags, 0, 0, &in_desc, + 0, NULL, &out_desc, &attrs, NULL); + TRACE("InitializeSecurityContext ret %08x\n", status); + + if(status == SEC_E_OK) { + if(in_bufs[1].BufferType == SECBUFFER_EXTRA) + FIXME("SECBUFFER_EXTRA not supported\n"); + + status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &connection->ssl_sizes); + if(status != SEC_E_OK) { + WARN("Could not get sizes\n"); + break; + } + + status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); + if(status == SEC_E_OK) { + res = netconn_verify_cert(connection, cert, cert->hCertStore); + CertFreeCertificateContext(cert); + if(res != ERROR_SUCCESS) { + WARN("cert verify failed: %u\n", res); + break; + } + }else { + WARN("Could not get cert\n"); + break; + } + + connection->ssl_buf = heap_alloc(connection->ssl_sizes.cbHeader + connection->ssl_sizes.cbMaximumMessage + + connection->ssl_sizes.cbTrailer); + if(!connection->ssl_buf) { + res = GetLastError(); + break; + } + } } - connection->ssl_s = ssl_s; + + if(status != SEC_E_OK || res != ERROR_SUCCESS) { + WARN("Failed to initialize security context failed: %08x\n", status); + heap_free(connection->ssl_buf); + connection->ssl_buf = NULL; + DeleteSecurityContext(&ctx); + return res ? res : ERROR_INTERNET_SECURITY_CHANNEL_ERROR; + } + + + TRACE("established SSL connection\n"); + connection->ssl_ctx = ctx; + connection->secure = TRUE; + connection->security_flags |= SECURITY_FLAG_SECURE; bits = NETCON_GetCipherStrength(connection); if (bits >= 128) @@ -869,21 +637,11 @@ static DWORD netcon_secure_connect_setup(netconn_t *connection, long tls_option) connection->security_flags |= SECURITY_FLAG_STRENGTH_MEDIUM; else connection->security_flags |= SECURITY_FLAG_STRENGTH_WEAK; - connection->security_flags |= SECURITY_FLAG_SECURE; if(connection->mask_errors) connection->server->security_flags = connection->security_flags; return ERROR_SUCCESS; - -fail: - if (ssl_s) - { - pSSL_shutdown(ssl_s); - pSSL_free(ssl_s); - } - return res; } -#endif /****************************************************************************** * NETCON_secure_connect @@ -891,7 +649,7 @@ fail: */ DWORD NETCON_secure_connect(netconn_t *connection, server_t *server) { - DWORD res = ERROR_NOT_SUPPORTED; + DWORD res; /* can't connect if we are already connected */ if(connection->secure) { @@ -905,31 +663,50 @@ DWORD NETCON_secure_connect(netconn_t *connection, server_t *server) connection->server = server; } -#ifdef SONAME_LIBSSL /* connect with given TLS options */ - res = netcon_secure_connect_setup(connection, get_tls_option()); + res = netcon_secure_connect_setup(connection, FALSE); if (res == ERROR_SUCCESS) return res; -#ifdef SSL_OP_NO_TLSv1_2 /* FIXME: when got version alert and FIN from server */ /* fallback to connect without TLSv1.1/TLSv1.2 */ - if (res == ERROR_INTERNET_SECURITY_CHANNEL_ERROR) + if (res == ERROR_INTERNET_SECURITY_CHANNEL_ERROR && have_compat_cred_handle) { closesocket(connection->socket); - pSSL_CTX_set_options(ctx,SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2); res = create_netconn_socket(connection->server, connection, 500); if (res != ERROR_SUCCESS) return res; - res = netcon_secure_connect_setup(connection, get_tls_option()|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2); + res = netcon_secure_connect_setup(connection, TRUE); } -#endif -#else - FIXME("Cannot connect, OpenSSL not available.\n"); -#endif return res; } +static BOOL send_ssl_chunk(netconn_t *conn, const void *msg, size_t size) +{ + SecBuffer bufs[4] = { + {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf}, + {size, SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader}, + {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size}, + {0, SECBUFFER_EMPTY, NULL} + }; + SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs}; + SECURITY_STATUS res; + + memcpy(bufs[1].pvBuffer, msg, size); + res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0); + if(res != SEC_E_OK) { + WARN("EncryptMessage failed\n"); + return FALSE; + } + + if(send(conn->socket, conn->ssl_buf, bufs[0].cbBuffer+bufs[1].cbBuffer+bufs[2].cbBuffer, 0) < 1) { + WARN("send failed\n"); + return FALSE; + } + + return TRUE; +} + /****************************************************************************** * NETCON_send * Basically calls 'send()' unless we should use SSL @@ -947,24 +724,118 @@ DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags, } else { -#ifdef SONAME_LIBSSL - if(!connection->secure) { - FIXME("not connected\n"); - return ERROR_NOT_SUPPORTED; + const BYTE *ptr = msg; + size_t chunk_size; + + *sent = 0; + + while(len) { + chunk_size = min(len, connection->ssl_sizes.cbMaximumMessage); + if(!send_ssl_chunk(connection, ptr, chunk_size)) + return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; + + *sent += chunk_size; + ptr += chunk_size; + len -= chunk_size; } - if (flags) - FIXME("SSL_write doesn't support any flags (%08x)\n", flags); - *sent = pSSL_write(connection->ssl_s, msg, len); - if (*sent < 1 && len) - return ERROR_INTERNET_CONNECTION_ABORTED; + return ERROR_SUCCESS; -#else - FIXME("not supported on this platform\n"); - return ERROR_NOT_SUPPORTED; -#endif } } +static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof) +{ + const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer; + SecBuffer bufs[4]; + SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs}; + SSIZE_T size, buf_len; + int i; + SECURITY_STATUS res; + + assert(conn->extra_len < ssl_buf_size); + + if(conn->extra_len) { + memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len); + buf_len = conn->extra_len; + conn->extra_len = 0; + heap_free(conn->extra_buf); + conn->extra_buf = NULL; + }else { + buf_len = recv(conn->socket, conn->ssl_buf+conn->extra_len, ssl_buf_size-conn->extra_len, 0); + if(buf_len < 0) { + WARN("recv failed\n"); + return FALSE; + } + + if(!buf_len) { + *eof = TRUE; + return TRUE; + } + } + + *ret_size = 0; + *eof = FALSE; + + do { + memset(bufs, 0, sizeof(bufs)); + bufs[0].BufferType = SECBUFFER_DATA; + bufs[0].cbBuffer = buf_len; + bufs[0].pvBuffer = conn->ssl_buf; + + res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL); + switch(res) { + case SEC_E_OK: + break; + case SEC_I_CONTEXT_EXPIRED: + TRACE("context expired\n"); + *eof = TRUE; + return TRUE; + case SEC_E_INCOMPLETE_MESSAGE: + assert(buf_len < ssl_buf_size); + + size = recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0); + if(size < 1) + return FALSE; + + buf_len += size; + continue; + default: + WARN("failed: %08x\n", res); + return FALSE; + } + } while(res != SEC_E_OK); + + for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) { + if(bufs[i].BufferType == SECBUFFER_DATA) { + size = min(buf_size, bufs[i].cbBuffer); + memcpy(buf, bufs[i].pvBuffer, size); + if(size < bufs[i].cbBuffer) { + assert(!conn->peek_len); + conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size); + if(!conn->peek_msg) + return FALSE; + conn->peek_len = bufs[i].cbBuffer-size; + memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len); + } + + *ret_size = size; + } + } + + for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) { + if(bufs[i].BufferType == SECBUFFER_EXTRA) { + conn->extra_buf = heap_alloc(bufs[i].cbBuffer); + if(!conn->extra_buf) + return FALSE; + + conn->extra_len = bufs[i].cbBuffer; + memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len); + } + } + + return TRUE; +} + /****************************************************************************** * NETCON_recv * Basically calls 'recv()' unless we should use SSL @@ -983,23 +854,46 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, int flags, int * } else { -#ifdef SONAME_LIBSSL - if(!connection->secure) { - FIXME("not connected\n"); - return ERROR_NOT_SUPPORTED; + SIZE_T size = 0, cread; + BOOL res, eof; + + if(connection->peek_msg) { + size = min(len, connection->peek_len); + memcpy(buf, connection->peek_msg, size); + connection->peek_len -= size; + connection->peek_msg += size; + + if(!connection->peek_len) { + heap_free(connection->peek_msg_mem); + connection->peek_msg_mem = connection->peek_msg = NULL; + } + /* check if we have enough data from the peek buffer */ + if(!(flags & MSG_WAITALL) || size == len) { + *recvd = size; + return ERROR_SUCCESS; + } } - *recvd = pSSL_read(connection->ssl_s, buf, len); - /* Check if EOF was received */ - if(!*recvd && (pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_ZERO_RETURN - || pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_SYSCALL)) - return ERROR_SUCCESS; + do { + res = read_ssl_chunk(connection, (BYTE*)buf+size, len-size, &cread, &eof); + if(!res) { + WARN("read_ssl_chunk failed\n"); + if(!size) + return ERROR_INTERNET_CONNECTION_ABORTED; + break; + } - return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED; -#else - FIXME("not supported on this platform\n"); - return ERROR_NOT_SUPPORTED; -#endif + if(eof) { + TRACE("EOF\n"); + break; + } + + size += cread; + }while(!size || ((flags & MSG_WAITALL) && size < len)); + + TRACE("received %ld bytes\n", size); + *recvd = size; + return ERROR_SUCCESS; } } @@ -1026,12 +920,7 @@ BOOL NETCON_query_data_available(netconn_t *connection, DWORD *available) } else { -#ifdef SONAME_LIBSSL - *available = pSSL_pending(connection->ssl_s); -#else - FIXME("not supported on this platform\n"); - return FALSE; -#endif + *available = connection->peek_len; } return TRUE; } @@ -1068,43 +957,28 @@ BOOL NETCON_is_alive(netconn_t *netconn) LPCVOID NETCON_GetCert(netconn_t *connection) { -#ifdef SONAME_LIBSSL - X509* cert; - LPCVOID r = NULL; + const CERT_CONTEXT *ret; + SECURITY_STATUS res; if (!connection->secure) return NULL; - cert = pSSL_get_peer_certificate(connection->ssl_s); - r = X509_to_cert_context(cert); - return r; -#else - FIXME("not supported on this platform\n"); - return NULL; -#endif + res = QueryContextAttributesW(&connection->ssl_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&ret); + return res == SEC_E_OK ? ret : NULL; } int NETCON_GetCipherStrength(netconn_t *connection) { -#ifdef SONAME_LIBSSL -#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090707f) - const SSL_CIPHER *cipher; -#else - SSL_CIPHER *cipher; -#endif - int bits = 0; + SecPkgContext_ConnectionInfo conn_info; + SECURITY_STATUS res; if (!connection->secure) return 0; - cipher = pSSL_get_current_cipher(connection->ssl_s); - if (!cipher) - return 0; - pSSL_CIPHER_get_bits(cipher, &bits); - return bits; -#else - FIXME("not supported on this platform\n"); - return 0; -#endif + + res = QueryContextAttributesW(&connection->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info); + if(res != SEC_E_OK) + WARN("QueryContextAttributesW failed: %08x\n", res); + return res == SEC_E_OK ? conn_info.dwCipherStrength : 0; } DWORD NETCON_set_timeout(netconn_t *connection, BOOL send, DWORD value) diff --git a/reactos/dll/win32/wininet/rsrc.rc b/reactos/dll/win32/wininet/rsrc.rc index 6ca5a8562d3..040a63e0f0d 100644 --- a/reactos/dll/win32/wininet/rsrc.rc +++ b/reactos/dll/win32/wininet/rsrc.rc @@ -123,3 +123,5 @@ #ifdef LANGUAGE_ZH_CN #include "lang/wininet_Zh.rc" #endif + +#include "version.rc" diff --git a/reactos/dll/win32/wininet/urlcache.c b/reactos/dll/win32/wininet/urlcache.c index 166f7807e40..ae94478af8a 100644 --- a/reactos/dll/win32/wininet/urlcache.c +++ b/reactos/dll/win32/wininet/urlcache.c @@ -67,6 +67,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); static const char urlcache_ver_prefix[] = "WINE URLCache Ver "; static const char urlcache_ver[] = "0.2012001"; +#ifndef CHAR_BIT +#define CHAR_BIT (8 * sizeof(CHAR)) +#endif + #define ENTRY_START_OFFSET 0x4000 #define DIR_LENGTH 8 #define MAX_DIR_NO 0x20 @@ -77,7 +81,7 @@ static const char urlcache_ver[] = "0.2012001"; #define ALLOCATION_TABLE_OFFSET 0x250 #define ALLOCATION_TABLE_SIZE (ENTRY_START_OFFSET - ALLOCATION_TABLE_OFFSET) #define MIN_BLOCK_NO 0x80 -#define MAX_BLOCK_NO (ALLOCATION_TABLE_SIZE * 8) +#define MAX_BLOCK_NO (ALLOCATION_TABLE_SIZE * CHAR_BIT) #define FILE_SIZE(blocks) ((blocks) * BLOCKSIZE + ENTRY_START_OFFSET) #define HASHTABLE_URL 0 @@ -104,6 +108,8 @@ static const char urlcache_ver[] = "0.2012001"; #define DWORD_ALIGN(x) ( (DWORD)(((DWORD)(x)+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD) ) +#define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD + typedef struct { DWORD signature; @@ -147,71 +153,243 @@ typedef struct /* CHAR szHeaderInfo[]; (header info) */ } entry_url; -struct _HASH_ENTRY +struct hash_entry { - DWORD dwHashKey; - DWORD dwOffsetEntry; + DWORD key; + DWORD offset; }; -typedef struct _HASH_CACHEFILE_ENTRY -{ - entry_header CacheFileEntry; - DWORD dwAddressNext; - DWORD dwHashTableNumber; - struct _HASH_ENTRY HashTable[HASHTABLE_SIZE]; -} HASH_CACHEFILE_ENTRY; - -typedef struct _DIRECTORY_DATA +typedef struct { - DWORD dwNumFiles; - char filename[DIR_LENGTH]; -} DIRECTORY_DATA; + entry_header header; + DWORD next; + DWORD id; + struct hash_entry hash_table[HASHTABLE_SIZE]; +} entry_hash_table; -typedef struct _URLCACHE_HEADER +typedef struct { - char szSignature[28]; - DWORD dwFileSize; - DWORD dwOffsetFirstHashTable; - DWORD dwIndexCapacityInBlocks; - DWORD dwBlocksInUse; - DWORD dwUnknown1; - ULARGE_INTEGER CacheLimit; - ULARGE_INTEGER CacheUsage; - ULARGE_INTEGER ExemptUsage; - DWORD DirectoryCount; - DIRECTORY_DATA directory_data[MAX_DIR_NO]; + char signature[28]; + DWORD size; + DWORD hash_table_off; + DWORD capacity_in_blocks; + DWORD blocks_in_use; + DWORD unk1; + ULARGE_INTEGER cache_limit; + ULARGE_INTEGER cache_usage; + ULARGE_INTEGER exempt_usage; + DWORD dirs_no; + struct _directory_data + { + DWORD files_no; + char name[DIR_LENGTH]; + } directory_data[MAX_DIR_NO]; DWORD options[0x21]; BYTE allocation_table[ALLOCATION_TABLE_SIZE]; -} URLCACHE_HEADER, *LPURLCACHE_HEADER; -typedef const URLCACHE_HEADER *LPCURLCACHE_HEADER; +} urlcache_header; -typedef struct _STREAM_HANDLE +typedef struct { - HANDLE hFile; - CHAR lpszUrl[1]; -} STREAM_HANDLE; + HANDLE file; + CHAR url[1]; +} stream_handle; -typedef struct _URLCACHECONTAINER +typedef struct { struct list entry; /* part of a list */ - LPWSTR cache_prefix; /* string that has to be prefixed for this container to be used */ + char *cache_prefix; /* string that has to be prefixed for this container to be used */ LPWSTR path; /* path to url container directory */ - HANDLE hMapping; /* handle of file mapping */ + HANDLE mapping; /* handle of file mapping */ DWORD file_size; /* size of file when mapping was opened */ - HANDLE hMutex; /* handle of mutex */ + HANDLE mutex; /* handle of mutex */ DWORD default_entry_type; -} URLCACHECONTAINER; +} cache_container; +typedef struct +{ + DWORD magic; + char *url_search_pattern; + DWORD container_idx; + DWORD hash_table_idx; + DWORD hash_entry_idx; +} find_handle; /* List of all containers available */ static struct list UrlContainers = LIST_INIT(UrlContainers); // ReactOS r54992 BOOL bDefaultContainersAdded = FALSE; -static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash); +static inline char *heap_strdupWtoUTF8(LPCWSTR str) +{ + char *ret = NULL; + + if(str) { + DWORD size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + ret = heap_alloc(size); + if(ret) + WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, size, NULL, NULL); + } + + return ret; +} + +/*********************************************************************** + * urlcache_block_is_free (Internal) + * + * Is the specified block number free? + * + * RETURNS + * zero if free + * non-zero otherwise + * + */ +static inline BYTE urlcache_block_is_free(BYTE *allocation_table, DWORD block_number) +{ + BYTE mask = 1 << (block_number%CHAR_BIT); + return (allocation_table[block_number/CHAR_BIT] & mask) == 0; +} + +/*********************************************************************** + * urlcache_block_free (Internal) + * + * Marks the specified block as free + * + * CAUTION + * this function is not updating used blocks count + * + * RETURNS + * nothing + * + */ +static inline void urlcache_block_free(BYTE *allocation_table, DWORD block_number) +{ + BYTE mask = ~(1 << (block_number%CHAR_BIT)); + allocation_table[block_number/CHAR_BIT] &= mask; +} + +/*********************************************************************** + * urlcache_block_alloc (Internal) + * + * Marks the specified block as allocated + * + * CAUTION + * this function is not updating used blocks count + * + * RETURNS + * nothing + * + */ +static inline void urlcache_block_alloc(BYTE *allocation_table, DWORD block_number) +{ + BYTE mask = 1 << (block_number%CHAR_BIT); + allocation_table[block_number/CHAR_BIT] |= mask; +} + +/*********************************************************************** + * urlcache_entry_alloc (Internal) + * + * Finds and allocates the first block of free space big enough and + * sets entry to point to it. + * + * RETURNS + * ERROR_SUCCESS when free memory block was found + * Any other Win32 error code if the entry could not be added + * + */ +static DWORD urlcache_entry_alloc(urlcache_header *header, DWORD blocks_needed, entry_header **entry) +{ + DWORD block, block_size; + + for(block=0; blockcapacity_in_blocks; block+=block_size+1) + { + block_size = 0; + while(block_sizecapacity_in_blocks + && urlcache_block_is_free(header->allocation_table, block+block_size)) + block_size++; + + if(block_size == blocks_needed) + { + DWORD index; + + TRACE("Found free blocks starting at no. %d (0x%x)\n", block, ENTRY_START_OFFSET+block*BLOCKSIZE); + + for(index=0; indexallocation_table, block+index); + + *entry = (entry_header*)((BYTE*)header+ENTRY_START_OFFSET+block*BLOCKSIZE); + for(index=0; indexblocks_used = blocks_needed; + + header->blocks_in_use += blocks_needed; + return ERROR_SUCCESS; + } + } + + return ERROR_HANDLE_DISK_FULL; +} + +/*********************************************************************** + * urlcache_entry_free (Internal) + * + * Deletes the specified entry and frees the space allocated to it + * + * RETURNS + * TRUE if it succeeded + * FALSE if it failed + * + */ +static BOOL urlcache_entry_free(urlcache_header *header, entry_header *entry) +{ + DWORD start_block, block; + + /* update allocation table */ + start_block = ((DWORD)((BYTE*)entry - (BYTE*)header) - ENTRY_START_OFFSET) / BLOCKSIZE; + for(block = start_block; block < start_block+entry->blocks_used; block++) + urlcache_block_free(header->allocation_table, block); + + header->blocks_in_use -= entry->blocks_used; + return TRUE; +} + +/*********************************************************************** + * urlcache_create_hash_table (Internal) + * + * Creates a new hash table in free space and adds it to the chain of existing + * hash tables. + * + * RETURNS + * ERROR_SUCCESS if the hash table was created + * ERROR_DISK_FULL if the hash table could not be created + * + */ +static DWORD urlcache_create_hash_table(urlcache_header *header, entry_hash_table *hash_table_prev, entry_hash_table **hash_table) +{ + DWORD dwOffset, error; + int i; + + if((error = urlcache_entry_alloc(header, 0x20, (entry_header**)hash_table)) != ERROR_SUCCESS) + return error; + + dwOffset = (BYTE*)*hash_table-(BYTE*)header; + + if(hash_table_prev) + hash_table_prev->next = dwOffset; + else + header->hash_table_off = dwOffset; + + (*hash_table)->header.signature = HASH_SIGNATURE; + (*hash_table)->next = 0; + (*hash_table)->id = hash_table_prev ? hash_table_prev->id+1 : 0; + for(i = 0; i < HASHTABLE_SIZE; i++) { + (*hash_table)->hash_table[i].offset = HASHTABLE_FREE; + (*hash_table)->hash_table[i].key = HASHTABLE_FREE; + } + return ERROR_SUCCESS; +} /*********************************************************************** - * URLCache_PathToObjectName (Internal) + * cache_container_create_object_name (Internal) * * Converts a path to a name suitable for use as a Win32 object name. * Replaces '\\' characters in-place with the specified character @@ -221,7 +399,7 @@ static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ * nothing * */ -static void URLCache_PathToObjectName(LPWSTR lpszPath, WCHAR replace) +static void cache_container_create_object_name(LPWSTR lpszPath, WCHAR replace) { for (; *lpszPath; lpszPath++) { @@ -239,7 +417,7 @@ static HANDLE cache_container_map_index(HANDLE file, const WCHAR *path, DWORD si HANDLE mapping; wsprintfW(mapping_name, mapping_name_format, path, size); - URLCache_PathToObjectName(mapping_name, '_'); + cache_container_create_object_name(mapping_name, '_'); mapping = OpenFileMappingW(FILE_MAP_WRITE, FALSE, mapping_name); if(mapping) { @@ -252,7 +430,7 @@ static HANDLE cache_container_map_index(HANDLE file, const WCHAR *path, DWORD si } /* Caller must hold container lock */ -static DWORD cache_container_set_size(URLCACHECONTAINER *container, HANDLE file, DWORD blocks_no) +static DWORD cache_container_set_size(cache_container *container, HANDLE file, DWORD blocks_no) { static const WCHAR cache_content_key[] = {'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', @@ -263,8 +441,8 @@ static DWORD cache_container_set_size(URLCACHECONTAINER *container, HANDLE file, DWORD file_size = FILE_SIZE(blocks_no); WCHAR dir_path[MAX_PATH], *dir_name; - HASH_CACHEFILE_ENTRY *hash_entry; - URLCACHE_HEADER *header; + entry_hash_table *hashtable_entry; + urlcache_header *header; HANDLE mapping; FILETIME ft; HKEY key; @@ -287,28 +465,28 @@ static DWORD cache_container_set_size(URLCACHECONTAINER *container, HANDLE file, } if(blocks_no != MIN_BLOCK_NO) { - if(file_size > header->dwFileSize) - memset((char*)header+header->dwFileSize, 0, file_size-header->dwFileSize); - header->dwFileSize = file_size; - header->dwIndexCapacityInBlocks = blocks_no; + if(file_size > header->size) + memset((char*)header+header->size, 0, file_size-header->size); + header->size = file_size; + header->capacity_in_blocks = blocks_no; UnmapViewOfFile(header); - CloseHandle(container->hMapping); - container->hMapping = mapping; + CloseHandle(container->mapping); + container->mapping = mapping; container->file_size = file_size; return ERROR_SUCCESS; } memset(header, 0, file_size); /* First set some constants and defaults in the header */ - memcpy(header->szSignature, urlcache_ver_prefix, sizeof(urlcache_ver_prefix)-1); - memcpy(header->szSignature+sizeof(urlcache_ver_prefix)-1, urlcache_ver, sizeof(urlcache_ver)-1); - header->dwFileSize = file_size; - header->dwIndexCapacityInBlocks = blocks_no; + memcpy(header->signature, urlcache_ver_prefix, sizeof(urlcache_ver_prefix)-1); + memcpy(header->signature+sizeof(urlcache_ver_prefix)-1, urlcache_ver, sizeof(urlcache_ver)-1); + header->size = file_size; + header->capacity_in_blocks = blocks_no; /* 127MB - taken from default for Windows 2000 */ - header->CacheLimit.QuadPart = 0x07ff5400; + header->cache_limit.QuadPart = 0x07ff5400; /* Copied from a Windows 2000 cache index */ - header->DirectoryCount = container->default_entry_type==NORMAL_CACHE_ENTRY ? 4 : 0; + header->dirs_no = container->default_entry_type==NORMAL_CACHE_ENTRY ? 4 : 0; /* If the registry has a cache size set, use the registry value */ if(RegOpenKeyW(HKEY_CURRENT_USER, cache_content_key, &key) == ERROR_SUCCESS) { @@ -316,11 +494,11 @@ static DWORD cache_container_set_size(URLCACHECONTAINER *container, HANDLE file, if(RegQueryValueExW(key, cache_limit, NULL, &keytype, (BYTE*)&dw, &len) == ERROR_SUCCESS && keytype == REG_DWORD) - header->CacheLimit.QuadPart = (ULONGLONG)dw * 1024; + header->cache_limit.QuadPart = (ULONGLONG)dw * 1024; RegCloseKey(key); } - URLCache_CreateHashTable(header, NULL, &hash_entry); + urlcache_create_hash_table(header, NULL, &hashtable_entry); /* Last step - create the directories */ strcpyW(dir_path, container->path); @@ -329,8 +507,8 @@ static DWORD cache_container_set_size(URLCACHECONTAINER *container, HANDLE file, GetSystemTimeAsFileTime(&ft); - for(i=0; iDirectoryCount; ++i) { - header->directory_data[i].dwNumFiles = 0; + for(i=0; idirs_no; ++i) { + header->directory_data[i].files_no = 0; for(j=0;; ++j) { ULONGLONG n = ft.dwHighDateTime; int k; @@ -365,7 +543,7 @@ static DWORD cache_container_set_size(URLCACHECONTAINER *container, HANDLE file, * pages and for UTF-16 */ for (k = 0; k < 8; ++k) - header->directory_data[i].filename[k] = dir_name[k]; + header->directory_data[i].name[k] = dir_name[k]; break; }else if(j >= 255) { /* Give up. The most likely cause of this @@ -381,37 +559,37 @@ static DWORD cache_container_set_size(URLCACHECONTAINER *container, HANDLE file, } UnmapViewOfFile(header); - CloseHandle(container->hMapping); - container->hMapping = mapping; + CloseHandle(container->mapping); + container->mapping = mapping; container->file_size = file_size; return ERROR_SUCCESS; } -static BOOL cache_container_is_valid(URLCACHE_HEADER *header, DWORD file_size) +static BOOL cache_container_is_valid(urlcache_header *header, DWORD file_size) { DWORD allocation_size, count_bits, i; if(file_size < FILE_SIZE(MIN_BLOCK_NO)) return FALSE; - if(file_size != header->dwFileSize) + if(file_size != header->size) return FALSE; - if (!memcmp(header->szSignature, urlcache_ver_prefix, sizeof(urlcache_ver_prefix)-1) && - memcmp(header->szSignature+sizeof(urlcache_ver_prefix)-1, urlcache_ver, sizeof(urlcache_ver)-1)) + if (!memcmp(header->signature, urlcache_ver_prefix, sizeof(urlcache_ver_prefix)-1) && + memcmp(header->signature+sizeof(urlcache_ver_prefix)-1, urlcache_ver, sizeof(urlcache_ver)-1)) return FALSE; - if(FILE_SIZE(header->dwIndexCapacityInBlocks) != file_size) + if(FILE_SIZE(header->capacity_in_blocks) != file_size) return FALSE; allocation_size = 0; - for(i=0; idwIndexCapacityInBlocks/8; i++) { + for(i=0; icapacity_in_blocks/8; i++) { for(count_bits = header->allocation_table[i]; count_bits!=0; count_bits>>=1) { if(count_bits & 1) allocation_size++; } } - if(allocation_size != header->dwBlocksInUse) + if(allocation_size != header->blocks_in_use) return FALSE; for(; ihMutex, INFINITE); + WaitForSingleObject(container->mutex, INFINITE); - if(container->hMapping) { - ReleaseMutex(container->hMutex); + if(container->mapping) { + ReleaseMutex(container->mutex); return ERROR_SUCCESS; } @@ -459,14 +637,14 @@ static DWORD cache_container_open_index(URLCACHECONTAINER *container, DWORD bloc } if(file == INVALID_HANDLE_VALUE) { TRACE("Could not open or create cache index file \"%s\"\n", debugstr_w(index_path)); - ReleaseMutex(container->hMutex); + ReleaseMutex(container->mutex); return GetLastError(); } file_size = GetFileSize(file, NULL); if(file_size == INVALID_FILE_SIZE) { CloseHandle(file); - ReleaseMutex(container->hMutex); + ReleaseMutex(container->mutex); return GetLastError(); } @@ -478,15 +656,15 @@ static DWORD cache_container_open_index(URLCACHECONTAINER *container, DWORD bloc if(file_size < FILE_SIZE(blocks_no)) { DWORD ret = cache_container_set_size(container, file, blocks_no); CloseHandle(file); - ReleaseMutex(container->hMutex); + ReleaseMutex(container->mutex); return ret; } container->file_size = file_size; - container->hMapping = cache_container_map_index(file, container->path, file_size, &validate); + container->mapping = cache_container_map_index(file, container->path, file_size, &validate); CloseHandle(file); - if(container->hMapping && validate) { - URLCACHE_HEADER *header = MapViewOfFile(container->hMapping, FILE_MAP_WRITE, 0, 0, 0); + if(container->mapping && validate) { + urlcache_header *header = MapViewOfFile(container->mapping, FILE_MAP_WRITE, 0, 0, 0); if(header && !cache_container_is_valid(header, file_size)) { WARN("detected old or broken index.dat file\n"); @@ -495,19 +673,19 @@ static DWORD cache_container_open_index(URLCACHECONTAINER *container, DWORD bloc }else if(header) { UnmapViewOfFile(header); }else { - CloseHandle(container->hMapping); - container->hMapping = NULL; + CloseHandle(container->mapping); + container->mapping = NULL; } } - if(!container->hMapping) + if(!container->mapping) { ERR("Couldn't create file mapping (error is %d)\n", GetLastError()); - ReleaseMutex(container->hMutex); + ReleaseMutex(container->mutex); return GetLastError(); } - ReleaseMutex(container->hMutex); + ReleaseMutex(container->mutex); return ERROR_SUCCESS; } @@ -520,24 +698,24 @@ static DWORD cache_container_open_index(URLCACHECONTAINER *container, DWORD bloc * nothing * */ -static void cache_container_close_index(URLCACHECONTAINER * pContainer) +static void cache_container_close_index(cache_container *pContainer) { - CloseHandle(pContainer->hMapping); - pContainer->hMapping = NULL; + CloseHandle(pContainer->mapping); + pContainer->mapping = NULL; } -static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, - LPCWSTR path, DWORD default_entry_type, LPWSTR mutex_name) +static BOOL cache_containers_add(const char *cache_prefix, LPCWSTR path, + DWORD default_entry_type, LPWSTR mutex_name) { - URLCACHECONTAINER * pContainer = heap_alloc(sizeof(URLCACHECONTAINER)); - int cache_prefix_len = strlenW(cache_prefix); + cache_container *pContainer = heap_alloc(sizeof(cache_container)); + int cache_prefix_len = strlen(cache_prefix); if (!pContainer) { return FALSE; } - pContainer->hMapping = NULL; + pContainer->mapping = NULL; pContainer->file_size = 0; pContainer->default_entry_type = default_entry_type; @@ -548,7 +726,7 @@ static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, return FALSE; } - pContainer->cache_prefix = heap_alloc((cache_prefix_len + 1) * sizeof(WCHAR)); + pContainer->cache_prefix = heap_alloc(cache_prefix_len+1); if (!pContainer->cache_prefix) { heap_free(pContainer->path); @@ -556,12 +734,12 @@ static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, return FALSE; } - memcpy(pContainer->cache_prefix, cache_prefix, (cache_prefix_len + 1) * sizeof(WCHAR)); + memcpy(pContainer->cache_prefix, cache_prefix, cache_prefix_len+1); CharLowerW(mutex_name); - URLCache_PathToObjectName(mutex_name, '!'); + cache_container_create_object_name(mutex_name, '!'); - if ((pContainer->hMutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL) + if ((pContainer->mutex = CreateMutexW(NULL, FALSE, mutex_name)) == NULL) { ERR("couldn't create mutex (error is %d)\n", GetLastError()); heap_free(pContainer->path); @@ -574,38 +752,35 @@ static BOOL URLCacheContainers_AddContainer(LPCWSTR cache_prefix, return TRUE; } -static void cache_container_delete_container(URLCACHECONTAINER * pContainer) +static void cache_container_delete_container(cache_container *pContainer) { list_remove(&pContainer->entry); cache_container_close_index(pContainer); - CloseHandle(pContainer->hMutex); + CloseHandle(pContainer->mutex); heap_free(pContainer->path); heap_free(pContainer->cache_prefix); heap_free(pContainer); } -static void URLCacheContainers_CreateDefaults(void) +static void cache_containers_init(void) { static const WCHAR UrlSuffix[] = {'C','o','n','t','e','n','t','.','I','E','5',0}; - static const WCHAR UrlPrefix[] = {0}; static const WCHAR HistorySuffix[] = {'H','i','s','t','o','r','y','.','I','E','5',0}; - static const WCHAR HistoryPrefix[] = {'V','i','s','i','t','e','d',':',0}; static const WCHAR CookieSuffix[] = {0}; - static const WCHAR CookiePrefix[] = {'C','o','o','k','i','e',':',0}; // ReactOS r50916 static const WCHAR UserProfile[] = {'U','S','E','R','P','R','O','F','I','L','E',0}; static const struct { int nFolder; /* CSIDL_* constant */ - const WCHAR * shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */ - const WCHAR * cache_prefix; /* prefix used to reference the container */ + const WCHAR *shpath_suffix; /* suffix on path returned by SHGetSpecialFolderPath */ + const char *cache_prefix; /* prefix used to reference the container */ DWORD default_entry_type; } DefaultContainerData[] = { - { CSIDL_INTERNET_CACHE, UrlSuffix, UrlPrefix, NORMAL_CACHE_ENTRY }, - { CSIDL_HISTORY, HistorySuffix, HistoryPrefix, URLHISTORY_CACHE_ENTRY }, - { CSIDL_COOKIES, CookieSuffix, CookiePrefix, COOKIE_CACHE_ENTRY }, + { CSIDL_INTERNET_CACHE, UrlSuffix, "", NORMAL_CACHE_ENTRY }, + { CSIDL_HISTORY, HistorySuffix, "Visited:", URLHISTORY_CACHE_ENTRY }, + { CSIDL_COOKIES, CookieSuffix, "Cookie:", COOKIE_CACHE_ENTRY }, }; DWORD i; @@ -621,6 +796,7 @@ static void URLCacheContainers_CreateDefaults(void) WCHAR wszCachePath[MAX_PATH]; WCHAR wszMutexName[MAX_PATH]; int path_len, suffix_len; + BOOL def_char; if (!SHGetSpecialFolderPathW(NULL, wszCachePath, DefaultContainerData[i].nFolder, TRUE)) { @@ -648,91 +824,93 @@ static void URLCacheContainers_CreateDefaults(void) wszCachePath[path_len + suffix_len + 2] = '\0'; } - URLCacheContainers_AddContainer(DefaultContainerData[i].cache_prefix, wszCachePath, + if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wszCachePath, path_len, + NULL, 0, NULL, &def_char) || def_char) + { + WCHAR tmp[MAX_PATH]; + + /* cannot convert path to ANSI code page */ + if (!(path_len = GetShortPathNameW(wszCachePath, tmp, MAX_PATH)) || + !WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, tmp, path_len, + NULL, 0, NULL, &def_char) || def_char) + ERR("Can't create container path accessible by ANSI functions\n"); + else + memcpy(wszCachePath, tmp, (path_len+1)*sizeof(WCHAR)); + } + + cache_containers_add(DefaultContainerData[i].cache_prefix, wszCachePath, DefaultContainerData[i].default_entry_type, wszMutexName); } } -static void URLCacheContainers_DeleteAll(void) +static void cache_containers_free(void) { while(!list_empty(&UrlContainers)) cache_container_delete_container( - LIST_ENTRY(list_head(&UrlContainers), URLCACHECONTAINER, entry) + LIST_ENTRY(list_head(&UrlContainers), cache_container, entry) ); } -static DWORD URLCacheContainers_FindContainerW(LPCWSTR lpwszUrl, URLCACHECONTAINER ** ppContainer) +static DWORD cache_containers_find(const char *url, cache_container **ret) { - URLCACHECONTAINER * pContainer; + cache_container *container; - TRACE("searching for prefix for URL: %s\n", debugstr_w(lpwszUrl)); + TRACE("searching for prefix for URL: %s\n", debugstr_a(url)); - if(!lpwszUrl) + if(!url) return ERROR_INVALID_PARAMETER; // ReactOS r54992 if (!bDefaultContainersAdded) - URLCacheContainers_CreateDefaults(); + cache_containers_init(); - LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) + LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry) { - int prefix_len = strlenW(pContainer->cache_prefix); - if (!strncmpW(pContainer->cache_prefix, lpwszUrl, prefix_len)) - { - TRACE("found container with prefix %s for URL %s\n", debugstr_w(pContainer->cache_prefix), debugstr_w(lpwszUrl)); - *ppContainer = pContainer; + int prefix_len = strlen(container->cache_prefix); + + if(!strncmp(container->cache_prefix, url, prefix_len)) { + TRACE("found container with prefix %s\n", debugstr_a(container->cache_prefix)); + *ret = container; return ERROR_SUCCESS; } } + ERR("no container found\n"); return ERROR_FILE_NOT_FOUND; } -static DWORD URLCacheContainers_FindContainerA(LPCSTR lpszUrl, URLCACHECONTAINER ** ppContainer) -{ - LPWSTR url = NULL; - DWORD ret; - - if (lpszUrl && !(url = heap_strdupAtoW(lpszUrl))) - return ERROR_OUTOFMEMORY; - - ret = URLCacheContainers_FindContainerW(url, ppContainer); - heap_free(url); - return ret; -} - -static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, URLCACHECONTAINER ** ppContainer) +static BOOL cache_containers_enum(char *search_pattern, DWORD index, cache_container **ret) { DWORD i = 0; - URLCACHECONTAINER * pContainer; + cache_container *container; - TRACE("searching for prefix: %s\n", debugstr_w(lpwszSearchPattern)); + TRACE("searching for prefix: %s\n", debugstr_a(search_pattern)); /* non-NULL search pattern only returns one container ever */ - if (lpwszSearchPattern && dwIndex > 0) + if (search_pattern && index > 0) return FALSE; // ReactOS r54992 if (!bDefaultContainersAdded) - URLCacheContainers_CreateDefaults(); + cache_containers_init(); - LIST_FOR_EACH_ENTRY(pContainer, &UrlContainers, URLCACHECONTAINER, entry) + LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry) { - if (lpwszSearchPattern) + if (search_pattern) { - if (!strcmpW(pContainer->cache_prefix, lpwszSearchPattern)) + if (!strcmp(container->cache_prefix, search_pattern)) { - TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix)); - *ppContainer = pContainer; + TRACE("found container with prefix %s\n", debugstr_a(container->cache_prefix)); + *ret = container; return TRUE; } } else { - if (i == dwIndex) + if (i == index) { - TRACE("found container with prefix %s\n", debugstr_w(pContainer->cache_prefix)); - *ppContainer = pContainer; + TRACE("found container with prefix %s\n", debugstr_a(container->cache_prefix)); + *ret = container; return TRUE; } } @@ -750,56 +928,56 @@ static BOOL URLCacheContainers_Enum(LPCWSTR lpwszSearchPattern, DWORD dwIndex, U * Cache file header if successful * NULL if failed and calls SetLastError. */ -static LPURLCACHE_HEADER cache_container_lock_index(URLCACHECONTAINER * pContainer) +static urlcache_header* cache_container_lock_index(cache_container *pContainer) { BYTE index; LPVOID pIndexData; - URLCACHE_HEADER * pHeader; + urlcache_header* pHeader; DWORD error; /* acquire mutex */ - WaitForSingleObject(pContainer->hMutex, INFINITE); + WaitForSingleObject(pContainer->mutex, INFINITE); - pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0); + pIndexData = MapViewOfFile(pContainer->mapping, FILE_MAP_WRITE, 0, 0, 0); if (!pIndexData) { - ReleaseMutex(pContainer->hMutex); + ReleaseMutex(pContainer->mutex); ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError()); return NULL; } - pHeader = (URLCACHE_HEADER *)pIndexData; + pHeader = (urlcache_header*)pIndexData; /* file has grown - we need to remap to prevent us getting * access violations when we try and access beyond the end * of the memory mapped file */ - if (pHeader->dwFileSize != pContainer->file_size) + if (pHeader->size != pContainer->file_size) { UnmapViewOfFile( pHeader ); cache_container_close_index(pContainer); error = cache_container_open_index(pContainer, MIN_BLOCK_NO); if (error != ERROR_SUCCESS) { - ReleaseMutex(pContainer->hMutex); + ReleaseMutex(pContainer->mutex); SetLastError(error); return NULL; } - pIndexData = MapViewOfFile(pContainer->hMapping, FILE_MAP_WRITE, 0, 0, 0); + pIndexData = MapViewOfFile(pContainer->mapping, FILE_MAP_WRITE, 0, 0, 0); if (!pIndexData) { - ReleaseMutex(pContainer->hMutex); + ReleaseMutex(pContainer->mutex); ERR("Couldn't MapViewOfFile. Error: %d\n", GetLastError()); return NULL; } - pHeader = (URLCACHE_HEADER *)pIndexData; + pHeader = (urlcache_header*)pIndexData; } - TRACE("Signature: %s, file size: %d bytes\n", pHeader->szSignature, pHeader->dwFileSize); + TRACE("Signature: %s, file size: %d bytes\n", pHeader->signature, pHeader->size); - for (index = 0; index < pHeader->DirectoryCount; index++) + for (index = 0; index < pHeader->dirs_no; index++) { - TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].filename); + TRACE("Directory[%d] = \"%.8s\"\n", index, pHeader->directory_data[index].name); } return pHeader; @@ -809,137 +987,15 @@ static LPURLCACHE_HEADER cache_container_lock_index(URLCACHECONTAINER * pContain * cache_container_unlock_index (Internal) * */ -static BOOL cache_container_unlock_index(URLCACHECONTAINER * pContainer, LPURLCACHE_HEADER pHeader) +static BOOL cache_container_unlock_index(cache_container *pContainer, urlcache_header *pHeader) { /* release mutex */ - ReleaseMutex(pContainer->hMutex); + ReleaseMutex(pContainer->mutex); return UnmapViewOfFile(pHeader); } -#ifndef CHAR_BIT -#define CHAR_BIT (8 * sizeof(CHAR)) -#endif - -/*********************************************************************** - * URLCache_Allocation_BlockIsFree (Internal) - * - * Is the specified block number free? - * - * RETURNS - * zero if free - * non-zero otherwise - * - */ -static inline BYTE URLCache_Allocation_BlockIsFree(BYTE * AllocationTable, DWORD dwBlockNumber) -{ - BYTE mask = 1 << (dwBlockNumber % CHAR_BIT); - return (AllocationTable[dwBlockNumber / CHAR_BIT] & mask) == 0; -} - -/*********************************************************************** - * URLCache_Allocation_BlockFree (Internal) - * - * Marks the specified block as free - * - * CAUTION - * this function is not updating used blocks count - * - * RETURNS - * nothing - * - */ -static inline void URLCache_Allocation_BlockFree(BYTE * AllocationTable, DWORD dwBlockNumber) -{ - BYTE mask = ~(1 << (dwBlockNumber % CHAR_BIT)); - AllocationTable[dwBlockNumber / CHAR_BIT] &= mask; -} - -/*********************************************************************** - * URLCache_Allocation_BlockAllocate (Internal) - * - * Marks the specified block as allocated - * - * CAUTION - * this function is not updating used blocks count - * - * RETURNS - * nothing - * - */ -static inline void URLCache_Allocation_BlockAllocate(BYTE * AllocationTable, DWORD dwBlockNumber) -{ - BYTE mask = 1 << (dwBlockNumber % CHAR_BIT); - AllocationTable[dwBlockNumber / CHAR_BIT] |= mask; -} - -/*********************************************************************** - * URLCache_FindFirstFreeEntry (Internal) - * - * Finds and allocates the first block of free space big enough and - * sets ppEntry to point to it. - * - * RETURNS - * ERROR_SUCCESS when free memory block was found - * Any other Win32 error code if the entry could not be added - * - */ -static DWORD URLCache_FindFirstFreeEntry(URLCACHE_HEADER * pHeader, DWORD dwBlocksNeeded, entry_header **ppEntry) -{ - DWORD dwBlockNumber; - DWORD dwFreeCounter; - for (dwBlockNumber = 0; dwBlockNumber < pHeader->dwIndexCapacityInBlocks; dwBlockNumber++) - { - for (dwFreeCounter = 0; - dwFreeCounter < dwBlocksNeeded && - dwFreeCounter + dwBlockNumber < pHeader->dwIndexCapacityInBlocks && - URLCache_Allocation_BlockIsFree(pHeader->allocation_table, dwBlockNumber + dwFreeCounter); - dwFreeCounter++) - TRACE("Found free block at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE); - - if (dwFreeCounter == dwBlocksNeeded) - { - DWORD index; - TRACE("Found free blocks starting at no. %d (0x%x)\n", dwBlockNumber, ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE); - for (index = 0; index < dwBlocksNeeded; index++) - URLCache_Allocation_BlockAllocate(pHeader->allocation_table, dwBlockNumber + index); - *ppEntry = (entry_header*)((LPBYTE)pHeader + ENTRY_START_OFFSET + dwBlockNumber * BLOCKSIZE); - for (index = 0; index < dwBlocksNeeded * BLOCKSIZE / sizeof(DWORD); index++) - ((DWORD*)*ppEntry)[index] = 0xdeadbeef; - (*ppEntry)->blocks_used = dwBlocksNeeded; - pHeader->dwBlocksInUse += dwBlocksNeeded; - return ERROR_SUCCESS; - } - } - - return ERROR_HANDLE_DISK_FULL; -} - -/*********************************************************************** - * URLCache_DeleteEntry (Internal) - * - * Deletes the specified entry and frees the space allocated to it - * - * RETURNS - * TRUE if it succeeded - * FALSE if it failed - * - */ -static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, entry_header *pEntry) -{ - DWORD dwStartBlock; - DWORD dwBlock; - - /* update allocation table */ - dwStartBlock = ((DWORD)((BYTE *)pEntry - (BYTE *)pHeader) - ENTRY_START_OFFSET) / BLOCKSIZE; - for (dwBlock = dwStartBlock; dwBlock < dwStartBlock + pEntry->blocks_used; dwBlock++) - URLCache_Allocation_BlockFree(pHeader->allocation_table, dwBlock); - - pHeader->dwBlocksInUse -= pEntry->blocks_used; - return TRUE; -} - /*********************************************************************** - * URLCache_LocalFileNameToPathW (Internal) + * urlcache_create_file_pathW (Internal) * * Copies the full path to the specified buffer given the local file * name and the index of the directory it is in. Always sets value in @@ -950,9 +1006,9 @@ static BOOL URLCache_DeleteEntry(LPURLCACHE_HEADER pHeader, entry_header *pEntry * FALSE if the buffer was too small * */ -static BOOL URLCache_LocalFileNameToPathW( - const URLCACHECONTAINER * pContainer, - LPCURLCACHE_HEADER pHeader, +static BOOL urlcache_create_file_pathW( + const cache_container *pContainer, + const urlcache_header *pHeader, LPCSTR szLocalFileName, BYTE Directory, LPWSTR wszPath, @@ -961,7 +1017,7 @@ static BOOL URLCache_LocalFileNameToPathW( LONG nRequired; int path_len = strlenW(pContainer->path); int file_name_len = MultiByteToWideChar(CP_ACP, 0, szLocalFileName, -1, NULL, 0); - if (Directory!=CACHE_CONTAINER_NO_SUBDIR && Directory>=pHeader->DirectoryCount) + if (Directory!=CACHE_CONTAINER_NO_SUBDIR && Directory>=pHeader->dirs_no) { *lpBufferSize = 0; return FALSE; @@ -977,7 +1033,7 @@ static BOOL URLCache_LocalFileNameToPathW( memcpy(wszPath, pContainer->path, path_len * sizeof(WCHAR)); if (Directory != CACHE_CONTAINER_NO_SUBDIR) { - dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].filename, DIR_LENGTH, wszPath + path_len, DIR_LENGTH); + dir_len = MultiByteToWideChar(CP_ACP, 0, pHeader->directory_data[Directory].name, DIR_LENGTH, wszPath + path_len, DIR_LENGTH); wszPath[dir_len + path_len] = '\\'; dir_len++; } @@ -994,7 +1050,7 @@ static BOOL URLCache_LocalFileNameToPathW( } /*********************************************************************** - * URLCache_LocalFileNameToPathA (Internal) + * urlcache_create_file_pathA (Internal) * * Copies the full path to the specified buffer given the local file * name and the index of the directory it is in. Always sets value in @@ -1005,9 +1061,9 @@ static BOOL URLCache_LocalFileNameToPathW( * FALSE if the buffer was too small * */ -static BOOL URLCache_LocalFileNameToPathA( - const URLCACHECONTAINER * pContainer, - LPCURLCACHE_HEADER pHeader, +static BOOL urlcache_create_file_pathA( + const cache_container *pContainer, + const urlcache_header *pHeader, LPCSTR szLocalFileName, BYTE Directory, LPSTR szPath, @@ -1016,7 +1072,7 @@ static BOOL URLCache_LocalFileNameToPathA( LONG nRequired; int path_len, file_name_len, dir_len; - if (Directory!=CACHE_CONTAINER_NO_SUBDIR && Directory>=pHeader->DirectoryCount) + if (Directory!=CACHE_CONTAINER_NO_SUBDIR && Directory>=pHeader->dirs_no) { *lpBufferSize = 0; return FALSE; @@ -1030,11 +1086,11 @@ static BOOL URLCache_LocalFileNameToPathA( dir_len = 0; nRequired = (path_len + dir_len + file_name_len) * sizeof(char); - if (nRequired < *lpBufferSize) + if (nRequired <= *lpBufferSize) { WideCharToMultiByte(CP_ACP, 0, pContainer->path, -1, szPath, path_len, NULL, NULL); if(dir_len) { - memcpy(szPath+path_len, pHeader->directory_data[Directory].filename, dir_len-1); + memcpy(szPath+path_len, pHeader->directory_data[Directory].name, dir_len-1); szPath[path_len + dir_len-1] = '\\'; } memcpy(szPath + path_len + dir_len, szLocalFileName, file_name_len); @@ -1048,7 +1104,7 @@ static BOOL URLCache_LocalFileNameToPathA( /* Just like FileTimeToDosDateTime, except that it also maps the special * case of a filetime of (0,0) to a DOS date/time of (0,0). */ -static void URLCache_FileTimeToDosDateTime(const FILETIME *ft, WORD *fatdate, +static void file_time_to_dos_date_time(const FILETIME *ft, WORD *fatdate, WORD *fattime) { if (!ft->dwLowDateTime && !ft->dwHighDateTime) @@ -1058,10 +1114,10 @@ static void URLCache_FileTimeToDosDateTime(const FILETIME *ft, WORD *fatdate, } /*********************************************************************** - * URLCache_DeleteFile (Internal) + * urlcache_delete_file (Internal) */ -static DWORD URLCache_DeleteFile(const URLCACHECONTAINER *container, - URLCACHE_HEADER *header, entry_url *url_entry) +static DWORD urlcache_delete_file(const cache_container *container, + urlcache_header *header, entry_url *url_entry) { WIN32_FILE_ATTRIBUTE_DATA attr; WCHAR path[MAX_PATH]; @@ -1072,14 +1128,14 @@ static DWORD URLCache_DeleteFile(const URLCACHECONTAINER *container, if(!url_entry->local_name_off) goto succ; - if(!URLCache_LocalFileNameToPathW(container, header, + if(!urlcache_create_file_pathW(container, header, (LPCSTR)url_entry+url_entry->local_name_off, url_entry->cache_dir, path, &path_size)) goto succ; if(!GetFileAttributesExW(path, GetFileExInfoStandard, &attr)) goto succ; - URLCache_FileTimeToDosDateTime(&attr.ftLastWriteTime, &date, &time); + file_time_to_dos_date_time(&attr.ftLastWriteTime, &date, &time); if(date != url_entry->write_date || time != url_entry->write_time) goto succ; @@ -1088,30 +1144,30 @@ static DWORD URLCache_DeleteFile(const URLCACHECONTAINER *container, return err; succ: - if (url_entry->cache_dir < header->DirectoryCount) + if (url_entry->cache_dir < header->dirs_no) { - if (header->directory_data[url_entry->cache_dir].dwNumFiles) - header->directory_data[url_entry->cache_dir].dwNumFiles--; + if (header->directory_data[url_entry->cache_dir].files_no) + header->directory_data[url_entry->cache_dir].files_no--; } if (url_entry->cache_entry_type & STICKY_CACHE_ENTRY) { - if (url_entry->size.QuadPart < header->ExemptUsage.QuadPart) - header->ExemptUsage.QuadPart -= url_entry->size.QuadPart; + if (url_entry->size.QuadPart < header->exempt_usage.QuadPart) + header->exempt_usage.QuadPart -= url_entry->size.QuadPart; else - header->ExemptUsage.QuadPart = 0; + header->exempt_usage.QuadPart = 0; } else { - if (url_entry->size.QuadPart < header->CacheUsage.QuadPart) - header->CacheUsage.QuadPart -= url_entry->size.QuadPart; + if (url_entry->size.QuadPart < header->cache_usage.QuadPart) + header->cache_usage.QuadPart -= url_entry->size.QuadPart; else - header->CacheUsage.QuadPart = 0; + header->cache_usage.QuadPart = 0; } return ERROR_SUCCESS; } -static BOOL urlcache_clean_leaked_entries(URLCACHECONTAINER *container, URLCACHE_HEADER *header) +static BOOL urlcache_clean_leaked_entries(cache_container *container, urlcache_header *header) { DWORD *leak_off; BOOL freed = FALSE; @@ -1120,9 +1176,9 @@ static BOOL urlcache_clean_leaked_entries(URLCACHECONTAINER *container, URLCACHE while(*leak_off) { entry_url *url_entry = (entry_url*)((LPBYTE)header + *leak_off); - if(SUCCEEDED(URLCache_DeleteFile(container, header, url_entry))) { + if(SUCCEEDED(urlcache_delete_file(container, header, url_entry))) { *leak_off = url_entry->exempt_delta; - URLCache_DeleteEntry(header, &url_entry->header); + urlcache_entry_free(header, &url_entry->header); freed = TRUE; }else { leak_off = &url_entry->exempt_delta; @@ -1144,26 +1200,26 @@ static BOOL urlcache_clean_leaked_entries(URLCACHECONTAINER *container, URLCACHE * ERROR_SUCCESS when new memory is available * error code otherwise */ -static DWORD cache_container_clean_index(URLCACHECONTAINER *container, URLCACHE_HEADER **file_view) +static DWORD cache_container_clean_index(cache_container *container, urlcache_header **file_view) { - URLCACHE_HEADER *header = *file_view; + urlcache_header *header = *file_view; DWORD ret; - TRACE("(%s %s)\n", debugstr_w(container->cache_prefix), debugstr_w(container->path)); + TRACE("(%s %s)\n", debugstr_a(container->cache_prefix), debugstr_w(container->path)); if(urlcache_clean_leaked_entries(container, header)) return ERROR_SUCCESS; - if(header->dwFileSize >= ALLOCATION_TABLE_SIZE*8*BLOCKSIZE + ENTRY_START_OFFSET) { + if(header->size >= ALLOCATION_TABLE_SIZE*8*BLOCKSIZE + ENTRY_START_OFFSET) { WARN("index file has maximal size\n"); return ERROR_NOT_ENOUGH_MEMORY; } cache_container_close_index(container); - ret = cache_container_open_index(container, header->dwIndexCapacityInBlocks*2); + ret = cache_container_open_index(container, header->capacity_in_blocks*2); if(ret != ERROR_SUCCESS) return ret; - header = MapViewOfFile(container->hMapping, FILE_MAP_WRITE, 0, 0, 0); + header = MapViewOfFile(container->mapping, FILE_MAP_WRITE, 0, 0, 0); if(!header) return GetLastError(); @@ -1175,7 +1231,7 @@ static DWORD cache_container_clean_index(URLCACHECONTAINER *container, URLCACHE_ /* Just like DosDateTimeToFileTime, except that it also maps the special * case of a DOS date/time of (0,0) to a filetime of (0,0). */ -static void URLCache_DosDateTimeToFileTime(WORD fatdate, WORD fattime, +static void dos_date_time_to_file_time(WORD fatdate, WORD fattime, FILETIME *ft) { if (!fatdate && !fattime) @@ -1184,8 +1240,65 @@ static void URLCache_DosDateTimeToFileTime(WORD fatdate, WORD fattime, DosDateTimeToFileTime(fatdate, fattime, ft); } +static int urlcache_decode_url(const char *url, WCHAR *decoded_url, int decoded_len) +{ +#ifndef __REACTOS__ /* FIXME: Vista+ */ + URL_COMPONENTSA uc; + DWORD len, part_len; + WCHAR *host_name; + + memset(&uc, 0, sizeof(uc)); + uc.dwStructSize = sizeof(uc); + uc.dwHostNameLength = 1; + if(!InternetCrackUrlA(url, 0, 0, &uc)) + uc.nScheme = INTERNET_SCHEME_UNKNOWN; + + if(uc.nScheme!=INTERNET_SCHEME_HTTP && uc.nScheme!=INTERNET_SCHEME_HTTPS) +#endif + return MultiByteToWideChar(CP_UTF8, 0, url, -1, decoded_url, decoded_len); + +#ifndef __REACTOS__ /* FIXME: Vista+ */ + if(!decoded_url) + decoded_len = 0; + + len = MultiByteToWideChar(CP_UTF8, 0, url, uc.lpszHostName-url, decoded_url, decoded_len); + if(!len) + return 0; + if(decoded_url) + decoded_len -= len; + + host_name = heap_alloc(uc.dwHostNameLength*sizeof(WCHAR)); + if(!host_name) + return 0; + if(!MultiByteToWideChar(CP_UTF8, 0, uc.lpszHostName, uc.dwHostNameLength, + host_name, uc.dwHostNameLength)) { + heap_free(host_name); + return 0; + } + part_len = IdnToUnicode(0, host_name, uc.dwHostNameLength, + decoded_url ? decoded_url+len : NULL, decoded_len); + heap_free(host_name); + if(!part_len) { + SetLastError(ERROR_INTERNET_INVALID_URL); + return 0; + } + len += part_len; + if(decoded_url) + decoded_len -= part_len; + + part_len = MultiByteToWideChar(CP_UTF8, 0, + uc.lpszHostName+uc.dwHostNameLength, + -1, decoded_url ? decoded_url+len : NULL, decoded_len); + if(!part_len) + return 0; + len += part_len; + + return len; +#endif /* !__REACTOS__ */ +} + /*********************************************************************** - * URLCache_CopyEntry (Internal) + * urlcache_copy_entry (Internal) * * Copies an entry from the cache index file to the Win32 structure * @@ -1194,159 +1307,160 @@ static void URLCache_DosDateTimeToFileTime(WORD fatdate, WORD fattime, * ERROR_INSUFFICIENT_BUFFER if the buffer was too small * */ -static DWORD URLCache_CopyEntry( - URLCACHECONTAINER * pContainer, - LPCURLCACHE_HEADER pHeader, - LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, - LPDWORD lpdwBufferSize, - const entry_url * pUrlEntry, - BOOL bUnicode) +static DWORD urlcache_copy_entry(cache_container *container, const urlcache_header *header, + INTERNET_CACHE_ENTRY_INFOA *entry_info, DWORD *info_size, const entry_url *url_entry, BOOL unicode) { - int lenUrl; - DWORD dwRequiredSize = sizeof(*lpCacheEntryInfo); - - if (*lpdwBufferSize >= dwRequiredSize) - { - lpCacheEntryInfo->lpHeaderInfo = NULL; - lpCacheEntryInfo->lpszFileExtension = NULL; - lpCacheEntryInfo->lpszLocalFileName = NULL; - lpCacheEntryInfo->lpszSourceUrlName = NULL; - lpCacheEntryInfo->CacheEntryType = pUrlEntry->cache_entry_type; - lpCacheEntryInfo->u.dwExemptDelta = pUrlEntry->exempt_delta; - lpCacheEntryInfo->dwHeaderInfoSize = pUrlEntry->header_info_size; - lpCacheEntryInfo->dwHitRate = pUrlEntry->hit_rate; - lpCacheEntryInfo->dwSizeHigh = pUrlEntry->size.u.HighPart; - lpCacheEntryInfo->dwSizeLow = pUrlEntry->size.u.LowPart; - lpCacheEntryInfo->dwStructSize = sizeof(*lpCacheEntryInfo); - lpCacheEntryInfo->dwUseCount = pUrlEntry->use_count; - URLCache_DosDateTimeToFileTime(pUrlEntry->expire_date, pUrlEntry->expire_time, &lpCacheEntryInfo->ExpireTime); - lpCacheEntryInfo->LastAccessTime = pUrlEntry->access_time; - lpCacheEntryInfo->LastModifiedTime = pUrlEntry->modification_time; - URLCache_DosDateTimeToFileTime(pUrlEntry->sync_date, pUrlEntry->sync_time, &lpCacheEntryInfo->LastSyncTime); - } - - if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) - ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); - dwRequiredSize = DWORD_ALIGN(dwRequiredSize); - if (bUnicode) - lenUrl = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->url_off, -1, NULL, 0); + int url_len; + DWORD size = sizeof(*entry_info); + + if(*info_size >= size) { + entry_info->lpHeaderInfo = NULL; + entry_info->lpszFileExtension = NULL; + entry_info->lpszLocalFileName = NULL; + entry_info->lpszSourceUrlName = NULL; + entry_info->CacheEntryType = url_entry->cache_entry_type; + entry_info->u.dwExemptDelta = url_entry->exempt_delta; + entry_info->dwHeaderInfoSize = url_entry->header_info_size; + entry_info->dwHitRate = url_entry->hit_rate; + entry_info->dwSizeHigh = url_entry->size.u.HighPart; + entry_info->dwSizeLow = url_entry->size.u.LowPart; + entry_info->dwStructSize = sizeof(*entry_info); + entry_info->dwUseCount = url_entry->use_count; + dos_date_time_to_file_time(url_entry->expire_date, url_entry->expire_time, &entry_info->ExpireTime); + entry_info->LastAccessTime = url_entry->access_time; + entry_info->LastModifiedTime = url_entry->modification_time; + dos_date_time_to_file_time(url_entry->sync_date, url_entry->sync_time, &entry_info->LastSyncTime); + } + + if(size%4 && size<*info_size) + ZeroMemory((LPBYTE)entry_info+size, 4-size%4); + size = DWORD_ALIGN(size); + if(unicode) + url_len = urlcache_decode_url((const char*)url_entry+url_entry->url_off, NULL, 0); else - lenUrl = strlen((LPCSTR)pUrlEntry + pUrlEntry->url_off); - dwRequiredSize += (lenUrl + 1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)); + url_len = strlen((LPCSTR)url_entry+url_entry->url_off) + 1; + size += url_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR)); - /* FIXME: is source url optional? */ - if (*lpdwBufferSize >= dwRequiredSize) - { - DWORD lenUrlBytes = (lenUrl+1) * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)); + if(*info_size >= size) { + DWORD url_size = url_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR)); - lpCacheEntryInfo->lpszSourceUrlName = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenUrlBytes; - if (bUnicode) - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->url_off, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenUrl + 1); + entry_info->lpszSourceUrlName = (LPSTR)entry_info+size-url_size; + if(unicode) + urlcache_decode_url((const char*)url_entry+url_entry->url_off, (WCHAR*)entry_info->lpszSourceUrlName, url_len); else - memcpy(lpCacheEntryInfo->lpszSourceUrlName, (LPCSTR)pUrlEntry + pUrlEntry->url_off, lenUrlBytes); + memcpy(entry_info->lpszSourceUrlName, (LPCSTR)url_entry+url_entry->url_off, url_size); } - if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) - ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); - dwRequiredSize = DWORD_ALIGN(dwRequiredSize); + if(size%4 && size<*info_size) + ZeroMemory((LPBYTE)entry_info+size, 4-size%4); + size = DWORD_ALIGN(size); - if (pUrlEntry->local_name_off) - { - LONG nLocalFilePathSize; - LPSTR lpszLocalFileName; - lpszLocalFileName = (LPSTR)lpCacheEntryInfo + dwRequiredSize; - nLocalFilePathSize = *lpdwBufferSize - dwRequiredSize; - if ((bUnicode && URLCache_LocalFileNameToPathW(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->local_name_off, pUrlEntry->cache_dir, (LPWSTR)lpszLocalFileName, &nLocalFilePathSize)) || - (!bUnicode && URLCache_LocalFileNameToPathA(pContainer, pHeader, (LPCSTR)pUrlEntry + pUrlEntry->local_name_off, pUrlEntry->cache_dir, lpszLocalFileName, &nLocalFilePathSize))) - { - lpCacheEntryInfo->lpszLocalFileName = lpszLocalFileName; + if(url_entry->local_name_off) { + LONG file_name_size; + LPSTR file_name; + file_name = (LPSTR)entry_info+size; + file_name_size = *info_size-size; + if((unicode && urlcache_create_file_pathW(container, header, (LPCSTR)url_entry+url_entry->local_name_off, url_entry->cache_dir, (LPWSTR)file_name, &file_name_size)) || + (!unicode && urlcache_create_file_pathA(container, header, (LPCSTR)url_entry+url_entry->local_name_off, url_entry->cache_dir, file_name, &file_name_size))) { + entry_info->lpszLocalFileName = file_name; } - dwRequiredSize += nLocalFilePathSize * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)) ; + size += file_name_size; - if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) - ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); - dwRequiredSize = DWORD_ALIGN(dwRequiredSize); + if(size%4 && size<*info_size) + ZeroMemory((LPBYTE)entry_info+size, 4-size%4); + size = DWORD_ALIGN(size); } - dwRequiredSize += pUrlEntry->header_info_size + 1; - if (*lpdwBufferSize >= dwRequiredSize) - { - lpCacheEntryInfo->lpHeaderInfo = (LPBYTE)lpCacheEntryInfo + dwRequiredSize - pUrlEntry->header_info_size - 1; - memcpy(lpCacheEntryInfo->lpHeaderInfo, (LPCSTR)pUrlEntry + pUrlEntry->header_info_off, pUrlEntry->header_info_size); - ((LPBYTE)lpCacheEntryInfo)[dwRequiredSize - 1] = '\0'; + if(url_entry->header_info_off) { + DWORD header_len; + + if(unicode) + header_len = MultiByteToWideChar(CP_UTF8, 0, (const char*)url_entry+url_entry->header_info_off, + url_entry->header_info_size, NULL, 0); + else + header_len = url_entry->header_info_size; + size += header_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR)); + + if(*info_size >= size) { + DWORD header_size = header_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR)); + entry_info->lpHeaderInfo = (LPBYTE)entry_info+size-header_size; + if(unicode) + MultiByteToWideChar(CP_UTF8, 0, (const char*)url_entry+url_entry->header_info_off, + url_entry->header_info_size, (LPWSTR)entry_info->lpHeaderInfo, header_len); + else + memcpy(entry_info->lpHeaderInfo, (LPCSTR)url_entry+url_entry->header_info_off, header_len); + } + if(size%4 && size<*info_size) + ZeroMemory((LPBYTE)entry_info+size, 4-size%4); + size = DWORD_ALIGN(size); } - if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) - ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); - dwRequiredSize = DWORD_ALIGN(dwRequiredSize); - if (pUrlEntry->file_extension_off) - { - int lenExtension; + if(url_entry->file_extension_off) { + int ext_len; - if (bUnicode) - lenExtension = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->file_extension_off, -1, NULL, 0); + if(unicode) + ext_len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)url_entry+url_entry->file_extension_off, -1, NULL, 0); else - lenExtension = strlen((LPCSTR)pUrlEntry + pUrlEntry->file_extension_off) + 1; - dwRequiredSize += lenExtension * (bUnicode ? sizeof(WCHAR) : sizeof(CHAR)); - - if (*lpdwBufferSize >= dwRequiredSize) - { - lpCacheEntryInfo->lpszFileExtension = (LPSTR)lpCacheEntryInfo + dwRequiredSize - lenExtension; - if (bUnicode) - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pUrlEntry + pUrlEntry->file_extension_off, -1, (LPWSTR)lpCacheEntryInfo->lpszSourceUrlName, lenExtension); + ext_len = strlen((LPCSTR)url_entry+url_entry->file_extension_off) + 1; + size += ext_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR)); + + if(*info_size >= size) { + DWORD ext_size = ext_len * (unicode ? sizeof(WCHAR) : sizeof(CHAR)); + entry_info->lpszFileExtension = (LPSTR)entry_info+size-ext_size; + if(unicode) + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)url_entry+url_entry->file_extension_off, -1, (LPWSTR)entry_info->lpszFileExtension, ext_len); else - memcpy(lpCacheEntryInfo->lpszFileExtension, (LPCSTR)pUrlEntry + pUrlEntry->file_extension_off, lenExtension * sizeof(CHAR)); + memcpy(entry_info->lpszFileExtension, (LPCSTR)url_entry+url_entry->file_extension_off, ext_len*sizeof(CHAR)); } - if ((dwRequiredSize % 4) && (dwRequiredSize < *lpdwBufferSize)) - ZeroMemory((LPBYTE)lpCacheEntryInfo + dwRequiredSize, 4 - (dwRequiredSize % 4)); - dwRequiredSize = DWORD_ALIGN(dwRequiredSize); + if(size%4 && size<*info_size) + ZeroMemory((LPBYTE)entry_info+size, 4-size%4); + size = DWORD_ALIGN(size); } - if (dwRequiredSize > *lpdwBufferSize) - { - *lpdwBufferSize = dwRequiredSize; + if(size > *info_size) { + *info_size = size; return ERROR_INSUFFICIENT_BUFFER; } - *lpdwBufferSize = dwRequiredSize; + *info_size = size; return ERROR_SUCCESS; } /*********************************************************************** - * URLCache_SetEntryInfo (Internal) + * urlcache_set_entry_info (Internal) * * Helper for SetUrlCacheEntryInfo{A,W}. Sets fields in URL entry - * according to the flags set by dwFieldControl. + * according to the flags set by field_control. * * RETURNS * ERROR_SUCCESS if the buffer was big enough * ERROR_INSUFFICIENT_BUFFER if the buffer was too small * */ -static DWORD URLCache_SetEntryInfo(entry_url * pUrlEntry, const INTERNET_CACHE_ENTRY_INFOW * lpCacheEntryInfo, DWORD dwFieldControl) +static DWORD urlcache_set_entry_info(entry_url *url_entry, const INTERNET_CACHE_ENTRY_INFOA *entry_info, DWORD field_control) { - if (dwFieldControl & CACHE_ENTRY_ACCTIME_FC) - pUrlEntry->access_time = lpCacheEntryInfo->LastAccessTime; - if (dwFieldControl & CACHE_ENTRY_ATTRIBUTE_FC) - pUrlEntry->cache_entry_type = lpCacheEntryInfo->CacheEntryType; - if (dwFieldControl & CACHE_ENTRY_EXEMPT_DELTA_FC) - pUrlEntry->exempt_delta = lpCacheEntryInfo->u.dwExemptDelta; - if (dwFieldControl & CACHE_ENTRY_EXPTIME_FC) - URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo->ExpireTime, &pUrlEntry->expire_date, &pUrlEntry->expire_time); - if (dwFieldControl & CACHE_ENTRY_HEADERINFO_FC) + if (field_control & CACHE_ENTRY_ACCTIME_FC) + url_entry->access_time = entry_info->LastAccessTime; + if (field_control & CACHE_ENTRY_ATTRIBUTE_FC) + url_entry->cache_entry_type = entry_info->CacheEntryType; + if (field_control & CACHE_ENTRY_EXEMPT_DELTA_FC) + url_entry->exempt_delta = entry_info->u.dwExemptDelta; + if (field_control & CACHE_ENTRY_EXPTIME_FC) + file_time_to_dos_date_time(&entry_info->ExpireTime, &url_entry->expire_date, &url_entry->expire_time); + if (field_control & CACHE_ENTRY_HEADERINFO_FC) FIXME("CACHE_ENTRY_HEADERINFO_FC unimplemented\n"); - if (dwFieldControl & CACHE_ENTRY_HITRATE_FC) - pUrlEntry->hit_rate = lpCacheEntryInfo->dwHitRate; - if (dwFieldControl & CACHE_ENTRY_MODTIME_FC) - pUrlEntry->modification_time = lpCacheEntryInfo->LastModifiedTime; - if (dwFieldControl & CACHE_ENTRY_SYNCTIME_FC) - URLCache_FileTimeToDosDateTime(&lpCacheEntryInfo->LastAccessTime, &pUrlEntry->sync_date, &pUrlEntry->sync_time); + if (field_control & CACHE_ENTRY_HITRATE_FC) + url_entry->hit_rate = entry_info->dwHitRate; + if (field_control & CACHE_ENTRY_MODTIME_FC) + url_entry->modification_time = entry_info->LastModifiedTime; + if (field_control & CACHE_ENTRY_SYNCTIME_FC) + file_time_to_dos_date_time(&entry_info->LastAccessTime, &url_entry->sync_date, &url_entry->sync_time); return ERROR_SUCCESS; } /*********************************************************************** - * URLCache_HashKey (Internal) + * urlcache_hash_key (Internal) * * Returns the hash key for a given string * @@ -1354,7 +1468,7 @@ static DWORD URLCache_SetEntryInfo(entry_url * pUrlEntry, const INTERNET_CACHE_E * hash key for the string * */ -static DWORD URLCache_HashKey(LPCSTR lpszKey) +static DWORD urlcache_hash_key(LPCSTR lpszKey) { /* NOTE: this uses the same lookup table as SHLWAPI.UrlHash{A,W} * but the algorithm and result are not the same! @@ -1409,19 +1523,14 @@ static DWORD URLCache_HashKey(LPCSTR lpszKey) return *(DWORD *)key; } -static inline HASH_CACHEFILE_ENTRY * URLCache_HashEntryFromOffset(LPCURLCACHE_HEADER pHeader, DWORD dwOffset) +static inline entry_hash_table* urlcache_get_hash_table(const urlcache_header *pHeader, DWORD dwOffset) { - return (HASH_CACHEFILE_ENTRY *)((LPBYTE)pHeader + dwOffset); + if(!dwOffset) + return NULL; + return (entry_hash_table*)((LPBYTE)pHeader + dwOffset); } -static inline BOOL URLCache_IsHashEntryValid(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY *pHashEntry) -{ - /* check pHashEntry located within acceptable bounds in the URL cache mapping */ - return ((DWORD)((const BYTE*)pHashEntry - (const BYTE*)pHeader) >= ENTRY_START_OFFSET) && - ((DWORD)((const BYTE*)pHashEntry - (const BYTE*)pHeader) < pHeader->dwFileSize); -} - -static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry) +static BOOL urlcache_find_hash_entry(const urlcache_header *pHeader, LPCSTR lpszUrl, struct hash_entry **ppHashEntry) { /* structure of hash table: * 448 entries divided into 64 blocks @@ -1435,34 +1544,33 @@ static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct * there can be multiple hash tables in the file and the offset to * the next one is stored in the header of the hash table */ - DWORD key = URLCache_HashKey(lpszUrl); + DWORD key = urlcache_hash_key(lpszUrl); DWORD offset = (key & (HASHTABLE_NUM_ENTRIES-1)) * HASHTABLE_BLOCKSIZE; - HASH_CACHEFILE_ENTRY * pHashEntry; - DWORD dwHashTableNumber = 0; + entry_hash_table* pHashEntry; + DWORD id = 0; key >>= HASHTABLE_FLAG_BITS; - for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); - URLCache_IsHashEntryValid(pHeader, pHashEntry); - pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext)) + for (pHashEntry = urlcache_get_hash_table(pHeader, pHeader->hash_table_off); + pHashEntry; pHashEntry = urlcache_get_hash_table(pHeader, pHashEntry->next)) { int i; - if (pHashEntry->dwHashTableNumber != dwHashTableNumber++) + if (pHashEntry->id != id++) { - ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber); + ERR("Error: not right hash table number (%d) expected %d\n", pHashEntry->id, id); continue; } /* make sure that it is in fact a hash entry */ - if (pHashEntry->CacheFileEntry.signature != HASH_SIGNATURE) + if (pHashEntry->header.signature != HASH_SIGNATURE) { - ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.signature); + ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->header.signature); continue; } for (i = 0; i < HASHTABLE_BLOCKSIZE; i++) { - struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i]; - if (key == pHashElement->dwHashKey>>HASHTABLE_FLAG_BITS) + struct hash_entry *pHashElement = &pHashEntry->hash_table[offset + i]; + if (key == pHashElement->key>>HASHTABLE_FLAG_BITS) { /* FIXME: we should make sure that this is the right element * before returning and claiming that it is. We can do this @@ -1478,25 +1586,8 @@ static BOOL URLCache_FindHash(LPCURLCACHE_HEADER pHeader, LPCSTR lpszUrl, struct return FALSE; } -static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, struct _HASH_ENTRY ** ppHashEntry) -{ - LPSTR urlA; - BOOL ret; - - urlA = heap_strdupWtoA(lpszUrl); - if (!urlA) - { - SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - - ret = URLCache_FindHash(pHeader, urlA, ppHashEntry); - heap_free(urlA); - return ret; -} - /*********************************************************************** - * URLCache_HashEntrySetFlags (Internal) + * urlcache_hash_entry_set_flags (Internal) * * Sets special bits in hash key * @@ -1504,13 +1595,13 @@ static BOOL URLCache_FindHashW(LPCURLCACHE_HEADER pHeader, LPCWSTR lpszUrl, stru * nothing * */ -static void URLCache_HashEntrySetFlags(struct _HASH_ENTRY * pHashEntry, DWORD dwFlag) +static void urlcache_hash_entry_set_flags(struct hash_entry *pHashEntry, DWORD dwFlag) { - pHashEntry->dwHashKey = (pHashEntry->dwHashKey >> HASHTABLE_FLAG_BITS << HASHTABLE_FLAG_BITS) | dwFlag; + pHashEntry->key = (pHashEntry->key >> HASHTABLE_FLAG_BITS << HASHTABLE_FLAG_BITS) | dwFlag; } /*********************************************************************** - * URLCache_DeleteEntryFromHash (Internal) + * urlcache_hash_entry_delete (Internal) * * Searches all the hash tables in the index for the given URL and * then if found deletes the entry. @@ -1520,14 +1611,14 @@ static void URLCache_HashEntrySetFlags(struct _HASH_ENTRY * pHashEntry, DWORD dw * FALSE if the entry could not be found * */ -static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry) +static BOOL urlcache_hash_entry_delete(struct hash_entry *pHashEntry) { - pHashEntry->dwHashKey = HASHTABLE_DEL; + pHashEntry->key = HASHTABLE_DEL; return TRUE; } /*********************************************************************** - * URLCache_AddEntryToHash (Internal) + * urlcache_hash_entry_create (Internal) * * Searches all the hash tables for a free slot based on the offset * generated from the hash key. If a free slot is found, the offset and @@ -1538,96 +1629,58 @@ static BOOL URLCache_DeleteEntryFromHash(struct _HASH_ENTRY * pHashEntry) * Any other Win32 error code if the entry could not be added * */ -static DWORD URLCache_AddEntryToHash(LPURLCACHE_HEADER pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry, DWORD dwFieldType) +static DWORD urlcache_hash_entry_create(urlcache_header *pHeader, LPCSTR lpszUrl, DWORD dwOffsetEntry, DWORD dwFieldType) { - /* see URLCache_FindEntryInHash for structure of hash tables */ + /* see urlcache_find_hash_entry for structure of hash tables */ - DWORD key = URLCache_HashKey(lpszUrl); + DWORD key = urlcache_hash_key(lpszUrl); DWORD offset = (key & (HASHTABLE_NUM_ENTRIES-1)) * HASHTABLE_BLOCKSIZE; - HASH_CACHEFILE_ENTRY * pHashEntry, *pHashPrev = NULL; - DWORD dwHashTableNumber = 0; + entry_hash_table* pHashEntry, *pHashPrev = NULL; + DWORD id = 0; DWORD error; key = ((key >> HASHTABLE_FLAG_BITS) << HASHTABLE_FLAG_BITS) + dwFieldType; - for (pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); - URLCache_IsHashEntryValid(pHeader, pHashEntry); - pHashEntry = URLCache_HashEntryFromOffset(pHeader, pHashEntry->dwAddressNext)) + for (pHashEntry = urlcache_get_hash_table(pHeader, pHeader->hash_table_off); + pHashEntry; pHashEntry = urlcache_get_hash_table(pHeader, pHashEntry->next)) { int i; pHashPrev = pHashEntry; - if (pHashEntry->dwHashTableNumber != dwHashTableNumber++) + if (pHashEntry->id != id++) { - ERR("not right hash table number (%d) expected %d\n", pHashEntry->dwHashTableNumber, dwHashTableNumber); + ERR("not right hash table number (%d) expected %d\n", pHashEntry->id, id); break; } /* make sure that it is in fact a hash entry */ - if (pHashEntry->CacheFileEntry.signature != HASH_SIGNATURE) + if (pHashEntry->header.signature != HASH_SIGNATURE) { - ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->CacheFileEntry.signature); + ERR("not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&pHashEntry->header.signature); break; } for (i = 0; i < HASHTABLE_BLOCKSIZE; i++) { - struct _HASH_ENTRY * pHashElement = &pHashEntry->HashTable[offset + i]; - if (pHashElement->dwHashKey==HASHTABLE_FREE || pHashElement->dwHashKey==HASHTABLE_DEL) /* if the slot is free */ + struct hash_entry *pHashElement = &pHashEntry->hash_table[offset + i]; + if (pHashElement->key==HASHTABLE_FREE || pHashElement->key==HASHTABLE_DEL) /* if the slot is free */ { - pHashElement->dwHashKey = key; - pHashElement->dwOffsetEntry = dwOffsetEntry; + pHashElement->key = key; + pHashElement->offset = dwOffsetEntry; return ERROR_SUCCESS; } } } - error = URLCache_CreateHashTable(pHeader, pHashPrev, &pHashEntry); + error = urlcache_create_hash_table(pHeader, pHashPrev, &pHashEntry); if (error != ERROR_SUCCESS) return error; - pHashEntry->HashTable[offset].dwHashKey = key; - pHashEntry->HashTable[offset].dwOffsetEntry = dwOffsetEntry; + pHashEntry->hash_table[offset].key = key; + pHashEntry->hash_table[offset].offset = dwOffsetEntry; return ERROR_SUCCESS; } /*********************************************************************** - * URLCache_CreateHashTable (Internal) - * - * Creates a new hash table in free space and adds it to the chain of existing - * hash tables. - * - * RETURNS - * ERROR_SUCCESS if the hash table was created - * ERROR_DISK_FULL if the hash table could not be created - * - */ -static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ENTRY *pPrevHash, HASH_CACHEFILE_ENTRY **ppHash) -{ - DWORD dwOffset, error; - int i; - - if ((error = URLCache_FindFirstFreeEntry(pHeader, 0x20, (entry_header**)ppHash)) != ERROR_SUCCESS) - return error; - - dwOffset = (BYTE *)*ppHash - (BYTE *)pHeader; - - if (pPrevHash) - pPrevHash->dwAddressNext = dwOffset; - else - pHeader->dwOffsetFirstHashTable = dwOffset; - (*ppHash)->CacheFileEntry.signature = HASH_SIGNATURE; - (*ppHash)->CacheFileEntry.blocks_used = 0x20; - (*ppHash)->dwAddressNext = 0; - (*ppHash)->dwHashTableNumber = pPrevHash ? pPrevHash->dwHashTableNumber + 1 : 0; - for (i = 0; i < HASHTABLE_SIZE; i++) - { - (*ppHash)->HashTable[i].dwOffsetEntry = HASHTABLE_FREE; - (*ppHash)->HashTable[i].dwHashKey = HASHTABLE_FREE; - } - return ERROR_SUCCESS; -} - -/*********************************************************************** - * URLCache_EnumHashTables (Internal) + * urlcache_enum_hash_tables (Internal) * * Enumerates the hash tables in a container. * @@ -1636,31 +1689,30 @@ static DWORD URLCache_CreateHashTable(LPURLCACHE_HEADER pHeader, HASH_CACHEFILE_ * FALSE if there are no more tables to enumerate. * */ -static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTableNumber, HASH_CACHEFILE_ENTRY ** ppHashEntry) +static BOOL urlcache_enum_hash_tables(const urlcache_header *pHeader, DWORD *id, entry_hash_table **ppHashEntry) { - for (*ppHashEntry = URLCache_HashEntryFromOffset(pHeader, pHeader->dwOffsetFirstHashTable); - URLCache_IsHashEntryValid(pHeader, *ppHashEntry); - *ppHashEntry = URLCache_HashEntryFromOffset(pHeader, (*ppHashEntry)->dwAddressNext)) + for (*ppHashEntry = urlcache_get_hash_table(pHeader, pHeader->hash_table_off); + *ppHashEntry; *ppHashEntry = urlcache_get_hash_table(pHeader, (*ppHashEntry)->next)) { - TRACE("looking at hash table number %d\n", (*ppHashEntry)->dwHashTableNumber); - if ((*ppHashEntry)->dwHashTableNumber != *pdwHashTableNumber) + TRACE("looking at hash table number %d\n", (*ppHashEntry)->id); + if ((*ppHashEntry)->id != *id) continue; /* make sure that it is in fact a hash entry */ - if ((*ppHashEntry)->CacheFileEntry.signature != HASH_SIGNATURE) + if ((*ppHashEntry)->header.signature != HASH_SIGNATURE) { - ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->CacheFileEntry.signature); - (*pdwHashTableNumber)++; + ERR("Error: not right signature (\"%.4s\") - expected \"HASH\"\n", (LPCSTR)&(*ppHashEntry)->header.signature); + (*id)++; continue; } - TRACE("hash table number %d found\n", *pdwHashTableNumber); + TRACE("hash table number %d found\n", *id); return TRUE; } return FALSE; } /*********************************************************************** - * URLCache_EnumHashTableEntries (Internal) + * urlcache_enum_hash_table_entries (Internal) * * Enumerates entries in a hash table and returns the next non-free entry. * @@ -1670,15 +1722,15 @@ static BOOL URLCache_EnumHashTables(LPCURLCACHE_HEADER pHeader, DWORD *pdwHashTa * enumerate. * */ -static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH_CACHEFILE_ENTRY * pHashEntry, - DWORD * index, const struct _HASH_ENTRY ** ppHashEntry) +static BOOL urlcache_enum_hash_table_entries(const urlcache_header *pHeader, const entry_hash_table *pHashEntry, + DWORD * index, const struct hash_entry **ppHashEntry) { for (; *index < HASHTABLE_SIZE ; (*index)++) { - if (pHashEntry->HashTable[*index].dwHashKey==HASHTABLE_FREE || pHashEntry->HashTable[*index].dwHashKey==HASHTABLE_DEL) + if (pHashEntry->hash_table[*index].key==HASHTABLE_FREE || pHashEntry->hash_table[*index].key==HASHTABLE_DEL) continue; - *ppHashEntry = &pHashEntry->HashTable[*index]; + *ppHashEntry = &pHashEntry->hash_table[*index]; TRACE("entry found %d\n", *index); return TRUE; } @@ -1687,7 +1739,7 @@ static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH } /*********************************************************************** - * URLCache_DeleteCacheDirectory (Internal) + * cache_container_delete_dir (Internal) * * Erase a directory containing an URL cache. * @@ -1695,7 +1747,7 @@ static BOOL URLCache_EnumHashTableEntries(LPCURLCACHE_HEADER pHeader, const HASH * TRUE success, FALSE failure/aborted. * */ -static BOOL URLCache_DeleteCacheDirectory(LPCWSTR lpszPath) +static BOOL cache_container_delete_dir(LPCWSTR lpszPath) { DWORD path_len; WCHAR path[MAX_PATH + 1]; @@ -1721,16 +1773,16 @@ static BOOL URLCache_DeleteCacheDirectory(LPCWSTR lpszPath) } /*********************************************************************** - * URLCache_IsLocked (Internal) + * urlcache_hash_entry_is_locked (Internal) * * Checks if entry is locked. Unlocks it if possible. */ -static BOOL URLCache_IsLocked(struct _HASH_ENTRY *hash_entry, entry_url *url_entry) +static BOOL urlcache_hash_entry_is_locked(struct hash_entry *hash_entry, entry_url *url_entry) { FILETIME cur_time; ULARGE_INTEGER acc_time, time; - if ((hash_entry->dwHashKey & ((1<key & ((1< (ULONGLONG)24*60*60*FILETIME_SECOND) { - URLCache_HashEntrySetFlags(hash_entry, HASHTABLE_URL); + urlcache_hash_entry_set_flags(hash_entry, HASHTABLE_URL); url_entry->use_count = 0; return FALSE; } @@ -1752,273 +1804,254 @@ static BOOL URLCache_IsLocked(struct _HASH_ENTRY *hash_entry, entry_url *url_ent return TRUE; } -/*********************************************************************** - * GetUrlCacheEntryInfoExA (WININET.@) - * - */ -BOOL WINAPI GetUrlCacheEntryInfoExA( - LPCSTR lpszUrl, - LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, - LPDWORD lpdwCacheEntryInfoBufSize, - LPSTR lpszReserved, - LPDWORD lpdwReserved, - LPVOID lpReserved, - DWORD dwFlags) +static BOOL urlcache_get_entry_info(const char *url, void *entry_info, + DWORD *size, DWORD flags, BOOL unicode) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - const entry_header *pEntry; - const entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; + urlcache_header *header; + struct hash_entry *hash_entry; + const entry_url *url_entry; + cache_container *container; DWORD error; - TRACE("(%s, %p, %p, %p, %p, %p, %x)\n", - debugstr_a(lpszUrl), - lpCacheEntryInfo, - lpdwCacheEntryInfoBufSize, - lpszReserved, - lpdwReserved, - lpReserved, - dwFlags); - - if ((lpszReserved != NULL) || - (lpdwReserved != NULL) || - (lpReserved != NULL)) - { - ERR("Reserved value was not 0\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - if (dwFlags & ~GET_INSTALLED_ENTRY) - FIXME("ignoring unsupported flags: %x\n", dwFlags); + TRACE("(%s, %p, %p, %x, %x)\n", debugstr_a(url), entry_info, size, flags, unicode); - error = URLCacheContainers_FindContainerA(lpszUrl, &pContainer); - if (error != ERROR_SUCCESS) - { + if(flags & ~GET_INSTALLED_ENTRY) + FIXME("ignoring unsupported flags: %x\n", flags); + + error = cache_containers_find(url, &container); + if(error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { + error = cache_container_open_index(container, MIN_BLOCK_NO); + if(error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - if (!(pHeader = cache_container_lock_index(pContainer))) + if(!(header = cache_container_lock_index(container))) return FALSE; - if (!URLCache_FindHash(pHeader, lpszUrl, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - WARN("entry %s not found!\n", debugstr_a(lpszUrl)); + if(!urlcache_find_hash_entry(header, url, &hash_entry)) { + cache_container_unlock_index(container, header); + WARN("entry %s not found!\n", debugstr_a(url)); SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } - pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (pEntry->signature != URL_SIGNATURE) - { - cache_container_unlock_index(pContainer, pHeader); + url_entry = (const entry_url*)((LPBYTE)header + hash_entry->offset); + if(url_entry->header.signature != URL_SIGNATURE) { + cache_container_unlock_index(container, header); FIXME("Trying to retrieve entry of unknown format %s\n", - debugstr_an((LPCSTR)&pEntry->signature, sizeof(DWORD))); + debugstr_an((LPCSTR)&url_entry->header.signature, sizeof(DWORD))); SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } - pUrlEntry = (const entry_url *)pEntry; - TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->url_off)); - TRACE("Header info: %s\n", debugstr_an((LPCSTR)pUrlEntry + - pUrlEntry->header_info_off, pUrlEntry->header_info_size)); + TRACE("Found URL: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->url_off)); + TRACE("Header info: %s\n", debugstr_an((LPCSTR)url_entry + + url_entry->header_info_off, url_entry->header_info_size)); - if((dwFlags & GET_INSTALLED_ENTRY) && !(pUrlEntry->cache_entry_type & INSTALLED_CACHE_ENTRY)) - { - cache_container_unlock_index(pContainer, pHeader); + if((flags & GET_INSTALLED_ENTRY) && !(url_entry->cache_entry_type & INSTALLED_CACHE_ENTRY)) { + cache_container_unlock_index(container, header); SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } - if (lpdwCacheEntryInfoBufSize) - { - if (!lpCacheEntryInfo) - *lpdwCacheEntryInfoBufSize = 0; - - error = URLCache_CopyEntry( - pContainer, - pHeader, - lpCacheEntryInfo, - lpdwCacheEntryInfoBufSize, - pUrlEntry, - FALSE /* ANSI */); - if (error != ERROR_SUCCESS) - { - cache_container_unlock_index(pContainer, pHeader); + if(size) { + if(!entry_info) + *size = 0; + + error = urlcache_copy_entry(container, header, entry_info, size, url_entry, unicode); + if(error != ERROR_SUCCESS) { + cache_container_unlock_index(container, header); SetLastError(error); return FALSE; } - if(pUrlEntry->local_name_off) - TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->local_name_off)); + if(url_entry->local_name_off) + TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->local_name_off)); } - cache_container_unlock_index(pContainer, pHeader); - + cache_container_unlock_index(container, header); return TRUE; } /*********************************************************************** - * GetUrlCacheEntryInfoA (WININET.@) + * GetUrlCacheEntryInfoExA (WININET.@) * */ -BOOL WINAPI GetUrlCacheEntryInfoA( - IN LPCSTR lpszUrlName, - IN LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, - IN OUT LPDWORD lpdwCacheEntryInfoBufferSize -) +BOOL WINAPI GetUrlCacheEntryInfoExA(LPCSTR lpszUrl, + LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufSize, LPSTR lpszReserved, + LPDWORD lpdwReserved, LPVOID lpReserved, DWORD dwFlags) { - return GetUrlCacheEntryInfoExA(lpszUrlName, lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, NULL, NULL, NULL, 0); + if(lpszReserved!=NULL || lpdwReserved!=NULL || lpReserved!=NULL) { + ERR("Reserved value was not 0\n"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return urlcache_get_entry_info(lpszUrl, lpCacheEntryInfo, + lpdwCacheEntryInfoBufSize, dwFlags, FALSE); } /*********************************************************************** - * GetUrlCacheEntryInfoW (WININET.@) + * GetUrlCacheEntryInfoA (WININET.@) * */ -BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl, - LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, - LPDWORD lpdwCacheEntryInfoBufferSize) +BOOL WINAPI GetUrlCacheEntryInfoA(LPCSTR lpszUrlName, + LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufferSize) { - return GetUrlCacheEntryInfoExW(lpszUrl, lpCacheEntryInfo, + return GetUrlCacheEntryInfoExA(lpszUrlName, lpCacheEntryInfo, lpdwCacheEntryInfoBufferSize, NULL, NULL, NULL, 0); } -/*********************************************************************** - * GetUrlCacheEntryInfoExW (WININET.@) - * - */ -BOOL WINAPI GetUrlCacheEntryInfoExW( - LPCWSTR lpszUrl, - LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, - LPDWORD lpdwCacheEntryInfoBufSize, - LPWSTR lpszReserved, - LPDWORD lpdwReserved, - LPVOID lpReserved, - DWORD dwFlags) +static int urlcache_encode_url(const WCHAR *url, char *encoded_url, int encoded_len) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - const entry_header *pEntry; - const entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; - DWORD error; +#ifndef __REACTOS__ /* FIXME: Vista+ */ + URL_COMPONENTSW uc; + DWORD len, part_len; + WCHAR *punycode; - TRACE("(%s, %p, %p, %p, %p, %p, %x)\n", - debugstr_w(lpszUrl), - lpCacheEntryInfo, - lpdwCacheEntryInfoBufSize, - lpszReserved, - lpdwReserved, - lpReserved, - dwFlags); + TRACE("%s\n", debugstr_w(url)); - /* Ignore GET_INSTALLED_ENTRY flag in unicode version of function */ - dwFlags &= ~GET_INSTALLED_ENTRY; + memset(&uc, 0, sizeof(uc)); + uc.dwStructSize = sizeof(uc); + uc.dwHostNameLength = 1; + if(!InternetCrackUrlW(url, 0, 0, &uc)) + uc.nScheme = INTERNET_SCHEME_UNKNOWN; - if ((lpszReserved != NULL) || - (lpdwReserved != NULL) || - (lpReserved != NULL)) - { - ERR("Reserved value was not 0\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + if(uc.nScheme!=INTERNET_SCHEME_HTTP && uc.nScheme!=INTERNET_SCHEME_HTTPS) +#endif + return WideCharToMultiByte(CP_UTF8, 0, url, -1, encoded_url, encoded_len, NULL, NULL); + +#ifndef __REACTOS__ /* FIXME: Vista+ */ + len = WideCharToMultiByte(CP_UTF8, 0, url, uc.lpszHostName-url, + encoded_url, encoded_len, NULL, NULL); + if(!len) + return 0; + if(encoded_url) + encoded_len -= len; + + part_len = IdnToAscii(0, uc.lpszHostName, uc.dwHostNameLength, NULL, 0); + if(!part_len) { + SetLastError(ERROR_INTERNET_INVALID_URL); + return 0; } - if (dwFlags) - FIXME("ignoring unsupported flags: %x\n", dwFlags); - error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer); - if (error != ERROR_SUCCESS) - { - SetLastError(error); - return FALSE; + punycode = heap_alloc(part_len*sizeof(WCHAR)); + if(!punycode) + return 0; + + part_len = IdnToAscii(0, uc.lpszHostName, uc.dwHostNameLength, punycode, part_len); + if(!part_len) { + heap_free(punycode); + return 0; } - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { - SetLastError(error); + part_len = WideCharToMultiByte(CP_UTF8, 0, punycode, part_len, + encoded_url ? encoded_url+len : NULL, encoded_len, NULL, NULL); + heap_free(punycode); + if(!part_len) + return 0; + if(encoded_url) + encoded_len -= part_len; + len += part_len; + + part_len = WideCharToMultiByte(CP_UTF8, 0, uc.lpszHostName+uc.dwHostNameLength, + -1, encoded_url ? encoded_url+len : NULL, encoded_len, NULL, NULL); + if(!part_len) + return 0; + len += part_len; + + TRACE("got (%d)%s\n", len, debugstr_a(encoded_url)); + return len; +#endif /* !__REACTOS__ */ +} + +static BOOL urlcache_encode_url_alloc(const WCHAR *url, char **encoded_url) +{ + DWORD encoded_len; + char *ret; + + encoded_len = urlcache_encode_url(url, NULL, 0); + if(!encoded_len) return FALSE; - } - if (!(pHeader = cache_container_lock_index(pContainer))) + ret = heap_alloc(encoded_len*sizeof(WCHAR)); + if(!ret) return FALSE; - if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - WARN("entry %s not found!\n", debugstr_w(lpszUrl)); - SetLastError(ERROR_FILE_NOT_FOUND); + encoded_len = urlcache_encode_url(url, ret, encoded_len); + if(!encoded_len) { + heap_free(ret); return FALSE; } - pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (pEntry->signature != URL_SIGNATURE) - { - cache_container_unlock_index(pContainer, pHeader); - FIXME("Trying to retrieve entry of unknown format %s\n", - debugstr_an((LPCSTR)&pEntry->signature, sizeof(DWORD))); - SetLastError(ERROR_FILE_NOT_FOUND); + *encoded_url = ret; + return TRUE; +} + +/*********************************************************************** + * GetUrlCacheEntryInfoExW (WININET.@) + * + */ +BOOL WINAPI GetUrlCacheEntryInfoExW(LPCWSTR lpszUrl, + LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufSize, LPWSTR lpszReserved, + LPDWORD lpdwReserved, LPVOID lpReserved, DWORD dwFlags) +{ + char *url; + BOOL ret; + + if(lpszReserved!=NULL || lpdwReserved!=NULL || lpReserved!=NULL) { + ERR("Reserved value was not 0\n"); + SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - pUrlEntry = (const entry_url *)pEntry; - TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->url_off)); - TRACE("Header info: %s\n", debugstr_an((LPCSTR)pUrlEntry + - pUrlEntry->header_info_off, pUrlEntry->header_info_size)); + /* Ignore GET_INSTALLED_ENTRY flag in unicode version of function */ + dwFlags &= ~GET_INSTALLED_ENTRY; - if (lpdwCacheEntryInfoBufSize) - { - if (!lpCacheEntryInfo) - *lpdwCacheEntryInfoBufSize = 0; - - error = URLCache_CopyEntry( - pContainer, - pHeader, - (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo, - lpdwCacheEntryInfoBufSize, - pUrlEntry, - TRUE /* UNICODE */); - if (error != ERROR_SUCCESS) - { - cache_container_unlock_index(pContainer, pHeader); - SetLastError(error); - return FALSE; - } - if(pUrlEntry->local_name_off) - TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->local_name_off)); - } + if(!urlcache_encode_url_alloc(lpszUrl, &url)) + return FALSE; - cache_container_unlock_index(pContainer, pHeader); + ret = urlcache_get_entry_info(url, lpCacheEntryInfo, + lpdwCacheEntryInfoBufSize, dwFlags, TRUE); + heap_free(url); + return ret; +} - return TRUE; +/*********************************************************************** + * GetUrlCacheEntryInfoW (WININET.@) + * + */ +BOOL WINAPI GetUrlCacheEntryInfoW(LPCWSTR lpszUrl, + LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufferSize) +{ + return GetUrlCacheEntryInfoExW(lpszUrl, lpCacheEntryInfo, + lpdwCacheEntryInfoBufferSize, NULL, NULL, NULL, 0); } /*********************************************************************** * SetUrlCacheEntryInfoA (WININET.@) */ -BOOL WINAPI SetUrlCacheEntryInfoA( - LPCSTR lpszUrlName, - LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, - DWORD dwFieldControl) +BOOL WINAPI SetUrlCacheEntryInfoA(LPCSTR lpszUrlName, + LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, + DWORD dwFieldControl) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; + urlcache_header *pHeader; + struct hash_entry *pHashEntry; entry_header *pEntry; - URLCACHECONTAINER * pContainer; + cache_container *pContainer; DWORD error; TRACE("(%s, %p, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, dwFieldControl); - error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); + error = cache_containers_find(lpszUrlName, &pContainer); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2035,7 +2068,7 @@ BOOL WINAPI SetUrlCacheEntryInfoA( if (!(pHeader = cache_container_lock_index(pContainer))) return FALSE; - if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) + if (!urlcache_find_hash_entry(pHeader, lpszUrlName, &pHashEntry)) { cache_container_unlock_index(pContainer, pHeader); WARN("entry %s not found!\n", debugstr_a(lpszUrlName)); @@ -2043,7 +2076,7 @@ BOOL WINAPI SetUrlCacheEntryInfoA( return FALSE; } - pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); + pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->offset); if (pEntry->signature != URL_SIGNATURE) { cache_container_unlock_index(pContainer, pHeader); @@ -2052,10 +2085,7 @@ BOOL WINAPI SetUrlCacheEntryInfoA( return FALSE; } - URLCache_SetEntryInfo( - (entry_url *)pEntry, - (const INTERNET_CACHE_ENTRY_INFOW *)lpCacheEntryInfo, - dwFieldControl); + urlcache_set_entry_info((entry_url*)pEntry, lpCacheEntryInfo, dwFieldControl); cache_container_unlock_index(pContainer, pHeader); @@ -2065,267 +2095,135 @@ BOOL WINAPI SetUrlCacheEntryInfoA( /*********************************************************************** * SetUrlCacheEntryInfoW (WININET.@) */ -BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, DWORD dwFieldControl) +BOOL WINAPI SetUrlCacheEntryInfoW(LPCWSTR lpszUrl, + LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, + DWORD dwFieldControl) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - entry_header *pEntry; - URLCACHECONTAINER * pContainer; - DWORD error; - - TRACE("(%s, %p, 0x%08x)\n", debugstr_w(lpszUrl), lpCacheEntryInfo, dwFieldControl); - - error = URLCacheContainers_FindContainerW(lpszUrl, &pContainer); - if (error != ERROR_SUCCESS) - { - SetLastError(error); - return FALSE; - } - - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { - SetLastError(error); - return FALSE; - } - - if (!(pHeader = cache_container_lock_index(pContainer))) - return FALSE; - - if (!URLCache_FindHashW(pHeader, lpszUrl, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - WARN("entry %s not found!\n", debugstr_w(lpszUrl)); - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } + char *url; + BOOL ret; - pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (pEntry->signature != URL_SIGNATURE) - { - cache_container_unlock_index(pContainer, pHeader); - FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->signature, sizeof(DWORD))); - SetLastError(ERROR_FILE_NOT_FOUND); + if(!urlcache_encode_url_alloc(lpszUrl, &url)) return FALSE; - } - - URLCache_SetEntryInfo( - (entry_url *)pEntry, - lpCacheEntryInfo, - dwFieldControl); - - cache_container_unlock_index(pContainer, pHeader); - return TRUE; + ret = SetUrlCacheEntryInfoA(url, (INTERNET_CACHE_ENTRY_INFOA*)lpCacheEntryInfo, dwFieldControl); + heap_free(url); + return ret; } -/*********************************************************************** - * RetrieveUrlCacheEntryFileA (WININET.@) - * - */ -BOOL WINAPI RetrieveUrlCacheEntryFileA( - IN LPCSTR lpszUrlName, - OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, - IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, - IN DWORD dwReserved - ) +static BOOL urlcache_entry_get_file(const char *url, void *entry_info, DWORD *size, BOOL unicode) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - entry_header *pEntry; - entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; + urlcache_header *header; + struct hash_entry *hash_entry; + entry_url *url_entry; + cache_container *container; DWORD error; - TRACE("(%s, %p, %p, 0x%08x)\n", - debugstr_a(lpszUrlName), - lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, - dwReserved); + TRACE("(%s, %p, %p, %x)\n", debugstr_a(url), entry_info, size, unicode); - if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize || - (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize)) - { + if(!url || !size || (!entry_info && *size)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); - if (error != ERROR_SUCCESS) - { + error = cache_containers_find(url, &container); + if(error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { + error = cache_container_open_index(container, MIN_BLOCK_NO); + if (error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - if (!(pHeader = cache_container_lock_index(pContainer))) + if (!(header = cache_container_lock_index(container))) return FALSE; - if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - TRACE("entry %s not found!\n", lpszUrlName); + if (!urlcache_find_hash_entry(header, url, &hash_entry)) { + cache_container_unlock_index(container, header); + TRACE("entry %s not found!\n", url); SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } - pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (pEntry->signature != URL_SIGNATURE) - { - cache_container_unlock_index(pContainer, pHeader); - FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->signature, sizeof(DWORD))); + url_entry = (entry_url*)((LPBYTE)header + hash_entry->offset); + if(url_entry->header.signature != URL_SIGNATURE) { + cache_container_unlock_index(container, header); + FIXME("Trying to retrieve entry of unknown format %s\n", + debugstr_an((LPSTR)&url_entry->header.signature, sizeof(DWORD))); SetLastError(ERROR_FILE_NOT_FOUND); return FALSE; } - pUrlEntry = (entry_url *)pEntry; - if (!pUrlEntry->local_name_off) - { - cache_container_unlock_index(pContainer, pHeader); + if(!url_entry->local_name_off) { + cache_container_unlock_index(container, header); SetLastError(ERROR_INVALID_DATA); return FALSE; } - TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->url_off)); - TRACE("Header info: %s\n", debugstr_an((LPCSTR)pUrlEntry + pUrlEntry->header_info_off, - pUrlEntry->header_info_size)); + TRACE("Found URL: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->url_off)); + TRACE("Header info: %s\n", debugstr_an((LPCSTR)url_entry + url_entry->header_info_off, + url_entry->header_info_size)); - error = URLCache_CopyEntry(pContainer, pHeader, lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, pUrlEntry, - FALSE); - if (error != ERROR_SUCCESS) - { - cache_container_unlock_index(pContainer, pHeader); + error = urlcache_copy_entry(container, header, entry_info, + size, url_entry, unicode); + if(error != ERROR_SUCCESS) { + cache_container_unlock_index(container, header); SetLastError(error); return FALSE; } - TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->local_name_off)); + TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)url_entry + url_entry->local_name_off)); - pUrlEntry->hit_rate++; - pUrlEntry->use_count++; - URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_LOCK); - GetSystemTimeAsFileTime(&pUrlEntry->access_time); + url_entry->hit_rate++; + url_entry->use_count++; + urlcache_hash_entry_set_flags(hash_entry, HASHTABLE_LOCK); + GetSystemTimeAsFileTime(&url_entry->access_time); - cache_container_unlock_index(pContainer, pHeader); + cache_container_unlock_index(container, header); return TRUE; } /*********************************************************************** - * RetrieveUrlCacheEntryFileW (WININET.@) + * RetrieveUrlCacheEntryFileA (WININET.@) * */ -BOOL WINAPI RetrieveUrlCacheEntryFileW( - IN LPCWSTR lpszUrlName, - OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, - IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, - IN DWORD dwReserved - ) +BOOL WINAPI RetrieveUrlCacheEntryFileA(LPCSTR lpszUrlName, + LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufferSize, DWORD dwReserved) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - entry_header *pEntry; - entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; - DWORD error; - - TRACE("(%s, %p, %p, 0x%08x)\n", - debugstr_w(lpszUrlName), - lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, - dwReserved); - - if (!lpszUrlName || !lpdwCacheEntryInfoBufferSize || - (!lpCacheEntryInfo && *lpdwCacheEntryInfoBufferSize)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); - if (error != ERROR_SUCCESS) - { - SetLastError(error); - return FALSE; - } - - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { - SetLastError(error); - return FALSE; - } - - if (!(pHeader = cache_container_lock_index(pContainer))) - return FALSE; - - if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - TRACE("entry %s not found!\n", debugstr_w(lpszUrlName)); - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (pEntry->signature != URL_SIGNATURE) - { - cache_container_unlock_index(pContainer, pHeader); - FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->signature, sizeof(DWORD))); - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - pUrlEntry = (entry_url *)pEntry; - if (!pUrlEntry->local_name_off) - { - cache_container_unlock_index(pContainer, pHeader); - SetLastError(ERROR_INVALID_DATA); - return FALSE; - } + return urlcache_entry_get_file(lpszUrlName, lpCacheEntryInfo, + lpdwCacheEntryInfoBufferSize, FALSE); +} - TRACE("Found URL: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->url_off)); - TRACE("Header info: %s\n", debugstr_an((LPCSTR)pUrlEntry + pUrlEntry->header_info_off, - pUrlEntry->header_info_size)); +/*********************************************************************** + * RetrieveUrlCacheEntryFileW (WININET.@) + * + */ +BOOL WINAPI RetrieveUrlCacheEntryFileW(LPCWSTR lpszUrlName, + LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufferSize, DWORD dwReserved) +{ + char *url; + BOOL ret; - error = URLCache_CopyEntry( - pContainer, - pHeader, - (LPINTERNET_CACHE_ENTRY_INFOA)lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, - pUrlEntry, - TRUE /* UNICODE */); - if (error != ERROR_SUCCESS) - { - cache_container_unlock_index(pContainer, pHeader); - SetLastError(error); + if(!urlcache_encode_url_alloc(lpszUrlName, &url)) return FALSE; - } - TRACE("Local File Name: %s\n", debugstr_a((LPCSTR)pUrlEntry + pUrlEntry->local_name_off)); - - pUrlEntry->hit_rate++; - pUrlEntry->use_count++; - URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_LOCK); - GetSystemTimeAsFileTime(&pUrlEntry->access_time); - - cache_container_unlock_index(pContainer, pHeader); - return TRUE; + ret = urlcache_entry_get_file(url, lpCacheEntryInfo, + lpdwCacheEntryInfoBufferSize, TRUE); + heap_free(url); + return ret; } -static BOOL DeleteUrlCacheEntryInternal(const URLCACHECONTAINER * pContainer, - LPURLCACHE_HEADER pHeader, struct _HASH_ENTRY *pHashEntry) +static BOOL urlcache_entry_delete(const cache_container *pContainer, + urlcache_header *pHeader, struct hash_entry *pHashEntry) { entry_header *pEntry; entry_url * pUrlEntry; - pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); + pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->offset); if (pEntry->signature != URL_SIGNATURE) { FIXME("Trying to delete entry of unknown format %s\n", @@ -2335,7 +2233,7 @@ static BOOL DeleteUrlCacheEntryInternal(const URLCACHECONTAINER * pContainer, } pUrlEntry = (entry_url *)pEntry; - if(URLCache_IsLocked(pHashEntry, pUrlEntry)) + if(urlcache_hash_entry_is_locked(pHashEntry, pUrlEntry)) { TRACE("Trying to delete locked entry\n"); pUrlEntry->cache_entry_type |= PENDING_DELETE_CACHE_ENTRY; @@ -2343,19 +2241,19 @@ static BOOL DeleteUrlCacheEntryInternal(const URLCACHECONTAINER * pContainer, return FALSE; } - if(!URLCache_DeleteFile(pContainer, pHeader, pUrlEntry)) + if(!urlcache_delete_file(pContainer, pHeader, pUrlEntry)) { - URLCache_DeleteEntry(pHeader, pEntry); + urlcache_entry_free(pHeader, pEntry); } else { /* Add entry to leaked files list */ pUrlEntry->header.signature = LEAK_SIGNATURE; pUrlEntry->exempt_delta = pHeader->options[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET]; - pHeader->options[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET] = pHashEntry->dwOffsetEntry; + pHeader->options[CACHE_HEADER_DATA_ROOT_LEAK_OFFSET] = pHashEntry->offset; } - URLCache_DeleteEntryFromHash(pHashEntry); + urlcache_hash_entry_delete(pHashEntry); return TRUE; } @@ -2377,49 +2275,49 @@ static void handle_full_cache(void) } /* Enumerates entries in cache, allows cache unlocking between calls. */ -static BOOL urlcache_next_entry(URLCACHE_HEADER *header, DWORD *hash_table_off, DWORD *hash_table_entry, - struct _HASH_ENTRY **hash_entry, entry_header **entry) +static BOOL urlcache_next_entry(urlcache_header *header, DWORD *hash_table_off, DWORD *hash_table_entry, + struct hash_entry **hash_entry, entry_header **entry) { - HASH_CACHEFILE_ENTRY *hashtable_entry; + entry_hash_table *hashtable_entry; *hash_entry = NULL; *entry = NULL; if(!*hash_table_off) { - *hash_table_off = header->dwOffsetFirstHashTable; + *hash_table_off = header->hash_table_off; *hash_table_entry = 0; - hashtable_entry = URLCache_HashEntryFromOffset(header, *hash_table_off); + hashtable_entry = urlcache_get_hash_table(header, *hash_table_off); }else { - if(*hash_table_off >= header->dwFileSize) { + if(*hash_table_off >= header->size) { *hash_table_off = 0; return FALSE; } - hashtable_entry = URLCache_HashEntryFromOffset(header, *hash_table_off); + hashtable_entry = urlcache_get_hash_table(header, *hash_table_off); } - if(hashtable_entry->CacheFileEntry.signature != HASH_SIGNATURE) { + if(hashtable_entry->header.signature != HASH_SIGNATURE) { *hash_table_off = 0; return FALSE; } while(1) { if(*hash_table_entry >= HASHTABLE_SIZE) { - *hash_table_off = hashtable_entry->dwAddressNext; + *hash_table_off = hashtable_entry->next; if(!*hash_table_off) { *hash_table_off = 0; return FALSE; } - hashtable_entry = URLCache_HashEntryFromOffset(header, *hash_table_off); + hashtable_entry = urlcache_get_hash_table(header, *hash_table_off); *hash_table_entry = 0; } - if(hashtable_entry->HashTable[*hash_table_entry].dwHashKey != HASHTABLE_DEL && - hashtable_entry->HashTable[*hash_table_entry].dwHashKey != HASHTABLE_FREE) { - *hash_entry = &hashtable_entry->HashTable[*hash_table_entry]; - *entry = (entry_header*)((LPBYTE)header + hashtable_entry->HashTable[*hash_table_entry].dwOffsetEntry); + if(hashtable_entry->hash_table[*hash_table_entry].key != HASHTABLE_DEL && + hashtable_entry->hash_table[*hash_table_entry].key != HASHTABLE_FREE) { + *hash_entry = &hashtable_entry->hash_table[*hash_table_entry]; + *entry = (entry_header*)((LPBYTE)header + hashtable_entry->hash_table[*hash_table_entry].offset); (*hash_table_entry)++; return TRUE; } @@ -2494,7 +2392,7 @@ static int dword_cmp(const void *p1, const void *p2) */ BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter) { - URLCACHECONTAINER *container; + cache_container *container; DWORD path_len, err; TRACE("(%s, %x, %x)\n", debugstr_w(cache_path), size, filter); @@ -2513,7 +2411,7 @@ BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter) } if(size==100 && !filter) { - LIST_FOR_EACH_ENTRY(container, &UrlContainers, URLCACHECONTAINER, entry) + LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry) { /* When cache_path==NULL only clean Temporary Internet Files */ if((!path_len && container->cache_prefix[0]==0) || @@ -2522,14 +2420,14 @@ BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter) { BOOL ret_del; - WaitForSingleObject(container->hMutex, INFINITE); + WaitForSingleObject(container->mutex, INFINITE); /* unlock, delete, recreate and lock cache */ cache_container_close_index(container); - ret_del = URLCache_DeleteCacheDirectory(container->path); + ret_del = cache_container_delete_dir(container->path); err = cache_container_open_index(container, MIN_BLOCK_NO); - ReleaseMutex(container->hMutex); + ReleaseMutex(container->mutex); if(!ret_del || (err != ERROR_SUCCESS)) return FALSE; } @@ -2538,10 +2436,10 @@ BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter) return TRUE; } - LIST_FOR_EACH_ENTRY(container, &UrlContainers, URLCACHECONTAINER, entry) + LIST_FOR_EACH_ENTRY(container, &UrlContainers, cache_container, entry) { - URLCACHE_HEADER *header; - struct _HASH_ENTRY *hash_entry; + urlcache_header *header; + struct hash_entry *hash_entry; entry_header *entry; entry_url *url_entry; ULONGLONG desired_size, cur_size; @@ -2564,8 +2462,8 @@ BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter) urlcache_clean_leaked_entries(container, header); - desired_size = header->CacheLimit.QuadPart*(100-size)/100; - cur_size = header->CacheUsage.QuadPart+header->ExemptUsage.QuadPart; + desired_size = header->cache_limit.QuadPart*(100-size)/100; + cur_size = header->cache_usage.QuadPart+header->exempt_usage.QuadPart; if(cur_size <= desired_size) delete_factor = 0; else @@ -2619,9 +2517,9 @@ BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter) if(urlcache_rate_entry(url_entry, &cur_time) <= delete_factor) { TRACE("deleting file: %s\n", debugstr_a((char*)url_entry+url_entry->local_name_off)); - DeleteUrlCacheEntryInternal(container, header, hash_entry); + urlcache_entry_delete(container, header, hash_entry); - if(header->CacheUsage.QuadPart+header->ExemptUsage.QuadPart <= desired_size) + if(header->cache_usage.QuadPart+header->exempt_usage.QuadPart <= desired_size) break; /* Allow other threads to use cache while cleaning */ @@ -2636,8 +2534,8 @@ BOOL WINAPI FreeUrlCacheSpaceW(LPCWSTR cache_path, DWORD size, DWORD filter) } TRACE("cache size after cleaning 0x%s/0x%s\n", - wine_dbgstr_longlong(header->CacheUsage.QuadPart+header->ExemptUsage.QuadPart), - wine_dbgstr_longlong(header->CacheLimit.QuadPart)); + wine_dbgstr_longlong(header->cache_usage.QuadPart+header->exempt_usage.QuadPart), + wine_dbgstr_longlong(header->cache_limit.QuadPart)); cache_container_unlock_index(container, header); } @@ -2663,16 +2561,13 @@ BOOL WINAPI FreeUrlCacheSpaceA(LPCSTR lpszCachePath, DWORD dwSize, DWORD dwFilte * UnlockUrlCacheEntryFileA (WININET.@) * */ -BOOL WINAPI UnlockUrlCacheEntryFileA( - IN LPCSTR lpszUrlName, - IN DWORD dwReserved - ) +BOOL WINAPI UnlockUrlCacheEntryFileA(LPCSTR lpszUrlName, DWORD dwReserved) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; + urlcache_header *pHeader; + struct hash_entry *pHashEntry; entry_header *pEntry; entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; + cache_container *pContainer; DWORD error; TRACE("(%s, 0x%08x)\n", debugstr_a(lpszUrlName), dwReserved); @@ -2684,7 +2579,7 @@ BOOL WINAPI UnlockUrlCacheEntryFileA( return FALSE; } - error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); + error = cache_containers_find(lpszUrlName, &pContainer); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -2701,7 +2596,7 @@ BOOL WINAPI UnlockUrlCacheEntryFileA( if (!(pHeader = cache_container_lock_index(pContainer))) return FALSE; - if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) + if (!urlcache_find_hash_entry(pHeader, lpszUrlName, &pHashEntry)) { cache_container_unlock_index(pContainer, pHeader); TRACE("entry %s not found!\n", lpszUrlName); @@ -2709,7 +2604,7 @@ BOOL WINAPI UnlockUrlCacheEntryFileA( return FALSE; } - pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); + pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->offset); if (pEntry->signature != URL_SIGNATURE) { cache_container_unlock_index(pContainer, pHeader); @@ -2728,9 +2623,9 @@ BOOL WINAPI UnlockUrlCacheEntryFileA( pUrlEntry->use_count--; if (!pUrlEntry->use_count) { - URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_URL); + urlcache_hash_entry_set_flags(pHashEntry, HASHTABLE_URL); if (pUrlEntry->cache_entry_type & PENDING_DELETE_CACHE_ENTRY) - DeleteUrlCacheEntryInternal(pContainer, pHeader, pHashEntry); + urlcache_entry_delete(pContainer, pHeader, pHashEntry); } cache_container_unlock_index(pContainer, pHeader); @@ -2742,324 +2637,162 @@ BOOL WINAPI UnlockUrlCacheEntryFileA( * UnlockUrlCacheEntryFileW (WININET.@) * */ -BOOL WINAPI UnlockUrlCacheEntryFileW( LPCWSTR lpszUrlName, DWORD dwReserved ) +BOOL WINAPI UnlockUrlCacheEntryFileW(LPCWSTR lpszUrlName, DWORD dwReserved) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - entry_header *pEntry; - entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; - DWORD error; - - TRACE("(%s, 0x%08x)\n", debugstr_w(lpszUrlName), dwReserved); - - if (dwReserved) - { - ERR("dwReserved != 0\n"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); - if (error != ERROR_SUCCESS) - { - SetLastError(error); - return FALSE; - } - - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { - SetLastError(error); - return FALSE; - } - - if (!(pHeader = cache_container_lock_index(pContainer))) - return FALSE; - - if (!URLCache_FindHashW(pHeader, lpszUrlName, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - TRACE("entry %s not found!\n", debugstr_w(lpszUrlName)); - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - pEntry = (entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (pEntry->signature != URL_SIGNATURE) - { - cache_container_unlock_index(pContainer, pHeader); - FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPSTR)&pEntry->signature, sizeof(DWORD))); - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - pUrlEntry = (entry_url *)pEntry; + char *url; + BOOL ret; - if (pUrlEntry->use_count == 0) - { - cache_container_unlock_index(pContainer, pHeader); + if(!urlcache_encode_url_alloc(lpszUrlName, &url)) return FALSE; - } - pUrlEntry->use_count--; - if (!pUrlEntry->use_count) - URLCache_HashEntrySetFlags(pHashEntry, HASHTABLE_URL); - cache_container_unlock_index(pContainer, pHeader); - - return TRUE; + ret = UnlockUrlCacheEntryFileA(url, dwReserved); + heap_free(url); + return ret; } -/*********************************************************************** - * CreateUrlCacheEntryA (WININET.@) - * - */ -BOOL WINAPI CreateUrlCacheEntryA( - IN LPCSTR lpszUrlName, - IN DWORD dwExpectedFileSize, - IN LPCSTR lpszFileExtension, - OUT LPSTR lpszFileName, - IN DWORD dwReserved -) -{ - WCHAR *url_name; - WCHAR *file_extension = NULL; - WCHAR file_name[MAX_PATH]; - BOOL bSuccess = FALSE; - DWORD dwError = 0; - - TRACE("(%s %d %s %p %d)\n", debugstr_a(lpszUrlName), dwExpectedFileSize, - debugstr_a(lpszFileExtension), lpszFileName, dwReserved); - - if (lpszUrlName && (url_name = heap_strdupAtoW(lpszUrlName))) - { - if (!lpszFileExtension || (file_extension = heap_strdupAtoW(lpszFileExtension))) - { - if (CreateUrlCacheEntryW(url_name, dwExpectedFileSize, file_extension, file_name, dwReserved)) - { - if (WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL) < MAX_PATH) - { - bSuccess = TRUE; - } - else - { - dwError = GetLastError(); - } - } - else - { - dwError = GetLastError(); - } - heap_free(file_extension); - } - else - { - dwError = GetLastError(); - } - heap_free(url_name); - if (!bSuccess) SetLastError(dwError); - } - return bSuccess; -} -/*********************************************************************** - * CreateUrlCacheEntryW (WININET.@) - * - */ -BOOL WINAPI CreateUrlCacheEntryW( - IN LPCWSTR lpszUrlName, - IN DWORD dwExpectedFileSize, - IN LPCWSTR lpszFileExtension, - OUT LPWSTR lpszFileName, - IN DWORD dwReserved -) +static BOOL urlcache_entry_create(const char *url, const char *ext, WCHAR *full_path) { - URLCACHECONTAINER * pContainer; - LPURLCACHE_HEADER pHeader; - CHAR szFile[MAX_PATH]; - WCHAR szExtension[MAX_PATH]; - LPCWSTR lpszUrlPart; - LPCWSTR lpszUrlEnd; - LPCWSTR lpszFileNameExtension; - LPWSTR lpszFileNameNoPath; - int i; - int countnoextension; - BYTE CacheDir; - LONG lBufferSize; - BOOL bFound = FALSE; + cache_container *container; + urlcache_header *header; + char file_name[MAX_PATH]; + WCHAR extW[MAX_PATH]; + BYTE cache_dir; + LONG full_path_len; BOOL generate_name = FALSE; - int count; DWORD error; - HANDLE hFile; + HANDLE file; FILETIME ft; + URL_COMPONENTSA uc; + int i; - static const WCHAR szWWW[] = {'w','w','w',0}; - - TRACE("(%s, 0x%08x, %s, %p, 0x%08x)\n", - debugstr_w(lpszUrlName), - dwExpectedFileSize, - debugstr_w(lpszFileExtension), - lpszFileName, - dwReserved); + TRACE("(%s, %s, %p)\n", debugstr_a(url), debugstr_a(ext), full_path); - if (dwReserved) - FIXME("dwReserved 0x%08x\n", dwReserved); + memset(&uc, 0, sizeof(uc)); + uc.dwStructSize = sizeof(uc); + uc.dwUrlPathLength = 1; + uc.dwExtraInfoLength = 1; + if(!InternetCrackUrlA(url, 0, 0, &uc)) + uc.dwUrlPathLength = 0; - lpszUrlEnd = lpszUrlName + strlenW(lpszUrlName); - - if (((lpszUrlEnd - lpszUrlName) > 1) && (*(lpszUrlEnd - 1) == '/' || *(lpszUrlEnd - 1) == '\\')) - lpszUrlEnd--; - - lpszUrlPart = memchrW(lpszUrlName, '?', lpszUrlEnd - lpszUrlName); - if (!lpszUrlPart) - lpszUrlPart = memchrW(lpszUrlName, '#', lpszUrlEnd - lpszUrlName); - if (lpszUrlPart) - lpszUrlEnd = lpszUrlPart; - - for (lpszUrlPart = lpszUrlEnd; - (lpszUrlPart >= lpszUrlName); - lpszUrlPart--) - { - if ((*lpszUrlPart == '/' || *lpszUrlPart == '\\') && ((lpszUrlEnd - lpszUrlPart) > 1)) - { - bFound = TRUE; - lpszUrlPart++; - break; + if(!uc.dwUrlPathLength) { + file_name[0] = 0; + }else { + char *p, *e; + + p = e = uc.lpszUrlPath+uc.dwUrlPathLength; + while(p>uc.lpszUrlPath && *(p-1)!='/' && *(p-1)!='\\' && *(p-1)!='.') + p--; + if(p>uc.lpszUrlPath && *(p-1)=='.') { + e = p-1; + while(p>uc.lpszUrlPath && *(p-1)!='/' && *(p-1)!='\\') + p--; } - } - if(!bFound) - lpszUrlPart++; - if (!lstrcmpW(lpszUrlPart, szWWW)) - { - lpszUrlPart += lstrlenW(szWWW); - } - - count = lpszUrlEnd - lpszUrlPart; - - if (bFound && (count < MAX_PATH)) - { - int len = WideCharToMultiByte(CP_ACP, 0, lpszUrlPart, count, szFile, sizeof(szFile) - 1, NULL, NULL); - if (!len) - return FALSE; - szFile[len] = '\0'; - while(len && szFile[--len] == '/') szFile[len] = '\0'; + memcpy(file_name, p, e-p); + file_name[e-p] = 0; - /* FIXME: get rid of illegal characters like \, / and : */ - TRACE("File name: %s\n", debugstr_a(szFile)); + for(p=file_name; *p; p++) { + switch(*p) { + case '<': case '>': + case ':': case '"': + case '|': case '?': + case '*': + *p = '_'; break; + default: break; + } + } } - else - { + + if(!file_name[0]) generate_name = TRUE; - szFile[0] = 0; - } - error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); - if (error != ERROR_SUCCESS) - { + error = cache_containers_find(url, &container); + if(error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { + error = cache_container_open_index(container, MIN_BLOCK_NO); + if(error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - if (!(pHeader = cache_container_lock_index(pContainer))) + if(!(header = cache_container_lock_index(container))) return FALSE; - if(pHeader->DirectoryCount) - CacheDir = (BYTE)(rand() % pHeader->DirectoryCount); + if(header->dirs_no) + cache_dir = (BYTE)(rand() % header->dirs_no); else - CacheDir = CACHE_CONTAINER_NO_SUBDIR; + cache_dir = CACHE_CONTAINER_NO_SUBDIR; - lBufferSize = MAX_PATH * sizeof(WCHAR); - if (!URLCache_LocalFileNameToPathW(pContainer, pHeader, szFile, CacheDir, lpszFileName, &lBufferSize)) - { + full_path_len = MAX_PATH * sizeof(WCHAR); + if(!urlcache_create_file_pathW(container, header, file_name, cache_dir, full_path, &full_path_len)) { WARN("Failed to get full path for filename %s, needed %u bytes.\n", - debugstr_a(szFile), lBufferSize); - cache_container_unlock_index(pContainer, pHeader); + debugstr_a(file_name), full_path_len); + cache_container_unlock_index(container, header); return FALSE; } + full_path_len = full_path_len/sizeof(WCHAR) - 1; - cache_container_unlock_index(pContainer, pHeader); - - for (lpszFileNameNoPath = lpszFileName + lBufferSize / sizeof(WCHAR) - 2; - lpszFileNameNoPath >= lpszFileName; - --lpszFileNameNoPath) - { - if (*lpszFileNameNoPath == '/' || *lpszFileNameNoPath == '\\') - break; - } - - countnoextension = lstrlenW(lpszFileNameNoPath); - lpszFileNameExtension = PathFindExtensionW(lpszFileNameNoPath); - if (lpszFileNameExtension) - countnoextension -= lstrlenW(lpszFileNameExtension); - *szExtension = '\0'; - - if (lpszFileExtension) - { - szExtension[0] = '.'; - lstrcpyW(szExtension+1, lpszFileExtension); - } + cache_container_unlock_index(container, header); - for (i = 0; i<255 && !generate_name; i++) - { - static const WCHAR szFormat[] = {'[','%','u',']','%','s',0}; + if(ext) { WCHAR *p; - wsprintfW(lpszFileNameNoPath + countnoextension, szFormat, i, szExtension); - for (p = lpszFileNameNoPath + 1; *p; p++) - { - switch (*p) - { + extW[0] = '.'; + MultiByteToWideChar(CP_ACP, 0, ext, -1, extW+1, MAX_PATH-1); + + for(p=extW; *p; p++) { + switch(*p) { case '<': case '>': case ':': case '"': - case '/': case '\\': case '|': case '?': case '*': *p = '_'; break; default: break; } } - if (p[-1] == ' ' || p[-1] == '.') p[-1] = '_'; + if(p[-1]==' ' || p[-1]=='.') + p[-1] = '_'; + }else { + extW[0] = '\0'; + } - TRACE("Trying: %s\n", debugstr_w(lpszFileName)); - hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - CloseHandle(hFile); + for(i=0; i<255 && !generate_name; i++) { + static const WCHAR format[] = {'[','%','u',']','%','s',0}; + + wsprintfW(full_path+full_path_len, format, i, extW); + + TRACE("Trying: %s\n", debugstr_w(full_path)); + file = CreateFileW(full_path, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); + if(file != INVALID_HANDLE_VALUE) { + CloseHandle(file); return TRUE; } } /* Try to generate random name */ GetSystemTimeAsFileTime(&ft); - strcpyW(lpszFileNameNoPath+countnoextension+8, szExtension); + strcpyW(full_path+full_path_len+8, extW); - for(i=0; i<255; i++) - { + for(i=0; i<255; i++) { int j; ULONGLONG n = ft.dwHighDateTime; n <<= 32; n += ft.dwLowDateTime; n ^= (ULONGLONG)i<<48; - for(j=0; j<8; j++) - { + for(j=0; j<8; j++) { int r = (n % 36); n /= 37; - lpszFileNameNoPath[countnoextension+j] = (r < 10 ? '0' + r : 'A' + r - 10); + full_path[full_path_len+j] = (r < 10 ? '0' + r : 'A' + r - 10); } - TRACE("Trying: %s\n", debugstr_w(lpszFileName)); - hFile = CreateFileW(lpszFileName, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - CloseHandle(hFile); + TRACE("Trying: %s\n", debugstr_w(full_path)); + file = CreateFileW(full_path, GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL); + if(file != INVALID_HANDLE_VALUE) { + CloseHandle(file); return TRUE; } } @@ -3069,403 +2802,340 @@ BOOL WINAPI CreateUrlCacheEntryW( } /*********************************************************************** - * CommitUrlCacheEntryInternal (Compensates for an MS bug) + * CreateUrlCacheEntryA (WININET.@) * - * The bug we are compensating for is that some drongo at Microsoft - * used lpHeaderInfo to pass binary data to CommitUrlCacheEntryA. - * As a consequence, CommitUrlCacheEntryA has been effectively - * redefined as LPBYTE rather than LPCSTR. But CommitUrlCacheEntryW - * is still defined as LPCWSTR. The result (other than madness) is - * that we always need to store lpHeaderInfo in CP_ACP rather than - * in UTF16, and we need to avoid converting lpHeaderInfo in - * CommitUrlCacheEntryA to UTF16 and then back to CP_ACP, since the - * result will lose data for arbitrary binary data. + */ +BOOL WINAPI CreateUrlCacheEntryA(LPCSTR lpszUrlName, DWORD dwExpectedFileSize, + LPCSTR lpszFileExtension, LPSTR lpszFileName, DWORD dwReserved) +{ + WCHAR file_name[MAX_PATH]; + + if(dwReserved) + FIXME("dwReserved 0x%08x\n", dwReserved); + + if(!urlcache_entry_create(lpszUrlName, lpszFileExtension, file_name)) + return FALSE; + + if(!WideCharToMultiByte(CP_ACP, 0, file_name, -1, lpszFileName, MAX_PATH, NULL, NULL)) + return FALSE; + return TRUE; +} +/*********************************************************************** + * CreateUrlCacheEntryW (WININET.@) * */ -static BOOL CommitUrlCacheEntryInternal( - IN LPCWSTR lpszUrlName, - IN LPCWSTR lpszLocalFileName, - IN FILETIME ExpireTime, - IN FILETIME LastModifiedTime, - IN DWORD CacheEntryType, - IN LPBYTE lpHeaderInfo, - IN DWORD dwHeaderSize, - IN LPCWSTR lpszFileExtension, - IN LPCWSTR lpszOriginalUrl - ) +BOOL WINAPI CreateUrlCacheEntryW(LPCWSTR lpszUrlName, DWORD dwExpectedFileSize, + LPCWSTR lpszFileExtension, LPWSTR lpszFileName, DWORD dwReserved) { - URLCACHECONTAINER * pContainer; - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - entry_header *pEntry; - entry_url * pUrlEntry; + char *url, *ext = NULL; + BOOL ret; + + if(dwReserved) + FIXME("dwReserved 0x%08x\n", dwReserved); + + if(lpszFileExtension) { + ext = heap_strdupWtoUTF8(lpszFileExtension); + if(!ext) + return FALSE; + } + + if(!urlcache_encode_url_alloc(lpszUrlName, &url)) { + heap_free(ext); + return FALSE; + } + + ret = urlcache_entry_create(url, ext, lpszFileName); + heap_free(ext); + heap_free(url); + return ret; +} + +static BOOL urlcache_entry_commit(const char *url, const WCHAR *file_name, + FILETIME expire_time, FILETIME modify_time, DWORD entry_type, + BYTE *header_info, DWORD header_size, const char *file_ext, + const char *original_url) +{ + cache_container *container; + urlcache_header *header; + struct hash_entry *hash_entry; + entry_header *entry; + entry_url *url_entry; DWORD url_entry_offset; - DWORD dwBytesNeeded = DWORD_ALIGN(sizeof(*pUrlEntry)); - DWORD dwOffsetLocalFileName = 0; - DWORD dwOffsetHeader = 0; - DWORD dwOffsetFileExtension = 0; + DWORD size = DWORD_ALIGN(sizeof(*url_entry)); + DWORD file_name_off = 0; + DWORD header_info_off = 0; + DWORD file_ext_off = 0; WIN32_FILE_ATTRIBUTE_DATA file_attr; LARGE_INTEGER file_size; - BYTE cDirectory; - char achFile[MAX_PATH]; - LPSTR lpszUrlNameA = NULL; - LPSTR lpszFileExtensionA = NULL; - char *pchLocalFileName = 0; + BYTE dir_id; + char file_name_no_container[MAX_PATH]; + char *local_file_name = 0; DWORD hit_rate = 0; DWORD exempt_delta = 0; DWORD error; - TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", - debugstr_w(lpszUrlName), - debugstr_w(lpszLocalFileName), - CacheEntryType, - lpHeaderInfo, - dwHeaderSize, - debugstr_w(lpszFileExtension), - debugstr_w(lpszOriginalUrl)); + TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", debugstr_a(url), debugstr_w(file_name), + entry_type, header_info, header_size, debugstr_a(file_ext), debugstr_a(original_url)); - if (CacheEntryType & STICKY_CACHE_ENTRY && !lpszLocalFileName) - { + if(entry_type & STICKY_CACHE_ENTRY && !file_name) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (lpszOriginalUrl) - WARN(": lpszOriginalUrl ignored\n"); + if(original_url) + WARN(": original_url ignored\n"); memset(&file_attr, 0, sizeof(file_attr)); - if (lpszLocalFileName) - { - if(!GetFileAttributesExW(lpszLocalFileName, GetFileExInfoStandard, &file_attr)) + if(file_name) { + if(!GetFileAttributesExW(file_name, GetFileExInfoStandard, &file_attr)) return FALSE; } file_size.u.LowPart = file_attr.nFileSizeLow; file_size.u.HighPart = file_attr.nFileSizeHigh; - error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); - if (error != ERROR_SUCCESS) - { + error = cache_containers_find(url, &container); + if(error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { + error = cache_container_open_index(container, MIN_BLOCK_NO); + if(error != ERROR_SUCCESS) { SetLastError(error); return FALSE; } - if (!(pHeader = cache_container_lock_index(pContainer))) + if(!(header = cache_container_lock_index(container))) return FALSE; - lpszUrlNameA = heap_strdupWtoA(lpszUrlName); - if (!lpszUrlNameA) - { - error = GetLastError(); - goto cleanup; - } - - if (lpszFileExtension && !(lpszFileExtensionA = heap_strdupWtoA(lpszFileExtension))) - { - error = GetLastError(); - goto cleanup; - } + if(urlcache_find_hash_entry(header, url, &hash_entry)) { + entry_url *url_entry = (entry_url*)((LPBYTE)header + hash_entry->offset); - if (URLCache_FindHash(pHeader, lpszUrlNameA, &pHashEntry)) - { - entry_url *pUrlEntry = (entry_url*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (URLCache_IsLocked(pHashEntry, pUrlEntry)) - { + if(urlcache_hash_entry_is_locked(hash_entry, url_entry)) { TRACE("Trying to overwrite locked entry\n"); - error = ERROR_SHARING_VIOLATION; - goto cleanup; + cache_container_unlock_index(container, header); + SetLastError(ERROR_SHARING_VIOLATION); + return FALSE; } - hit_rate = pUrlEntry->hit_rate; - exempt_delta = pUrlEntry->exempt_delta; - DeleteUrlCacheEntryInternal(pContainer, pHeader, pHashEntry); + hit_rate = url_entry->hit_rate; + exempt_delta = url_entry->exempt_delta; + urlcache_entry_delete(container, header, hash_entry); } - if (pHeader->DirectoryCount) - cDirectory = 0; + if(header->dirs_no) + dir_id = 0; else - cDirectory = CACHE_CONTAINER_NO_SUBDIR; + dir_id = CACHE_CONTAINER_NO_SUBDIR; - if (lpszLocalFileName) - { + if(file_name) { BOOL bFound = FALSE; - if (strncmpW(lpszLocalFileName, pContainer->path, lstrlenW(pContainer->path))) - { - ERR("path %s must begin with cache content path %s\n", debugstr_w(lpszLocalFileName), debugstr_w(pContainer->path)); - error = ERROR_INVALID_PARAMETER; - goto cleanup; + if(strncmpW(file_name, container->path, lstrlenW(container->path))) { + ERR("path %s must begin with cache content path %s\n", debugstr_w(file_name), debugstr_w(container->path)); + cache_container_unlock_index(container, header); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } /* skip container path prefix */ - lpszLocalFileName += lstrlenW(pContainer->path); + file_name += lstrlenW(container->path); - WideCharToMultiByte(CP_ACP, 0, lpszLocalFileName, -1, achFile, MAX_PATH, NULL, NULL); - pchLocalFileName = achFile; + WideCharToMultiByte(CP_ACP, 0, file_name, -1, file_name_no_container, MAX_PATH, NULL, NULL); + local_file_name = file_name_no_container; - if(pHeader->DirectoryCount) - { - for (cDirectory = 0; cDirectory < pHeader->DirectoryCount; cDirectory++) - { - if (!strncmp(pHeader->directory_data[cDirectory].filename, pchLocalFileName, DIR_LENGTH)) - { + if(header->dirs_no) { + for(dir_id = 0; dir_id < header->dirs_no; dir_id++) { + if(!strncmp(header->directory_data[dir_id].name, local_file_name, DIR_LENGTH)) { bFound = TRUE; break; } } - if (!bFound) - { - ERR("cache directory not found in path %s\n", debugstr_w(lpszLocalFileName)); - error = ERROR_INVALID_PARAMETER; - goto cleanup; + if(!bFound) { + ERR("cache directory not found in path %s\n", debugstr_w(file_name)); + cache_container_unlock_index(container, header); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } - lpszLocalFileName += DIR_LENGTH + 1; - pchLocalFileName += DIR_LENGTH + 1; + file_name += DIR_LENGTH + 1; + local_file_name += DIR_LENGTH + 1; } } - dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszUrlNameA) + 1); - if (lpszLocalFileName) - { - dwOffsetLocalFileName = dwBytesNeeded; - dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(pchLocalFileName) + 1); + size = DWORD_ALIGN(size + strlen(url) + 1); + if(file_name) { + file_name_off = size; + size = DWORD_ALIGN(size + strlen(local_file_name) + 1); } - if (lpHeaderInfo) - { - dwOffsetHeader = dwBytesNeeded; - dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + dwHeaderSize); + if(header_info && header_size) { + header_info_off = size; + size = DWORD_ALIGN(size + header_size); } - if (lpszFileExtensionA) - { - dwOffsetFileExtension = dwBytesNeeded; - dwBytesNeeded = DWORD_ALIGN(dwBytesNeeded + strlen(lpszFileExtensionA) + 1); + if(file_ext && (file_ext_off = strlen(file_ext))) { + DWORD len = file_ext_off; + + file_ext_off = size; + size = DWORD_ALIGN(size + len + 1); } /* round up to next block */ - if (dwBytesNeeded % BLOCKSIZE) - { - dwBytesNeeded -= dwBytesNeeded % BLOCKSIZE; - dwBytesNeeded += BLOCKSIZE; + if(size % BLOCKSIZE) { + size -= size % BLOCKSIZE; + size += BLOCKSIZE; } - error = URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry); - while (error == ERROR_HANDLE_DISK_FULL) - { - error = cache_container_clean_index(pContainer, &pHeader); - if (error == ERROR_SUCCESS) - error = URLCache_FindFirstFreeEntry(pHeader, dwBytesNeeded / BLOCKSIZE, &pEntry); + error = urlcache_entry_alloc(header, size / BLOCKSIZE, &entry); + while(error == ERROR_HANDLE_DISK_FULL) { + error = cache_container_clean_index(container, &header); + if(error == ERROR_SUCCESS) + error = urlcache_entry_alloc(header, size / BLOCKSIZE, &entry); + } + if(error != ERROR_SUCCESS) { + cache_container_unlock_index(container, header); + SetLastError(error); + return FALSE; } - if (error != ERROR_SUCCESS) - goto cleanup; /* FindFirstFreeEntry fills in blocks used */ - pUrlEntry = (entry_url *)pEntry; - url_entry_offset = (LPBYTE)pUrlEntry - (LPBYTE)pHeader; - pUrlEntry->header.signature = URL_SIGNATURE; - pUrlEntry->cache_dir = cDirectory; - pUrlEntry->cache_entry_type = CacheEntryType | pContainer->default_entry_type; - pUrlEntry->header_info_size = dwHeaderSize; - if ((CacheEntryType & STICKY_CACHE_ENTRY) && !exempt_delta) - { + url_entry = (entry_url *)entry; + url_entry_offset = (LPBYTE)url_entry - (LPBYTE)header; + url_entry->header.signature = URL_SIGNATURE; + url_entry->cache_dir = dir_id; + url_entry->cache_entry_type = entry_type | container->default_entry_type; + url_entry->header_info_size = header_size; + if((entry_type & STICKY_CACHE_ENTRY) && !exempt_delta) { /* Sticky entries have a default exempt time of one day */ exempt_delta = 86400; } - pUrlEntry->exempt_delta = exempt_delta; - pUrlEntry->hit_rate = hit_rate+1; - pUrlEntry->file_extension_off = dwOffsetFileExtension; - pUrlEntry->header_info_off = dwOffsetHeader; - pUrlEntry->local_name_off = dwOffsetLocalFileName; - pUrlEntry->url_off = DWORD_ALIGN(sizeof(*pUrlEntry)); - pUrlEntry->size.QuadPart = file_size.QuadPart; - pUrlEntry->use_count = 0; - GetSystemTimeAsFileTime(&pUrlEntry->access_time); - pUrlEntry->modification_time = LastModifiedTime; - URLCache_FileTimeToDosDateTime(&pUrlEntry->access_time, &pUrlEntry->sync_date, &pUrlEntry->sync_time); - URLCache_FileTimeToDosDateTime(&ExpireTime, &pUrlEntry->expire_date, &pUrlEntry->expire_time); - URLCache_FileTimeToDosDateTime(&file_attr.ftLastWriteTime, &pUrlEntry->write_date, &pUrlEntry->write_time); + url_entry->exempt_delta = exempt_delta; + url_entry->hit_rate = hit_rate+1; + url_entry->file_extension_off = file_ext_off; + url_entry->header_info_off = header_info_off; + url_entry->local_name_off = file_name_off; + url_entry->url_off = DWORD_ALIGN(sizeof(*url_entry)); + url_entry->size.QuadPart = file_size.QuadPart; + url_entry->use_count = 0; + GetSystemTimeAsFileTime(&url_entry->access_time); + url_entry->modification_time = modify_time; + file_time_to_dos_date_time(&url_entry->access_time, &url_entry->sync_date, &url_entry->sync_time); + file_time_to_dos_date_time(&expire_time, &url_entry->expire_date, &url_entry->expire_time); + file_time_to_dos_date_time(&file_attr.ftLastWriteTime, &url_entry->write_date, &url_entry->write_time); /*** Unknowns ***/ - pUrlEntry->unk1 = 0; - pUrlEntry->unk2 = 0; - pUrlEntry->unk3 = 0x60; - pUrlEntry->unk4 = 0; - pUrlEntry->unk5 = 0x1010; - pUrlEntry->unk7 = 0; - pUrlEntry->unk8 = 0; - - - strcpy((LPSTR)pUrlEntry + pUrlEntry->url_off, lpszUrlNameA); - if (dwOffsetLocalFileName) - strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetLocalFileName), pchLocalFileName); - if (dwOffsetHeader) - memcpy((LPBYTE)pUrlEntry + dwOffsetHeader, lpHeaderInfo, dwHeaderSize); - if (dwOffsetFileExtension) - strcpy((LPSTR)((LPBYTE)pUrlEntry + dwOffsetFileExtension), lpszFileExtensionA); - - error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA, url_entry_offset, HASHTABLE_URL); - while (error == ERROR_HANDLE_DISK_FULL) - { - error = cache_container_clean_index(pContainer, &pHeader); - if (error == ERROR_SUCCESS) - { - pUrlEntry = (entry_url *)((LPBYTE)pHeader + url_entry_offset); - error = URLCache_AddEntryToHash(pHeader, lpszUrlNameA, + url_entry->unk1 = 0; + url_entry->unk2 = 0; + url_entry->unk3 = 0x60; + url_entry->unk4 = 0; + url_entry->unk5 = 0x1010; + url_entry->unk7 = 0; + url_entry->unk8 = 0; + + + strcpy((LPSTR)url_entry + url_entry->url_off, url); + if(file_name_off) + strcpy((LPSTR)((LPBYTE)url_entry + file_name_off), local_file_name); + if(header_info_off) + memcpy((LPBYTE)url_entry + header_info_off, header_info, header_size); + if(file_ext_off) + strcpy((LPSTR)((LPBYTE)url_entry + file_ext_off), file_ext); + + error = urlcache_hash_entry_create(header, url, url_entry_offset, HASHTABLE_URL); + while(error == ERROR_HANDLE_DISK_FULL) { + error = cache_container_clean_index(container, &header); + if(error == ERROR_SUCCESS) { + url_entry = (entry_url *)((LPBYTE)header + url_entry_offset); + error = urlcache_hash_entry_create(header, url, url_entry_offset, HASHTABLE_URL); } } - if (error != ERROR_SUCCESS) - URLCache_DeleteEntry(pHeader, &pUrlEntry->header); - else - { - if (pUrlEntry->cache_dir < pHeader->DirectoryCount) - pHeader->directory_data[pUrlEntry->cache_dir].dwNumFiles++; - if (CacheEntryType & STICKY_CACHE_ENTRY) - pHeader->ExemptUsage.QuadPart += file_size.QuadPart; - else - pHeader->CacheUsage.QuadPart += file_size.QuadPart; - if (pHeader->CacheUsage.QuadPart + pHeader->ExemptUsage.QuadPart > - pHeader->CacheLimit.QuadPart) - handle_full_cache(); - } - -cleanup: - cache_container_unlock_index(pContainer, pHeader); - heap_free(lpszUrlNameA); - heap_free(lpszFileExtensionA); - - if (error == ERROR_SUCCESS) - return TRUE; - else - { + if(error != ERROR_SUCCESS) { + urlcache_entry_free(header, &url_entry->header); + cache_container_unlock_index(container, header); SetLastError(error); return FALSE; } + + if(url_entry->cache_dir < header->dirs_no) + header->directory_data[url_entry->cache_dir].files_no++; + if(entry_type & STICKY_CACHE_ENTRY) + header->exempt_usage.QuadPart += file_size.QuadPart; + else + header->cache_usage.QuadPart += file_size.QuadPart; + if(header->cache_usage.QuadPart+header->exempt_usage.QuadPart > header->cache_limit.QuadPart) + handle_full_cache(); + + cache_container_unlock_index(container, header); + return TRUE; } /*********************************************************************** * CommitUrlCacheEntryA (WININET.@) - * */ -BOOL WINAPI CommitUrlCacheEntryA( - IN LPCSTR lpszUrlName, - IN LPCSTR lpszLocalFileName, - IN FILETIME ExpireTime, - IN FILETIME LastModifiedTime, - IN DWORD CacheEntryType, - IN LPBYTE lpHeaderInfo, - IN DWORD dwHeaderSize, - IN LPCSTR lpszFileExtension, - IN LPCSTR lpszOriginalUrl - ) +BOOL WINAPI CommitUrlCacheEntryA(LPCSTR lpszUrlName, LPCSTR lpszLocalFileName, + FILETIME ExpireTime, FILETIME LastModifiedTime, DWORD CacheEntryType, + LPBYTE lpHeaderInfo, DWORD dwHeaderSize, LPCSTR lpszFileExtension, LPCSTR lpszOriginalUrl) { - WCHAR *url_name = NULL; - WCHAR *local_file_name = NULL; - WCHAR *original_url = NULL; - WCHAR *file_extension = NULL; - BOOL bSuccess = FALSE; - - TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", - debugstr_a(lpszUrlName), - debugstr_a(lpszLocalFileName), - CacheEntryType, - lpHeaderInfo, - dwHeaderSize, - debugstr_a(lpszFileExtension), - debugstr_a(lpszOriginalUrl)); - - url_name = heap_strdupAtoW(lpszUrlName); - if (!url_name) - goto cleanup; - - if (lpszLocalFileName) - { - local_file_name = heap_strdupAtoW(lpszLocalFileName); - if (!local_file_name) - goto cleanup; - } - if (lpszFileExtension) - { - file_extension = heap_strdupAtoW(lpszFileExtension); - if (!file_extension) - goto cleanup; - } - if (lpszOriginalUrl) - { - original_url = heap_strdupAtoW(lpszOriginalUrl); - if (!original_url) - goto cleanup; - } + WCHAR *file_name = NULL; + BOOL ret; - bSuccess = CommitUrlCacheEntryInternal(url_name, local_file_name, ExpireTime, LastModifiedTime, - CacheEntryType, lpHeaderInfo, dwHeaderSize, - file_extension, original_url); + if(lpszLocalFileName) { + file_name = heap_strdupAtoW(lpszLocalFileName); + if(!file_name) + return FALSE; + } -cleanup: - heap_free(original_url); - heap_free(file_extension); - heap_free(local_file_name); - heap_free(url_name); - return bSuccess; + ret = urlcache_entry_commit(lpszUrlName, file_name, ExpireTime, LastModifiedTime, + CacheEntryType, lpHeaderInfo, dwHeaderSize, lpszFileExtension, lpszOriginalUrl); + heap_free(file_name); + return ret; } /*********************************************************************** * CommitUrlCacheEntryW (WININET.@) - * */ -BOOL WINAPI CommitUrlCacheEntryW( - IN LPCWSTR lpszUrlName, - IN LPCWSTR lpszLocalFileName, - IN FILETIME ExpireTime, - IN FILETIME LastModifiedTime, - IN DWORD CacheEntryType, - IN LPWSTR lpHeaderInfo, - IN DWORD dwHeaderSize, - IN LPCWSTR lpszFileExtension, - IN LPCWSTR lpszOriginalUrl - ) +BOOL WINAPI CommitUrlCacheEntryW(LPCWSTR lpszUrlName, LPCWSTR lpszLocalFileName, + FILETIME ExpireTime, FILETIME LastModifiedTime, DWORD CacheEntryType, + LPWSTR lpHeaderInfo, DWORD dwHeaderSize, LPCWSTR lpszFileExtension, LPCWSTR lpszOriginalUrl) { - DWORD dwError = 0; - BOOL bSuccess = FALSE; - DWORD len = 0; - CHAR *header_info = NULL; - - TRACE("(%s, %s, ..., ..., %x, %p, %d, %s, %s)\n", - debugstr_w(lpszUrlName), - debugstr_w(lpszLocalFileName), - CacheEntryType, - lpHeaderInfo, - dwHeaderSize, - debugstr_w(lpszFileExtension), - debugstr_w(lpszOriginalUrl)); - - if (!lpHeaderInfo || (header_info = heap_strdupWtoA(lpHeaderInfo))) - { - if(header_info) - len = strlen(header_info); - if (CommitUrlCacheEntryInternal(lpszUrlName, lpszLocalFileName, ExpireTime, LastModifiedTime, - CacheEntryType, (LPBYTE)header_info, len, lpszFileExtension, lpszOriginalUrl)) - { - bSuccess = TRUE; - } - else - { - dwError = GetLastError(); - } - if (header_info) - { - heap_free(header_info); - if (!bSuccess) - SetLastError(dwError); - } - } - return bSuccess; + char *url, *original_url=NULL, *file_ext=NULL, *header_info=NULL; + BOOL ret; + + if(!urlcache_encode_url_alloc(lpszUrlName, &url)) + return FALSE; + + if(lpHeaderInfo) { + header_info = heap_strdupWtoUTF8(lpHeaderInfo); + if(!header_info) { + heap_free(url); + return FALSE; + } + dwHeaderSize = strlen(header_info); + } + + if(lpszFileExtension) { + file_ext = heap_strdupWtoA(lpszFileExtension); + if(!file_ext) { + heap_free(url); + heap_free(header_info); + return FALSE; + } + } + + if(lpszOriginalUrl && !urlcache_encode_url_alloc(lpszOriginalUrl, &original_url)) { + heap_free(url); + heap_free(header_info); + heap_free(file_ext); + return FALSE; + } + + ret = urlcache_entry_commit(url, lpszLocalFileName, ExpireTime, LastModifiedTime, + CacheEntryType, (BYTE*)header_info, dwHeaderSize, file_ext, original_url); + heap_free(url); + heap_free(header_info); + heap_free(file_ext); + heap_free(original_url); + return ret; } /*********************************************************************** @@ -3481,7 +3151,7 @@ BOOL WINAPI ReadUrlCacheEntryStream( ) { /* Get handle to file from 'stream' */ - STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream; + stream_handle *pStream = (stream_handle*)hUrlCacheStream; if (dwReserved != 0) { @@ -3490,28 +3160,24 @@ BOOL WINAPI ReadUrlCacheEntryStream( return FALSE; } - if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH)) + if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->url, INTERNET_MAX_URL_LENGTH)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - if (SetFilePointer(pStream->hFile, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) + if (SetFilePointer(pStream->file, dwLocation, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) return FALSE; - return ReadFile(pStream->hFile, lpBuffer, *lpdwLen, lpdwLen, NULL); + return ReadFile(pStream->file, lpBuffer, *lpdwLen, lpdwLen, NULL); } /*********************************************************************** * RetrieveUrlCacheEntryStreamA (WININET.@) * */ -HANDLE WINAPI RetrieveUrlCacheEntryStreamA( - IN LPCSTR lpszUrlName, - OUT LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, - IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, - IN BOOL fRandomRead, - IN DWORD dwReserved - ) +HANDLE WINAPI RetrieveUrlCacheEntryStreamA(LPCSTR lpszUrlName, + LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufferSize, BOOL fRandomRead, DWORD dwReserved) { /* NOTE: this is not the same as the way that the native * version allocates 'stream' handles. I did it this way @@ -3519,103 +3185,89 @@ HANDLE WINAPI RetrieveUrlCacheEntryStreamA( * on this behaviour. (Native version appears to allocate * indices into a table) */ - STREAM_HANDLE * pStream; - HANDLE hFile; + stream_handle *stream; + HANDLE file; - TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved ); + TRACE("(%s, %p, %p, %x, 0x%08x)\n", debugstr_a(lpszUrlName), lpCacheEntryInfo, + lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved); - if (!RetrieveUrlCacheEntryFileA(lpszUrlName, - lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, - dwReserved)) - { + if(!RetrieveUrlCacheEntryFileA(lpszUrlName, lpCacheEntryInfo, + lpdwCacheEntryInfoBufferSize, dwReserved)) + return NULL; + + file = CreateFileA(lpCacheEntryInfo->lpszLocalFileName, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, NULL); + if(file == INVALID_HANDLE_VALUE) { + UnlockUrlCacheEntryFileA(lpszUrlName, 0); return NULL; } - hFile = CreateFileA(lpCacheEntryInfo->lpszLocalFileName, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, - NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; - /* allocate handle storage space */ - pStream = heap_alloc(sizeof(STREAM_HANDLE) + strlen(lpszUrlName) * sizeof(CHAR)); - if (!pStream) - { - CloseHandle(hFile); + stream = heap_alloc(sizeof(stream_handle) + strlen(lpszUrlName) * sizeof(CHAR)); + if(!stream) { + CloseHandle(file); + UnlockUrlCacheEntryFileA(lpszUrlName, 0); SetLastError(ERROR_OUTOFMEMORY); - return FALSE; + return NULL; } - pStream->hFile = hFile; - strcpy(pStream->lpszUrl, lpszUrlName); - return pStream; + stream->file = file; + strcpy(stream->url, lpszUrlName); + return stream; } /*********************************************************************** * RetrieveUrlCacheEntryStreamW (WININET.@) * */ -HANDLE WINAPI RetrieveUrlCacheEntryStreamW( - IN LPCWSTR lpszUrlName, - OUT LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, - IN OUT LPDWORD lpdwCacheEntryInfoBufferSize, - IN BOOL fRandomRead, - IN DWORD dwReserved - ) +HANDLE WINAPI RetrieveUrlCacheEntryStreamW(LPCWSTR lpszUrlName, + LPINTERNET_CACHE_ENTRY_INFOW lpCacheEntryInfo, + LPDWORD lpdwCacheEntryInfoBufferSize, BOOL fRandomRead, DWORD dwReserved) { - DWORD size; - int url_len; + DWORD len; /* NOTE: this is not the same as the way that the native * version allocates 'stream' handles. I did it this way * as it is much easier and no applications should depend * on this behaviour. (Native version appears to allocate * indices into a table) */ - STREAM_HANDLE * pStream; - HANDLE hFile; + stream_handle *stream; + HANDLE file; - TRACE( "(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved ); + TRACE("(%s, %p, %p, %x, 0x%08x)\n", debugstr_w(lpszUrlName), lpCacheEntryInfo, + lpdwCacheEntryInfoBufferSize, fRandomRead, dwReserved); - if (!RetrieveUrlCacheEntryFileW(lpszUrlName, - lpCacheEntryInfo, - lpdwCacheEntryInfoBufferSize, - dwReserved)) - { + if(!(len = urlcache_encode_url(lpszUrlName, NULL, 0))) return NULL; - } - hFile = CreateFileW(lpCacheEntryInfo->lpszLocalFileName, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, - NULL); - if (hFile == INVALID_HANDLE_VALUE) - return FALSE; + if(!RetrieveUrlCacheEntryFileW(lpszUrlName, lpCacheEntryInfo, + lpdwCacheEntryInfoBufferSize, dwReserved)) + return NULL; + + file = CreateFileW(lpCacheEntryInfo->lpszLocalFileName, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, fRandomRead ? FILE_FLAG_RANDOM_ACCESS : 0, NULL); + if(file == INVALID_HANDLE_VALUE) { + UnlockUrlCacheEntryFileW(lpszUrlName, 0); + return NULL; + } /* allocate handle storage space */ - size = sizeof(STREAM_HANDLE); - url_len = WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, NULL, 0, NULL, NULL); - size += url_len; - pStream = heap_alloc(size); - if (!pStream) - { - CloseHandle(hFile); + stream = heap_alloc(sizeof(stream_handle) + len*sizeof(WCHAR)); + if(!stream) { + CloseHandle(file); + UnlockUrlCacheEntryFileW(lpszUrlName, 0); SetLastError(ERROR_OUTOFMEMORY); - return FALSE; + return NULL; } - pStream->hFile = hFile; - WideCharToMultiByte(CP_ACP, 0, lpszUrlName, -1, pStream->lpszUrl, url_len, NULL, NULL); - return pStream; + stream->file = file; + if(!urlcache_encode_url(lpszUrlName, stream->url, len)) { + CloseHandle(file); + UnlockUrlCacheEntryFileW(lpszUrlName, 0); + heap_free(stream); + return NULL; + } + return stream; } /*********************************************************************** @@ -3627,7 +3279,7 @@ BOOL WINAPI UnlockUrlCacheEntryStream( IN DWORD dwReserved ) { - STREAM_HANDLE * pStream = (STREAM_HANDLE *)hUrlCacheStream; + stream_handle *pStream = (stream_handle*)hUrlCacheStream; if (dwReserved != 0) { @@ -3636,16 +3288,16 @@ BOOL WINAPI UnlockUrlCacheEntryStream( return FALSE; } - if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->lpszUrl, INTERNET_MAX_URL_LENGTH)) + if (IsBadReadPtr(pStream, sizeof(*pStream)) || IsBadStringPtrA(pStream->url, INTERNET_MAX_URL_LENGTH)) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - if (!UnlockUrlCacheEntryFileA(pStream->lpszUrl, 0)) + if (!UnlockUrlCacheEntryFileA(pStream->url, 0)) return FALSE; - CloseHandle(pStream->hFile); + CloseHandle(pStream->file); heap_free(pStream); return TRUE; } @@ -3657,15 +3309,15 @@ BOOL WINAPI UnlockUrlCacheEntryStream( */ BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName) { - URLCACHECONTAINER * pContainer; - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; + cache_container *pContainer; + urlcache_header *pHeader; + struct hash_entry *pHashEntry; DWORD error; BOOL ret; TRACE("(%s)\n", debugstr_a(lpszUrlName)); - error = URLCacheContainers_FindContainerA(lpszUrlName, &pContainer); + error = cache_containers_find(lpszUrlName, &pContainer); if (error != ERROR_SUCCESS) { SetLastError(error); @@ -3682,7 +3334,7 @@ BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName) if (!(pHeader = cache_container_lock_index(pContainer))) return FALSE; - if (!URLCache_FindHash(pHeader, lpszUrlName, &pHashEntry)) + if (!urlcache_find_hash_entry(pHeader, lpszUrlName, &pHashEntry)) { cache_container_unlock_index(pContainer, pHeader); TRACE("entry %s not found!\n", lpszUrlName); @@ -3690,7 +3342,7 @@ BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName) return FALSE; } - ret = DeleteUrlCacheEntryInternal(pContainer, pHeader, pHashEntry); + ret = urlcache_entry_delete(pContainer, pHeader, pHashEntry); cache_container_unlock_index(pContainer, pHeader); @@ -3703,57 +3355,14 @@ BOOL WINAPI DeleteUrlCacheEntryA(LPCSTR lpszUrlName) */ BOOL WINAPI DeleteUrlCacheEntryW(LPCWSTR lpszUrlName) { - URLCACHECONTAINER * pContainer; - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - LPSTR urlA; - DWORD error; + char *url; BOOL ret; - TRACE("(%s)\n", debugstr_w(lpszUrlName)); - - urlA = heap_strdupWtoA(lpszUrlName); - if (!urlA) - { - SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - - error = URLCacheContainers_FindContainerW(lpszUrlName, &pContainer); - if (error != ERROR_SUCCESS) - { - heap_free(urlA); - SetLastError(error); - return FALSE; - } - - error = cache_container_open_index(pContainer, MIN_BLOCK_NO); - if (error != ERROR_SUCCESS) - { - heap_free(urlA); - SetLastError(error); - return FALSE; - } - - if (!(pHeader = cache_container_lock_index(pContainer))) - { - heap_free(urlA); - return FALSE; - } - - if (!URLCache_FindHash(pHeader, urlA, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - TRACE("entry %s not found!\n", debugstr_a(urlA)); - heap_free(urlA); - SetLastError(ERROR_FILE_NOT_FOUND); + if(!urlcache_encode_url_alloc(lpszUrlName, &url)) return FALSE; - } - - ret = DeleteUrlCacheEntryInternal(pContainer, pHeader, pHashEntry); - cache_container_unlock_index(pContainer, pHeader); - heap_free(urlA); + ret = DeleteUrlCacheEntryA(url); + heap_free(url); return ret; } @@ -3865,17 +3474,6 @@ HANDLE WINAPI FindFirstUrlCacheEntryExW( return NULL; } -#define URLCACHE_FIND_ENTRY_HANDLE_MAGIC 0xF389ABCD - -typedef struct URLCacheFindEntryHandle -{ - DWORD dwMagic; - LPWSTR lpszUrlSearchPattern; - DWORD dwContainerIndex; - DWORD dwHashTableIndex; - DWORD dwHashEntryIndex; -} URLCacheFindEntryHandle; - /*********************************************************************** * FindFirstUrlCacheEntryA (WININET.@) * @@ -3883,7 +3481,7 @@ typedef struct URLCacheFindEntryHandle INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern, LPINTERNET_CACHE_ENTRY_INFOA lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize) { - URLCacheFindEntryHandle *pEntryHandle; + find_handle *pEntryHandle; TRACE("(%s, %p, %p)\n", debugstr_a(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize); @@ -3891,21 +3489,21 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern, if (!pEntryHandle) return NULL; - pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; + pEntryHandle->magic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - pEntryHandle->lpszUrlSearchPattern = heap_strdupAtoW(lpszUrlSearchPattern); - if (!pEntryHandle->lpszUrlSearchPattern) + pEntryHandle->url_search_pattern = heap_strdupA(lpszUrlSearchPattern); + if (!pEntryHandle->url_search_pattern) { heap_free(pEntryHandle); return NULL; } } else - pEntryHandle->lpszUrlSearchPattern = NULL; - pEntryHandle->dwContainerIndex = 0; - pEntryHandle->dwHashTableIndex = 0; - pEntryHandle->dwHashEntryIndex = 0; + pEntryHandle->url_search_pattern = NULL; + pEntryHandle->container_idx = 0; + pEntryHandle->hash_table_idx = 0; + pEntryHandle->hash_entry_idx = 0; if (!FindNextUrlCacheEntryA(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize)) { @@ -3922,7 +3520,7 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryA(LPCSTR lpszUrlSearchPattern, INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern, LPINTERNET_CACHE_ENTRY_INFOW lpFirstCacheEntryInfo, LPDWORD lpdwFirstCacheEntryInfoBufferSize) { - URLCacheFindEntryHandle *pEntryHandle; + find_handle *pEntryHandle; TRACE("(%s, %p, %p)\n", debugstr_w(lpszUrlSearchPattern), lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize); @@ -3930,21 +3528,21 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern, if (!pEntryHandle) return NULL; - pEntryHandle->dwMagic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; + pEntryHandle->magic = URLCACHE_FIND_ENTRY_HANDLE_MAGIC; if (lpszUrlSearchPattern) { - pEntryHandle->lpszUrlSearchPattern = heap_strdupW(lpszUrlSearchPattern); - if (!pEntryHandle->lpszUrlSearchPattern) + pEntryHandle->url_search_pattern = heap_strdupWtoA(lpszUrlSearchPattern); + if (!pEntryHandle->url_search_pattern) { heap_free(pEntryHandle); return NULL; } } else - pEntryHandle->lpszUrlSearchPattern = NULL; - pEntryHandle->dwContainerIndex = 0; - pEntryHandle->dwHashTableIndex = 0; - pEntryHandle->dwHashEntryIndex = 0; + pEntryHandle->url_search_pattern = NULL; + pEntryHandle->container_idx = 0; + pEntryHandle->hash_table_idx = 0; + pEntryHandle->hash_entry_idx = 0; if (!FindNextUrlCacheEntryW(pEntryHandle, lpFirstCacheEntryInfo, lpdwFirstCacheEntryInfoBufferSize)) { @@ -3954,26 +3552,26 @@ INTERNETAPI HANDLE WINAPI FindFirstUrlCacheEntryW(LPCWSTR lpszUrlSearchPattern, return pEntryHandle; } -static BOOL FindNextUrlCacheEntryInternal( +static BOOL urlcache_find_next_entry( HANDLE hEnumHandle, LPINTERNET_CACHE_ENTRY_INFOA lpNextCacheEntryInfo, LPDWORD lpdwNextCacheEntryInfoBufferSize, BOOL unicode) { - URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle; - URLCACHECONTAINER * pContainer; + find_handle *pEntryHandle = (find_handle*)hEnumHandle; + cache_container *pContainer; - if (pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC) + if (pEntryHandle->magic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - for (; URLCacheContainers_Enum(pEntryHandle->lpszUrlSearchPattern, pEntryHandle->dwContainerIndex, &pContainer); - pEntryHandle->dwContainerIndex++, pEntryHandle->dwHashTableIndex = 0) + for (; cache_containers_enum(pEntryHandle->url_search_pattern, pEntryHandle->container_idx, &pContainer); + pEntryHandle->container_idx++, pEntryHandle->hash_table_idx = 0) { - LPURLCACHE_HEADER pHeader; - HASH_CACHEFILE_ENTRY *pHashTableEntry; + urlcache_header *pHeader; + entry_hash_table *pHashTableEntry; DWORD error; error = cache_container_open_index(pContainer, MIN_BLOCK_NO); @@ -3986,15 +3584,15 @@ static BOOL FindNextUrlCacheEntryInternal( if (!(pHeader = cache_container_lock_index(pContainer))) return FALSE; - for (; URLCache_EnumHashTables(pHeader, &pEntryHandle->dwHashTableIndex, &pHashTableEntry); - pEntryHandle->dwHashTableIndex++, pEntryHandle->dwHashEntryIndex = 0) + for (; urlcache_enum_hash_tables(pHeader, &pEntryHandle->hash_table_idx, &pHashTableEntry); + pEntryHandle->hash_table_idx++, pEntryHandle->hash_entry_idx = 0) { - const struct _HASH_ENTRY *pHashEntry = NULL; - for (; URLCache_EnumHashTableEntries(pHeader, pHashTableEntry, &pEntryHandle->dwHashEntryIndex, &pHashEntry); - pEntryHandle->dwHashEntryIndex++) + const struct hash_entry *pHashEntry = NULL; + for (; urlcache_enum_hash_table_entries(pHeader, pHashTableEntry, &pEntryHandle->hash_entry_idx, &pHashEntry); + pEntryHandle->hash_entry_idx++) { const entry_url *pUrlEntry; - const entry_header *pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); + const entry_header *pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->offset); if (pEntry->signature != URL_SIGNATURE) continue; @@ -4006,7 +3604,7 @@ static BOOL FindNextUrlCacheEntryInternal( debugstr_an((LPCSTR)pUrlEntry + pUrlEntry->header_info_off, pUrlEntry->header_info_size)); - error = URLCache_CopyEntry( + error = urlcache_copy_entry( pContainer, pHeader, lpNextCacheEntryInfo, @@ -4024,7 +3622,7 @@ static BOOL FindNextUrlCacheEntryInternal( /* increment the current index so that next time the function * is called the next entry is returned */ - pEntryHandle->dwHashEntryIndex++; + pEntryHandle->hash_entry_idx++; cache_container_unlock_index(pContainer, pHeader); return TRUE; } @@ -4047,7 +3645,7 @@ BOOL WINAPI FindNextUrlCacheEntryA( { TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize); - return FindNextUrlCacheEntryInternal(hEnumHandle, lpNextCacheEntryInfo, + return urlcache_find_next_entry(hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize, FALSE /* not UNICODE */); } @@ -4062,7 +3660,7 @@ BOOL WINAPI FindNextUrlCacheEntryW( { TRACE("(%p, %p, %p)\n", hEnumHandle, lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize); - return FindNextUrlCacheEntryInternal(hEnumHandle, + return urlcache_find_next_entry(hEnumHandle, (LPINTERNET_CACHE_ENTRY_INFOA)lpNextCacheEntryInfo, lpdwNextCacheEntryInfoBufferSize, TRUE /* UNICODE */); } @@ -4072,18 +3670,18 @@ BOOL WINAPI FindNextUrlCacheEntryW( */ BOOL WINAPI FindCloseUrlCache(HANDLE hEnumHandle) { - URLCacheFindEntryHandle *pEntryHandle = (URLCacheFindEntryHandle *)hEnumHandle; + find_handle *pEntryHandle = (find_handle*)hEnumHandle; TRACE("(%p)\n", hEnumHandle); - if (!pEntryHandle || pEntryHandle->dwMagic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC) + if (!pEntryHandle || pEntryHandle->magic != URLCACHE_FIND_ENTRY_HANDLE_MAGIC) { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - pEntryHandle->dwMagic = 0; - heap_free(pEntryHandle->lpszUrlSearchPattern); + pEntryHandle->magic = 0; + heap_free(pEntryHandle->url_search_pattern); heap_free(pEntryHandle); return TRUE; } @@ -4276,7 +3874,7 @@ DWORD WINAPI DeleteIE3Cache(HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int n return 0; } -static BOOL IsUrlCacheEntryExpiredInternal(const entry_url *pUrlEntry, +static BOOL urlcache_entry_is_expired(const entry_url *pUrlEntry, FILETIME *pftLastModified) { BOOL ret; @@ -4284,7 +3882,7 @@ static BOOL IsUrlCacheEntryExpiredInternal(const entry_url *pUrlEntry, *pftLastModified = pUrlEntry->modification_time; GetSystemTimeAsFileTime(&now); - URLCache_DosDateTimeToFileTime(pUrlEntry->expire_date, + dos_date_time_to_file_time(pUrlEntry->expire_date, pUrlEntry->expire_time, &expired); /* If the expired time is 0, it's interpreted as not expired */ if (!expired.dwLowDateTime && !expired.dwHighDateTime) @@ -4302,13 +3900,13 @@ static BOOL IsUrlCacheEntryExpiredInternal(const entry_url *pUrlEntry, * dwFlags [I] Unknown * pftLastModified [O] Last modified time */ -BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified ) +BOOL WINAPI IsUrlCacheEntryExpiredA(LPCSTR url, DWORD dwFlags, FILETIME* pftLastModified) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; + urlcache_header *pHeader; + struct hash_entry *pHashEntry; const entry_header *pEntry; const entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; + cache_container *pContainer; BOOL expired; TRACE("(%s, %08x, %p)\n", debugstr_a(url), dwFlags, pftLastModified); @@ -4319,7 +3917,7 @@ BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLas FIXME("unknown flags 0x%08x\n", dwFlags); /* Any error implies that the URL is expired, i.e. not in the cache */ - if (URLCacheContainers_FindContainerA(url, &pContainer)) + if (cache_containers_find(url, &pContainer)) { memset(pftLastModified, 0, sizeof(*pftLastModified)); return TRUE; @@ -4337,7 +3935,7 @@ BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLas return TRUE; } - if (!URLCache_FindHash(pHeader, url, &pHashEntry)) + if (!urlcache_find_hash_entry(pHeader, url, &pHashEntry)) { cache_container_unlock_index(pContainer, pHeader); memset(pftLastModified, 0, sizeof(*pftLastModified)); @@ -4345,7 +3943,7 @@ BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLas return TRUE; } - pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); + pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->offset); if (pEntry->signature != URL_SIGNATURE) { cache_container_unlock_index(pContainer, pHeader); @@ -4355,7 +3953,7 @@ BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLas } pUrlEntry = (const entry_url *)pEntry; - expired = IsUrlCacheEntryExpiredInternal(pUrlEntry, pftLastModified); + expired = urlcache_entry_is_expired(pUrlEntry, pftLastModified); cache_container_unlock_index(pContainer, pHeader); @@ -4370,72 +3968,17 @@ BOOL WINAPI IsUrlCacheEntryExpiredA( LPCSTR url, DWORD dwFlags, FILETIME* pftLas * dwFlags [I] Unknown * pftLastModified [O] Last modified time */ -BOOL WINAPI IsUrlCacheEntryExpiredW( LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified ) +BOOL WINAPI IsUrlCacheEntryExpiredW(LPCWSTR url, DWORD dwFlags, FILETIME* pftLastModified) { - LPURLCACHE_HEADER pHeader; - struct _HASH_ENTRY * pHashEntry; - const entry_header *pEntry; - const entry_url * pUrlEntry; - URLCACHECONTAINER * pContainer; - BOOL expired; - - TRACE("(%s, %08x, %p)\n", debugstr_w(url), dwFlags, pftLastModified); - - if (!url || !pftLastModified) - return TRUE; - if (dwFlags) - FIXME("unknown flags 0x%08x\n", dwFlags); - - /* Any error implies that the URL is expired, i.e. not in the cache */ - if (URLCacheContainers_FindContainerW(url, &pContainer)) - { - memset(pftLastModified, 0, sizeof(*pftLastModified)); - return TRUE; - } - - if (cache_container_open_index(pContainer, MIN_BLOCK_NO)) - { - memset(pftLastModified, 0, sizeof(*pftLastModified)); - return TRUE; - } - - if (!(pHeader = cache_container_lock_index(pContainer))) - { - memset(pftLastModified, 0, sizeof(*pftLastModified)); - return TRUE; - } - - if (!URLCache_FindHashW(pHeader, url, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - memset(pftLastModified, 0, sizeof(*pftLastModified)); - TRACE("entry %s not found!\n", debugstr_w(url)); - return TRUE; - } - - if (!URLCache_FindHashW(pHeader, url, &pHashEntry)) - { - cache_container_unlock_index(pContainer, pHeader); - memset(pftLastModified, 0, sizeof(*pftLastModified)); - TRACE("entry %s not found!\n", debugstr_w(url)); - return TRUE; - } - - pEntry = (const entry_header*)((LPBYTE)pHeader + pHashEntry->dwOffsetEntry); - if (pEntry->signature != URL_SIGNATURE) - { - cache_container_unlock_index(pContainer, pHeader); - memset(pftLastModified, 0, sizeof(*pftLastModified)); - FIXME("Trying to retrieve entry of unknown format %s\n", debugstr_an((LPCSTR)&pEntry->signature, sizeof(DWORD))); - return TRUE; - } - - pUrlEntry = (const entry_url *)pEntry; - expired = IsUrlCacheEntryExpiredInternal(pUrlEntry, pftLastModified); + char *encoded_url; + BOOL ret; - cache_container_unlock_index(pContainer, pHeader); + if(!urlcache_encode_url_alloc(url, &encoded_url)) + return FALSE; - return expired; + ret = IsUrlCacheEntryExpiredA(encoded_url, dwFlags, pftLastModified); + heap_free(encoded_url); + return ret; } /*********************************************************************** @@ -4503,7 +4046,7 @@ BOOL init_urlcache(void) return FALSE; } - URLCacheContainers_CreateDefaults(); + cache_containers_init(); return TRUE; } @@ -4515,7 +4058,7 @@ void free_urlcache(void) CloseHandle(free_cache_running); CloseHandle(dll_unload_event); - URLCacheContainers_DeleteAll(); + cache_containers_free(); } /*********************************************************************** diff --git a/reactos/dll/win32/wininet/version.rc b/reactos/dll/win32/wininet/version.rc index bc37bd83e37..2e6d49d2100 100644 --- a/reactos/dll/win32/wininet/version.rc +++ b/reactos/dll/win32/wininet/version.rc @@ -25,4 +25,4 @@ #define WINE_PRODUCTVERSION 6,0,2800,1106 #define WINE_PRODUCTVERSION_STR "6.0.2800.1106" -#include "wine/wine_common_ver.rc" +#include diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index f64550af3d9..00db97af8d5 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -203,7 +203,7 @@ reactos/dll/win32/windowscodecs # Synced to Wine-1.7.1 reactos/dll/win32/winemp3.acm # Synced to Wine-1.7.1 reactos/dll/win32/wing32 # Out of sync reactos/dll/win32/winhttp # Synced to Wine-1.7.1 -reactos/dll/win32/wininet # Synced to Wine-1.5.26 +reactos/dll/win32/wininet # Synced to Wine-1.7.1 reactos/dll/win32/winmm # Forked at Wine-20050628 reactos/dll/win32/winmm/midimap # Forked at Wine-20050628 reactos/dll/win32/winmm/wavemap # Forked at Wine-20050628 -- 2.17.1