1 /* 2 * Unit test suite for ntdll path functions 3 * 4 * Copyright 2003 Eric Pouech 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdio.h> 22 23 #include "ntdll_test.h" 24 25 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen, 26 LPCSTR src, DWORD srclen ); 27 static NTSTATUS (WINAPI *pRtlCreateEnvironment)(BOOLEAN, PWSTR*); 28 static NTSTATUS (WINAPI *pRtlDestroyEnvironment)(PWSTR); 29 static NTSTATUS (WINAPI *pRtlQueryEnvironmentVariable_U)(PWSTR, PUNICODE_STRING, PUNICODE_STRING); 30 static void (WINAPI *pRtlSetCurrentEnvironment)(PWSTR, PWSTR*); 31 static NTSTATUS (WINAPI *pRtlSetEnvironmentVariable)(PWSTR*, PUNICODE_STRING, PUNICODE_STRING); 32 static NTSTATUS (WINAPI *pRtlExpandEnvironmentStrings_U)(LPWSTR, PUNICODE_STRING, PUNICODE_STRING, PULONG); 33 34 static WCHAR small_env[] = {'f','o','o','=','t','o','t','o',0, 35 'f','o','=','t','i','t','i',0, 36 'f','o','o','o','=','t','u','t','u',0, 37 's','r','=','a','n','=','o','u','o',0, 38 'g','=','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 39 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 40 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 41 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 42 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 43 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 44 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 45 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 46 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a', 47 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',0, 48 '=','o','O','H','=','I','I','I',0, 49 'n','u','l','=',0, 50 0}; 51 52 static void testQuery(void) 53 { 54 struct test 55 { 56 const char *var; 57 int len; 58 NTSTATUS status; 59 const char *val; 60 NTSTATUS alt; 61 }; 62 63 static const struct test tests[] = 64 { 65 {"foo", 256, STATUS_SUCCESS, "toto"}, 66 {"FoO", 256, STATUS_SUCCESS, "toto"}, 67 {"foo=", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, 68 {"foo ", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, 69 {"foo", 1, STATUS_BUFFER_TOO_SMALL, "toto"}, 70 {"foo", 3, STATUS_BUFFER_TOO_SMALL, "toto"}, 71 {"foo", 4, STATUS_SUCCESS, "toto", STATUS_BUFFER_TOO_SMALL}, 72 {"foo", 5, STATUS_SUCCESS, "toto"}, 73 {"fooo", 256, STATUS_SUCCESS, "tutu"}, 74 {"f", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, 75 {"g", 256, STATUS_SUCCESS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 76 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, 77 {"sr=an", 256, STATUS_SUCCESS, "ouo", STATUS_VARIABLE_NOT_FOUND}, 78 {"sr", 256, STATUS_SUCCESS, "an=ouo"}, 79 {"=oOH", 256, STATUS_SUCCESS, "III"}, 80 {"", 256, STATUS_VARIABLE_NOT_FOUND, NULL}, 81 {"nul", 256, STATUS_SUCCESS, ""}, 82 {NULL, 0, 0, NULL} 83 }; 84 85 WCHAR bn[257]; 86 WCHAR bv[257]; 87 UNICODE_STRING name; 88 UNICODE_STRING value; 89 NTSTATUS nts; 90 unsigned int i; 91 92 for (i = 0; tests[i].var; i++) 93 { 94 const struct test *test = &tests[i]; 95 name.Length = strlen(test->var) * 2; 96 name.MaximumLength = name.Length + 2; 97 name.Buffer = bn; 98 value.Length = 0; 99 value.MaximumLength = test->len * 2; 100 value.Buffer = bv; 101 bv[test->len] = '@'; 102 103 pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->var, strlen(test->var)+1 ); 104 nts = pRtlQueryEnvironmentVariable_U(small_env, &name, &value); 105 ok( nts == test->status || (test->alt && nts == test->alt), 106 "[%d]: Wrong status for '%s', expecting %x got %x\n", 107 i, test->var, test->status, nts ); 108 if (nts == test->status) switch (nts) 109 { 110 case STATUS_SUCCESS: 111 pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->val, strlen(test->val)+1 ); 112 ok( value.Length == strlen(test->val) * sizeof(WCHAR), "Wrong length %d for %s\n", 113 value.Length, test->var ); 114 ok((value.Length == strlen(test->val) * sizeof(WCHAR) && memcmp(bv, bn, value.Length) == 0) || 115 lstrcmpW(bv, bn) == 0, 116 "Wrong result for %s/%d\n", test->var, test->len); 117 ok(bv[test->len] == '@', "Writing too far away in the buffer for %s/%d\n", test->var, test->len); 118 break; 119 case STATUS_BUFFER_TOO_SMALL: 120 ok( value.Length == strlen(test->val) * sizeof(WCHAR), 121 "Wrong returned length %d (too small buffer) for %s\n", value.Length, test->var ); 122 break; 123 } 124 } 125 } 126 127 static void testSetHelper(LPWSTR* env, const char* var, const char* val, NTSTATUS ret, NTSTATUS alt) 128 { 129 WCHAR bvar[256], bval1[256], bval2[256]; 130 UNICODE_STRING uvar; 131 UNICODE_STRING uval; 132 NTSTATUS nts; 133 134 uvar.Length = strlen(var) * sizeof(WCHAR); 135 uvar.MaximumLength = uvar.Length + sizeof(WCHAR); 136 uvar.Buffer = bvar; 137 pRtlMultiByteToUnicodeN( bvar, sizeof(bvar), NULL, var, strlen(var)+1 ); 138 if (val) 139 { 140 uval.Length = strlen(val) * sizeof(WCHAR); 141 uval.MaximumLength = uval.Length + sizeof(WCHAR); 142 uval.Buffer = bval1; 143 pRtlMultiByteToUnicodeN( bval1, sizeof(bval1), NULL, val, strlen(val)+1 ); 144 } 145 nts = pRtlSetEnvironmentVariable(env, &uvar, val ? &uval : NULL); 146 ok(nts == ret || (alt && nts == alt), "Setting var %s=%s (%x/%x)\n", var, val, nts, ret); 147 if (nts == STATUS_SUCCESS) 148 { 149 uval.Length = 0; 150 uval.MaximumLength = sizeof(bval2); 151 uval.Buffer = bval2; 152 nts = pRtlQueryEnvironmentVariable_U(*env, &uvar, &uval); 153 switch (nts) 154 { 155 case STATUS_SUCCESS: 156 ok(lstrcmpW(bval1, bval2) == 0, "Cannot get value written to environment\n"); 157 break; 158 case STATUS_VARIABLE_NOT_FOUND: 159 ok(val == NULL || 160 broken(strchr(var,'=') != NULL), /* variable containing '=' may be set but not found again on NT4 */ 161 "Couldn't find variable, but didn't delete it. val = %s\n", val); 162 break; 163 default: 164 ok(0, "Wrong ret %u for %s\n", nts, var); 165 break; 166 } 167 } 168 } 169 170 static void testSet(void) 171 { 172 LPWSTR env; 173 char tmp[16]; 174 int i; 175 176 ok(pRtlCreateEnvironment(FALSE, &env) == STATUS_SUCCESS, "Creating environment\n"); 177 178 testSetHelper(&env, "cat", "dog", STATUS_SUCCESS, 0); 179 testSetHelper(&env, "cat", "horse", STATUS_SUCCESS, 0); 180 testSetHelper(&env, "cat", "zz", STATUS_SUCCESS, 0); 181 testSetHelper(&env, "cat", NULL, STATUS_SUCCESS, 0); 182 testSetHelper(&env, "cat", NULL, STATUS_SUCCESS, STATUS_VARIABLE_NOT_FOUND); 183 testSetHelper(&env, "foo", "meouw", STATUS_SUCCESS, 0); 184 testSetHelper(&env, "me=too", "also", STATUS_SUCCESS, STATUS_INVALID_PARAMETER); 185 testSetHelper(&env, "me", "too=also", STATUS_SUCCESS, 0); 186 testSetHelper(&env, "=too", "also", STATUS_SUCCESS, 0); 187 testSetHelper(&env, "=", "also", STATUS_SUCCESS, 0); 188 189 for (i = 0; i < 128; i++) 190 { 191 sprintf(tmp, "zork%03d", i); 192 testSetHelper(&env, tmp, "is alive", STATUS_SUCCESS, 0); 193 } 194 195 for (i = 0; i < 128; i++) 196 { 197 sprintf(tmp, "zork%03d", i); 198 testSetHelper(&env, tmp, NULL, STATUS_SUCCESS, 0); 199 } 200 testSetHelper(&env, "fOo", NULL, STATUS_SUCCESS, 0); 201 202 ok(pRtlDestroyEnvironment(env) == STATUS_SUCCESS, "Destroying environment\n"); 203 } 204 205 static void testExpand(void) 206 { 207 static const struct test 208 { 209 const char *src; 210 const char *dst; 211 } tests[] = 212 { 213 {"hello%foo%world", "hellototoworld"}, 214 {"hello%=oOH%world", "helloIIIworld"}, 215 {"hello%foo", "hello%foo"}, 216 {"hello%bar%world", "hello%bar%world"}, 217 /* 218 * {"hello%foo%world%=oOH%eeck", "hellototoworldIIIeeck"}, 219 * Interestingly enough, with a 8 WCHAR buffers, we get on 2k: 220 * helloIII 221 * so it seems like strings overflowing the buffer are written 222 * (truncated) but the write cursor is not advanced :-/ 223 */ 224 {NULL, NULL} 225 }; 226 227 const struct test* test; 228 NTSTATUS nts; 229 UNICODE_STRING us_src, us_dst; 230 WCHAR src[256], dst[256], rst[256]; 231 ULONG ul; 232 233 for (test = tests; test->src; test++) 234 { 235 pRtlMultiByteToUnicodeN(src, sizeof(src), NULL, test->src, strlen(test->src)+1); 236 pRtlMultiByteToUnicodeN(rst, sizeof(rst), NULL, test->dst, strlen(test->dst)+1); 237 238 us_src.Length = strlen(test->src) * sizeof(WCHAR); 239 us_src.MaximumLength = us_src.Length + 2; 240 us_src.Buffer = src; 241 242 us_dst.Length = 0; 243 us_dst.MaximumLength = 0; 244 us_dst.Buffer = NULL; 245 246 nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul); 247 ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%u)\n", nts); 248 ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), 249 "Wrong returned length for %s: %u\n", test->src, ul ); 250 251 us_dst.Length = 0; 252 us_dst.MaximumLength = sizeof(dst); 253 us_dst.Buffer = dst; 254 255 nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul); 256 ok(nts == STATUS_SUCCESS, "Call failed (%u)\n", nts); 257 ok(ul == us_dst.Length + sizeof(WCHAR), 258 "Wrong returned length for %s: %u\n", test->src, ul); 259 ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), 260 "Wrong returned length for %s: %u\n", test->src, ul); 261 ok(lstrcmpW(dst, rst) == 0, "Wrong result for %s: expecting %s\n", 262 test->src, test->dst); 263 264 us_dst.Length = 0; 265 us_dst.MaximumLength = 8 * sizeof(WCHAR); 266 us_dst.Buffer = dst; 267 dst[8] = '-'; 268 nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul); 269 ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%u)\n", nts); 270 ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), 271 "Wrong returned length for %s (with buffer too small): %u\n", test->src, ul); 272 ok(dst[8] == '-', "Writing too far in buffer (got %c/%d)\n", dst[8], dst[8]); 273 } 274 275 } 276 277 START_TEST(env) 278 { 279 HMODULE mod = GetModuleHandleA("ntdll.dll"); 280 if (!mod) 281 { 282 win_skip("Not running on NT, skipping tests\n"); 283 return; 284 } 285 286 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN"); 287 pRtlCreateEnvironment = (void*)GetProcAddress(mod, "RtlCreateEnvironment"); 288 pRtlDestroyEnvironment = (void*)GetProcAddress(mod, "RtlDestroyEnvironment"); 289 pRtlQueryEnvironmentVariable_U = (void*)GetProcAddress(mod, "RtlQueryEnvironmentVariable_U"); 290 pRtlSetCurrentEnvironment = (void*)GetProcAddress(mod, "RtlSetCurrentEnvironment"); 291 pRtlSetEnvironmentVariable = (void*)GetProcAddress(mod, "RtlSetEnvironmentVariable"); 292 pRtlExpandEnvironmentStrings_U = (void*)GetProcAddress(mod, "RtlExpandEnvironmentStrings_U"); 293 294 if (pRtlQueryEnvironmentVariable_U) 295 testQuery(); 296 if (pRtlSetEnvironmentVariable) 297 testSet(); 298 if (pRtlExpandEnvironmentStrings_U) 299 testExpand(); 300 } 301