1 /* 2 * Copyright 2012 Hans Leidekker for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #define COBJMACROS 20 21 #include <stdarg.h> 22 #ifdef __REACTOS__ 23 #include <wchar.h> 24 #endif 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "wbemcli.h" 29 30 #include "wine/debug.h" 31 #include "wbemprox_private.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox); 34 35 static HRESULT append_table( struct view *view, struct table *table ) 36 { 37 struct table **tmp; 38 if (!(tmp = heap_realloc( view->table, (view->table_count + 1) * sizeof(*tmp) ))) return E_OUTOFMEMORY; 39 view->table = tmp; 40 view->table[view->table_count++] = table; 41 return S_OK; 42 } 43 44 HRESULT create_view( enum view_type type, const WCHAR *path, const struct keyword *keywordlist, const WCHAR *class, 45 const struct property *proplist, const struct expr *cond, struct view **ret ) 46 { 47 struct view *view = heap_alloc_zero( sizeof(*view) ); 48 49 if (!view) return E_OUTOFMEMORY; 50 51 switch (type) 52 { 53 case VIEW_TYPE_ASSOCIATORS: 54 view->path = path; 55 view->keywordlist = keywordlist; 56 break; 57 58 case VIEW_TYPE_SELECT: 59 { 60 struct table *table = grab_table( class ); 61 HRESULT hr; 62 63 if (table && (hr = append_table( view, table )) != S_OK) 64 { 65 heap_free( view ); 66 return hr; 67 } 68 view->proplist = proplist; 69 view->cond = cond; 70 break; 71 } 72 default: 73 ERR( "unhandled type %u\n", type ); 74 heap_free( view ); 75 return E_INVALIDARG; 76 } 77 78 view->type = type; 79 *ret = view; 80 return S_OK; 81 } 82 83 void destroy_view( struct view *view ) 84 { 85 ULONG i; 86 if (!view) return; 87 for (i = 0; i < view->table_count; i++) release_table( view->table[i] ); 88 heap_free( view->table ); 89 heap_free( view->result ); 90 heap_free( view ); 91 } 92 93 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr ) 94 { 95 const WCHAR *p = lstr, *q = rstr; 96 97 while (*p && *q) 98 { 99 if (*q == '%') 100 { 101 while (*q == '%') q++; 102 if (!*q) return TRUE; 103 while (*p && *q && towupper( *p ) == towupper( *q )) { p++; q++; }; 104 if (!*p && !*q) return TRUE; 105 } 106 if (*q != '%' && towupper( *p++ ) != towupper( *q++ )) return FALSE; 107 } 108 return TRUE; 109 } 110 111 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val ) 112 { 113 if (!lstr || !rstr) 114 { 115 *val = 0; 116 return S_OK; 117 } 118 switch (op) 119 { 120 case OP_EQ: 121 *val = !wcscmp( lstr, rstr ); 122 break; 123 case OP_GT: 124 *val = wcscmp( lstr, rstr ) > 0; 125 break; 126 case OP_LT: 127 *val = wcscmp( lstr, rstr ) < 0; 128 break; 129 case OP_LE: 130 *val = wcscmp( lstr, rstr ) <= 0; 131 break; 132 case OP_GE: 133 *val = wcscmp( lstr, rstr ) >= 0; 134 break; 135 case OP_NE: 136 *val = wcscmp( lstr, rstr ); 137 break; 138 case OP_LIKE: 139 *val = eval_like( lstr, rstr ); 140 break; 141 default: 142 ERR("unhandled operator %u\n", op); 143 return WBEM_E_INVALID_QUERY; 144 } 145 return S_OK; 146 } 147 148 static BOOL is_int( CIMTYPE type ) 149 { 150 switch (type) 151 { 152 case CIM_SINT8: 153 case CIM_SINT16: 154 case CIM_SINT32: 155 case CIM_SINT64: 156 case CIM_UINT8: 157 case CIM_UINT16: 158 case CIM_UINT32: 159 case CIM_UINT64: 160 return TRUE; 161 default: 162 return FALSE; 163 } 164 } 165 166 static inline BOOL is_strcmp( const struct complex_expr *expr, UINT ltype, UINT rtype ) 167 { 168 if ((ltype == CIM_STRING || is_int( ltype )) && expr->left->type == EXPR_PROPVAL && 169 expr->right->type == EXPR_SVAL) return TRUE; 170 else if ((rtype == CIM_STRING || is_int( rtype )) && expr->right->type == EXPR_PROPVAL && 171 expr->left->type == EXPR_SVAL) return TRUE; 172 return FALSE; 173 } 174 175 static inline BOOL is_boolcmp( const struct complex_expr *expr, UINT ltype, UINT rtype ) 176 { 177 if (ltype == CIM_BOOLEAN && expr->left->type == EXPR_PROPVAL && 178 (expr->right->type == EXPR_SVAL || expr->right->type == EXPR_BVAL)) return TRUE; 179 else if (rtype == CIM_BOOLEAN && expr->right->type == EXPR_PROPVAL && 180 (expr->left->type == EXPR_SVAL || expr->left->type == EXPR_BVAL)) return TRUE; 181 return FALSE; 182 } 183 184 static HRESULT eval_boolcmp( UINT op, LONGLONG lval, LONGLONG rval, UINT ltype, UINT rtype, LONGLONG *val ) 185 { 186 static const WCHAR trueW[] = {'T','r','u','e',0}; 187 188 if (ltype == CIM_STRING) lval = !wcsicmp( (const WCHAR *)(INT_PTR)lval, trueW ) ? -1 : 0; 189 else if (rtype == CIM_STRING) rval = !wcsicmp( (const WCHAR *)(INT_PTR)rval, trueW ) ? -1 : 0; 190 191 switch (op) 192 { 193 case OP_EQ: 194 *val = (lval == rval); 195 break; 196 case OP_NE: 197 *val = (lval != rval); 198 break; 199 default: 200 ERR("unhandled operator %u\n", op); 201 return WBEM_E_INVALID_QUERY; 202 } 203 return S_OK; 204 } 205 206 static inline BOOL is_refcmp( const struct complex_expr *expr, UINT ltype, UINT rtype ) 207 { 208 if (ltype == CIM_REFERENCE && expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) return TRUE; 209 else if (rtype == CIM_REFERENCE && expr->right->type == EXPR_PROPVAL && expr->left->type == EXPR_SVAL) return TRUE; 210 return FALSE; 211 } 212 213 static HRESULT eval_refcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val ) 214 { 215 if (!lstr || !rstr) 216 { 217 *val = 0; 218 return S_OK; 219 } 220 switch (op) 221 { 222 case OP_EQ: 223 *val = !wcsicmp( lstr, rstr ); 224 break; 225 case OP_NE: 226 *val = wcsicmp( lstr, rstr ); 227 break; 228 default: 229 ERR("unhandled operator %u\n", op); 230 return WBEM_E_INVALID_QUERY; 231 } 232 return S_OK; 233 } 234 235 static UINT resolve_type( UINT left, UINT right ) 236 { 237 switch (left) 238 { 239 case CIM_SINT8: 240 case CIM_SINT16: 241 case CIM_SINT32: 242 case CIM_SINT64: 243 case CIM_UINT8: 244 case CIM_UINT16: 245 case CIM_UINT32: 246 case CIM_UINT64: 247 switch (right) 248 { 249 case CIM_SINT8: 250 case CIM_SINT16: 251 case CIM_SINT32: 252 case CIM_SINT64: 253 case CIM_UINT8: 254 case CIM_UINT16: 255 case CIM_UINT32: 256 case CIM_UINT64: 257 return CIM_UINT64; 258 default: break; 259 } 260 break; 261 262 case CIM_STRING: 263 if (right == CIM_STRING) return CIM_STRING; 264 break; 265 266 case CIM_BOOLEAN: 267 if (right == CIM_BOOLEAN) return CIM_BOOLEAN; 268 break; 269 270 case CIM_REFERENCE: 271 if (right == CIM_REFERENCE) return CIM_REFERENCE; 272 break; 273 274 default: 275 break; 276 } 277 return CIM_ILLEGAL; 278 } 279 280 static const WCHAR *format_int( WCHAR *buf, UINT len, CIMTYPE type, LONGLONG val ) 281 { 282 static const WCHAR fmt_signedW[] = {'%','d',0}; 283 static const WCHAR fmt_unsignedW[] = {'%','u',0}; 284 static const WCHAR fmt_signed64W[] = {'%','I','6','4','d',0}; 285 static const WCHAR fmt_unsigned64W[] = {'%','I','6','4','u',0}; 286 287 switch (type) 288 { 289 case CIM_SINT8: 290 case CIM_SINT16: 291 case CIM_SINT32: 292 swprintf( buf, fmt_signedW, val ); 293 return buf; 294 295 case CIM_UINT8: 296 case CIM_UINT16: 297 case CIM_UINT32: 298 swprintf( buf, fmt_unsignedW, val ); 299 return buf; 300 301 case CIM_SINT64: 302 wsprintfW( buf, fmt_signed64W, val ); 303 return buf; 304 305 case CIM_UINT64: 306 wsprintfW( buf, fmt_unsigned64W, val ); 307 return buf; 308 309 default: 310 ERR( "unhandled type %u\n", type ); 311 return NULL; 312 } 313 } 314 315 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr, 316 LONGLONG *val, UINT *type ) 317 { 318 HRESULT lret, rret; 319 LONGLONG lval, rval; 320 UINT ltype, rtype; 321 322 lret = eval_cond( table, row, expr->left, &lval, <ype ); 323 rret = eval_cond( table, row, expr->right, &rval, &rtype ); 324 if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY; 325 326 *type = resolve_type( ltype, rtype ); 327 328 if (is_strcmp( expr, ltype, rtype )) 329 { 330 const WCHAR *lstr, *rstr; 331 WCHAR lbuf[21], rbuf[21]; 332 333 if (is_int( ltype )) lstr = format_int( lbuf, ARRAY_SIZE( lbuf ), ltype, lval ); 334 else lstr = (const WCHAR *)(INT_PTR)lval; 335 336 if (is_int( rtype )) rstr = format_int( rbuf, ARRAY_SIZE( rbuf ), rtype, rval ); 337 else rstr = (const WCHAR *)(INT_PTR)rval; 338 339 return eval_strcmp( expr->op, lstr, rstr, val ); 340 } 341 if (is_boolcmp( expr, ltype, rtype )) 342 { 343 return eval_boolcmp( expr->op, lval, rval, ltype, rtype, val ); 344 } 345 if (is_refcmp( expr, ltype, rtype )) 346 { 347 return eval_refcmp( expr->op, (const WCHAR *)(INT_PTR)lval, (const WCHAR *)(INT_PTR)rval, val ); 348 } 349 350 switch (expr->op) 351 { 352 case OP_EQ: 353 *val = (lval == rval); 354 break; 355 case OP_AND: 356 *val = (lval && rval); 357 break; 358 case OP_OR: 359 *val = (lval || rval); 360 break; 361 case OP_GT: 362 *val = (lval > rval); 363 break; 364 case OP_LT: 365 *val = (lval < rval); 366 break; 367 case OP_LE: 368 *val = (lval <= rval); 369 break; 370 case OP_GE: 371 *val = (lval >= rval); 372 break; 373 case OP_NE: 374 *val = (lval != rval); 375 break; 376 default: 377 ERR("unhandled operator %u\n", expr->op); 378 return WBEM_E_INVALID_QUERY; 379 } 380 return S_OK; 381 } 382 383 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr, 384 LONGLONG *val, UINT *type ) 385 386 { 387 HRESULT hr; 388 UINT column; 389 LONGLONG lval; 390 391 if (expr->op == OP_NOT) 392 { 393 hr = eval_cond( table, row, expr->left, &lval, type ); 394 if (hr != S_OK) 395 return hr; 396 *val = !lval; 397 return S_OK; 398 } 399 400 hr = get_column_index( table, expr->left->u.propval->name, &column ); 401 if (hr != S_OK) 402 return hr; 403 404 hr = get_value( table, row, column, &lval ); 405 if (hr != S_OK) 406 return hr; 407 408 switch (expr->op) 409 { 410 case OP_ISNULL: 411 *val = !lval; 412 break; 413 case OP_NOTNULL: 414 *val = lval; 415 break; 416 default: 417 ERR("unknown operator %u\n", expr->op); 418 return WBEM_E_INVALID_QUERY; 419 } 420 421 *type = table->columns[column].type & CIM_TYPE_MASK; 422 return S_OK; 423 } 424 425 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval, 426 LONGLONG *val, UINT *type ) 427 428 { 429 HRESULT hr; 430 UINT column; 431 432 hr = get_column_index( table, propval->name, &column ); 433 if (hr != S_OK) 434 return hr; 435 436 *type = table->columns[column].type & CIM_TYPE_MASK; 437 return get_value( table, row, column, val ); 438 } 439 440 HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond, LONGLONG *val, UINT *type ) 441 { 442 if (!cond) 443 { 444 *val = 1; 445 *type = CIM_UINT64; 446 return S_OK; 447 } 448 switch (cond->type) 449 { 450 case EXPR_COMPLEX: 451 return eval_binary( table, row, &cond->u.expr, val, type ); 452 453 case EXPR_UNARY: 454 return eval_unary( table, row, &cond->u.expr, val, type ); 455 456 case EXPR_PROPVAL: 457 return eval_propval( table, row, cond->u.propval, val, type ); 458 459 case EXPR_SVAL: 460 *val = (INT_PTR)cond->u.sval; 461 *type = CIM_STRING; 462 return S_OK; 463 464 case EXPR_IVAL: 465 *val = cond->u.ival; 466 *type = CIM_UINT64; 467 return S_OK; 468 469 case EXPR_BVAL: 470 *val = cond->u.ival; 471 *type = CIM_BOOLEAN; 472 return S_OK; 473 474 default: 475 ERR("invalid expression type\n"); 476 break; 477 } 478 return WBEM_E_INVALID_QUERY; 479 } 480 481 static WCHAR *build_assoc_query( const WCHAR *class, UINT class_len ) 482 { 483 static const WCHAR fmtW[] = 484 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','_','_','A','S','S','O','C','I','A','T','O','R','S', 485 ' ','W','H','E','R','E',' ','C','l','a','s','s','=','\'','%','s','\'',0}; 486 UINT len = class_len + ARRAY_SIZE(fmtW); 487 WCHAR *ret; 488 489 if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) return NULL; 490 swprintf( ret, fmtW, class ); 491 return ret; 492 } 493 494 static HRESULT create_assoc_enum( const WCHAR *class, UINT class_len, IEnumWbemClassObject **iter ) 495 { 496 WCHAR *query; 497 HRESULT hr; 498 499 if (!(query = build_assoc_query( class, class_len ))) return E_OUTOFMEMORY; 500 hr = exec_query( query, iter ); 501 heap_free( query ); 502 return hr; 503 } 504 505 static WCHAR *build_antecedent_query( const WCHAR *assocclass, const WCHAR *dependent ) 506 { 507 static const WCHAR fmtW[] = 508 {'S','E','L','E','C','T',' ','A','n','t','e','c','e','d','e','n','t',' ','F','R','O','M',' ','%','s',' ', 509 'W','H','E','R','E',' ','D','e','p','e','n','d','e','n','t','=','\'','%','s','\'',0}; 510 UINT len = lstrlenW(assocclass) + lstrlenW(dependent) + ARRAY_SIZE(fmtW); 511 WCHAR *ret; 512 513 if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) return NULL; 514 swprintf( ret, fmtW, assocclass, dependent ); 515 return ret; 516 } 517 518 static BSTR build_servername(void) 519 { 520 WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p; 521 DWORD len = ARRAY_SIZE( server ); 522 523 if (!(GetComputerNameW( server, &len ))) return NULL; 524 for (p = server; *p; p++) *p = towupper( *p ); 525 return SysAllocString( server ); 526 } 527 528 static BSTR build_namespace(void) 529 { 530 static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0}; 531 return SysAllocString( cimv2W ); 532 } 533 534 static WCHAR *build_canonical_path( const WCHAR *relpath ) 535 { 536 static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':',0}; 537 BSTR server, namespace; 538 WCHAR *ret; 539 UINT len, i; 540 541 if (!(server = build_servername())) return NULL; 542 if (!(namespace = build_namespace())) 543 { 544 SysFreeString( server ); 545 return NULL; 546 } 547 548 len = ARRAY_SIZE( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + lstrlenW( relpath ); 549 if ((ret = heap_alloc( len * sizeof(WCHAR ) ))) 550 { 551 len = swprintf( ret, fmtW, server, namespace ); 552 for (i = 0; i < lstrlenW( relpath ); i ++) 553 { 554 if (relpath[i] == '\'') ret[len++] = '"'; 555 else ret[len++] = relpath[i]; 556 } 557 ret[len] = 0; 558 } 559 560 SysFreeString( server ); 561 SysFreeString( namespace ); 562 return ret; 563 } 564 565 static HRESULT get_antecedent( const WCHAR *assocclass, const WCHAR *dependent, BSTR *ret ) 566 { 567 static const WCHAR antecedentW[] = {'A','n','t','e','c','e','d','e','n','t',0}; 568 WCHAR *fullpath, *str; 569 IEnumWbemClassObject *iter = NULL; 570 IWbemClassObject *obj; 571 HRESULT hr = E_OUTOFMEMORY; 572 ULONG count; 573 VARIANT var; 574 575 if (!(fullpath = build_canonical_path( dependent ))) return E_OUTOFMEMORY; 576 if (!(str = build_antecedent_query( assocclass, fullpath ))) goto done; 577 if ((hr = exec_query( str, &iter )) != S_OK) goto done; 578 579 IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count ); 580 if (!count) 581 { 582 *ret = NULL; 583 goto done; 584 } 585 586 hr = IWbemClassObject_Get( obj, antecedentW, 0, &var, NULL, NULL ); 587 IWbemClassObject_Release( obj ); 588 if (hr != S_OK) goto done; 589 *ret = V_BSTR( &var ); 590 591 done: 592 if (iter) IEnumWbemClassObject_Release( iter ); 593 heap_free( str ); 594 heap_free( fullpath ); 595 return hr; 596 } 597 598 static HRESULT do_query( const WCHAR *str, struct query **ret_query ) 599 { 600 struct query *query; 601 HRESULT hr; 602 603 if (!(query = create_query())) return E_OUTOFMEMORY; 604 if ((hr = parse_query( str, &query->view, &query->mem )) != S_OK || (hr = execute_view( query->view )) != S_OK) 605 { 606 release_query( query ); 607 return hr; 608 } 609 *ret_query = query; 610 return S_OK; 611 } 612 613 static HRESULT get_antecedent_table( const WCHAR *assocclass, const WCHAR *dependent, struct table **table ) 614 { 615 BSTR antecedent = NULL; 616 struct path *path = NULL; 617 WCHAR *str = NULL; 618 struct query *query = NULL; 619 HRESULT hr; 620 621 if ((hr = get_antecedent( assocclass, dependent, &antecedent )) != S_OK) return hr; 622 if (!antecedent) 623 { 624 *table = NULL; 625 return S_OK; 626 } 627 if ((hr = parse_path( antecedent, &path )) != S_OK) goto done; 628 if (!(str = query_from_path( path ))) 629 { 630 hr = E_OUTOFMEMORY; 631 goto done; 632 } 633 634 if ((hr = do_query( str, &query )) != S_OK) goto done; 635 if (query->view->table_count) *table = addref_table( query->view->table[0] ); 636 else *table = NULL; 637 638 done: 639 if (query) release_query( query ); 640 free_path( path ); 641 SysFreeString( antecedent ); 642 heap_free( str ); 643 return hr; 644 } 645 646 static HRESULT exec_assoc_view( struct view *view ) 647 { 648 static const WCHAR assocclassW[] = {'A','s','s','o','c','C','l','a','s','s',0}; 649 IEnumWbemClassObject *iter = NULL; 650 struct path *path; 651 HRESULT hr; 652 653 if (view->keywordlist) FIXME( "ignoring keywords\n" ); 654 if ((hr = parse_path( view->path, &path )) != S_OK) return hr; 655 656 if ((hr = create_assoc_enum( path->class, path->class_len, &iter )) != S_OK) goto done; 657 for (;;) 658 { 659 ULONG count; 660 IWbemClassObject *obj; 661 struct table *table; 662 VARIANT var; 663 664 IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count ); 665 if (!count) break; 666 667 if ((hr = IWbemClassObject_Get( obj, assocclassW, 0, &var, NULL, NULL )) != S_OK) 668 { 669 IWbemClassObject_Release( obj ); 670 goto done; 671 } 672 IWbemClassObject_Release( obj ); 673 674 hr = get_antecedent_table( V_BSTR(&var), view->path, &table ); 675 VariantClear( &var ); 676 if (hr != S_OK) goto done; 677 678 if (table && (hr = append_table( view, table )) != S_OK) 679 { 680 release_table( table ); 681 goto done; 682 } 683 } 684 685 if (view->table_count) 686 { 687 if (!(view->result = heap_alloc_zero( view->table_count * sizeof(UINT) ))) hr = E_OUTOFMEMORY; 688 else view->result_count = view->table_count; 689 } 690 691 done: 692 if (iter) IEnumWbemClassObject_Release( iter ); 693 free_path( path ); 694 return hr; 695 } 696 697 static HRESULT exec_select_view( struct view *view ) 698 { 699 UINT i, j = 0, len; 700 enum fill_status status = FILL_STATUS_UNFILTERED; 701 struct table *table; 702 703 if (!view->table_count) return S_OK; 704 705 table = view->table[0]; 706 if (table->fill) 707 { 708 clear_table( table ); 709 status = table->fill( table, view->cond ); 710 } 711 if (status == FILL_STATUS_FAILED) return WBEM_E_FAILED; 712 if (!table->num_rows) return S_OK; 713 714 len = min( table->num_rows, 16 ); 715 if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY; 716 717 for (i = 0; i < table->num_rows; i++) 718 { 719 HRESULT hr; 720 LONGLONG val = 0; 721 UINT type; 722 723 if (j >= len) 724 { 725 UINT *tmp; 726 len *= 2; 727 if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY; 728 view->result = tmp; 729 } 730 if (status == FILL_STATUS_FILTERED) val = 1; 731 else if ((hr = eval_cond( table, i, view->cond, &val, &type )) != S_OK) return hr; 732 if (val) view->result[j++] = i; 733 } 734 735 view->result_count = j; 736 return S_OK; 737 } 738 739 HRESULT execute_view( struct view *view ) 740 { 741 switch (view->type) 742 { 743 case VIEW_TYPE_ASSOCIATORS: 744 return exec_assoc_view( view ); 745 746 case VIEW_TYPE_SELECT: 747 return exec_select_view( view ); 748 749 default: 750 ERR( "unhandled type %u\n", view->type ); 751 return E_INVALIDARG; 752 } 753 } 754 755 struct query *create_query(void) 756 { 757 struct query *query; 758 759 if (!(query = heap_alloc( sizeof(*query) ))) return NULL; 760 list_init( &query->mem ); 761 query->refs = 1; 762 return query; 763 } 764 765 void free_query( struct query *query ) 766 { 767 struct list *mem, *next; 768 769 if (!query) return; 770 destroy_view( query->view ); 771 LIST_FOR_EACH_SAFE( mem, next, &query->mem ) { heap_free( mem ); } 772 heap_free( query ); 773 } 774 775 struct query *addref_query( struct query *query ) 776 { 777 InterlockedIncrement( &query->refs ); 778 return query; 779 } 780 781 void release_query( struct query *query ) 782 { 783 if (!InterlockedDecrement( &query->refs )) free_query( query ); 784 } 785 786 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result ) 787 { 788 HRESULT hr; 789 struct query *query; 790 791 *result = NULL; 792 if (!(query = create_query())) return E_OUTOFMEMORY; 793 hr = parse_query( str, &query->view, &query->mem ); 794 if (hr != S_OK) goto done; 795 hr = execute_view( query->view ); 796 if (hr != S_OK) goto done; 797 hr = EnumWbemClassObject_create( query, (void **)result ); 798 799 done: 800 release_query( query ); 801 return hr; 802 } 803 804 BOOL is_result_prop( const struct view *view, const WCHAR *name ) 805 { 806 const struct property *prop = view->proplist; 807 if (!prop) return TRUE; 808 while (prop) 809 { 810 if (!wcsicmp( prop->name, name )) return TRUE; 811 prop = prop->next; 812 } 813 return FALSE; 814 } 815 816 static BOOL is_system_prop( const WCHAR *name ) 817 { 818 return (name[0] == '_' && name[1] == '_'); 819 } 820 821 static BSTR build_proplist( const struct table *table, UINT row, UINT count, UINT *len ) 822 { 823 static const WCHAR fmtW[] = {'%','s','=','%','s',0}; 824 UINT i, j, offset; 825 BSTR *values, ret = NULL; 826 827 if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL; 828 829 *len = j = 0; 830 for (i = 0; i < table->num_cols; i++) 831 { 832 if (table->columns[i].type & COL_FLAG_KEY) 833 { 834 const WCHAR *name = table->columns[i].name; 835 values[j] = get_value_bstr( table, row, i ); 836 *len += lstrlenW( fmtW ) + lstrlenW( name ) + lstrlenW( values[j] ); 837 j++; 838 } 839 } 840 if ((ret = SysAllocStringLen( NULL, *len ))) 841 { 842 offset = j = 0; 843 for (i = 0; i < table->num_cols; i++) 844 { 845 if (table->columns[i].type & COL_FLAG_KEY) 846 { 847 const WCHAR *name = table->columns[i].name; 848 offset += swprintf( ret + offset, fmtW, name, values[j] ); 849 if (j < count - 1) ret[offset++] = ','; 850 j++; 851 } 852 } 853 } 854 for (i = 0; i < count; i++) SysFreeString( values[i] ); 855 heap_free( values ); 856 return ret; 857 } 858 859 static UINT count_key_columns( const struct table *table ) 860 { 861 UINT i, num_keys = 0; 862 863 for (i = 0; i < table->num_cols; i++) 864 { 865 if (table->columns[i].type & COL_FLAG_KEY) num_keys++; 866 } 867 return num_keys; 868 } 869 870 static BSTR build_relpath( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name ) 871 { 872 static const WCHAR fmtW[] = {'%','s','.','%','s',0}; 873 BSTR class, proplist, ret = NULL; 874 struct table *table = view->table[table_index]; 875 UINT row = view->result[result_index]; 876 UINT num_keys, len; 877 878 if (view->proplist) return NULL; 879 880 if (!(class = SysAllocString( view->table[table_index]->name ))) return NULL; 881 if (!(num_keys = count_key_columns( table ))) return class; 882 if (!(proplist = build_proplist( table, row, num_keys, &len ))) goto done; 883 884 len += lstrlenW( fmtW ) + SysStringLen( class ); 885 if (!(ret = SysAllocStringLen( NULL, len ))) goto done; 886 swprintf( ret, fmtW, class, proplist ); 887 888 done: 889 SysFreeString( class ); 890 SysFreeString( proplist ); 891 return ret; 892 } 893 894 static BSTR build_path( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name ) 895 { 896 static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0}; 897 BSTR server, namespace = NULL, relpath = NULL, ret = NULL; 898 UINT len; 899 900 if (view->proplist) return NULL; 901 902 if (!(server = build_servername())) return NULL; 903 if (!(namespace = build_namespace())) goto done; 904 if (!(relpath = build_relpath( view, table_index, result_index, name ))) goto done; 905 906 len = lstrlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath ); 907 if (!(ret = SysAllocStringLen( NULL, len ))) goto done; 908 swprintf( ret, fmtW, server, namespace, relpath ); 909 910 done: 911 SysFreeString( server ); 912 SysFreeString( namespace ); 913 SysFreeString( relpath ); 914 return ret; 915 } 916 917 BOOL is_method( const struct table *table, UINT column ) 918 { 919 return table->columns[column].type & COL_FLAG_METHOD; 920 } 921 922 static UINT count_properties( const struct table *table ) 923 { 924 UINT i, num_props = 0; 925 926 for (i = 0; i < table->num_cols; i++) 927 { 928 if (!is_method( table, i )) num_props++; 929 } 930 return num_props; 931 } 932 933 static UINT count_result_properties( const struct view *view, UINT table_index ) 934 { 935 const struct property *prop = view->proplist; 936 UINT count; 937 938 if (!prop) return count_properties( view->table[table_index] ); 939 940 count = 1; 941 while ((prop = prop->next)) count++; 942 return count; 943 } 944 945 static HRESULT get_system_propval( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name, 946 VARIANT *ret, CIMTYPE *type, LONG *flavor ) 947 { 948 static const WCHAR classW[] = {'_','_','C','L','A','S','S',0}; 949 static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0}; 950 static const WCHAR pathW[] = {'_','_','P','A','T','H',0}; 951 static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0}; 952 static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0}; 953 static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0}; 954 static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0}; 955 956 if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM; 957 958 if (!wcsicmp( name, classW )) 959 { 960 if (ret) 961 { 962 V_VT( ret ) = VT_BSTR; 963 V_BSTR( ret ) = SysAllocString( view->table[table_index]->name ); 964 } 965 if (type) *type = CIM_STRING; 966 return S_OK; 967 } 968 if (!wcsicmp( name, genusW )) 969 { 970 if (ret) 971 { 972 V_VT( ret ) = VT_I4; 973 V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */ 974 } 975 if (type) *type = CIM_SINT32; 976 return S_OK; 977 } 978 else if (!wcsicmp( name, namespaceW )) 979 { 980 if (ret) 981 { 982 V_VT( ret ) = VT_BSTR; 983 V_BSTR( ret ) = view->proplist ? NULL : build_namespace(); 984 } 985 if (type) *type = CIM_STRING; 986 return S_OK; 987 } 988 else if (!wcsicmp( name, pathW )) 989 { 990 if (ret) 991 { 992 V_VT( ret ) = VT_BSTR; 993 V_BSTR( ret ) = build_path( view, table_index, result_index, name ); 994 } 995 if (type) *type = CIM_STRING; 996 return S_OK; 997 } 998 if (!wcsicmp( name, propcountW )) 999 { 1000 if (ret) 1001 { 1002 V_VT( ret ) = VT_I4; 1003 V_I4( ret ) = count_result_properties( view, table_index ); 1004 } 1005 if (type) *type = CIM_SINT32; 1006 return S_OK; 1007 } 1008 else if (!wcsicmp( name, relpathW )) 1009 { 1010 if (ret) 1011 { 1012 V_VT( ret ) = VT_BSTR; 1013 V_BSTR( ret ) = build_relpath( view, table_index, result_index, name ); 1014 } 1015 if (type) *type = CIM_STRING; 1016 return S_OK; 1017 } 1018 else if (!wcsicmp( name, serverW )) 1019 { 1020 if (ret) 1021 { 1022 V_VT( ret ) = VT_BSTR; 1023 V_BSTR( ret ) = view->proplist ? NULL : build_servername(); 1024 } 1025 if (type) *type = CIM_STRING; 1026 return S_OK; 1027 } 1028 FIXME("system property %s not implemented\n", debugstr_w(name)); 1029 return WBEM_E_NOT_FOUND; 1030 } 1031 1032 VARTYPE to_vartype( CIMTYPE type ) 1033 { 1034 switch (type) 1035 { 1036 case CIM_BOOLEAN: return VT_BOOL; 1037 1038 case CIM_STRING: 1039 case CIM_REFERENCE: 1040 case CIM_DATETIME: return VT_BSTR; 1041 1042 case CIM_SINT8: return VT_I1; 1043 case CIM_UINT8: return VT_UI1; 1044 case CIM_SINT16: return VT_I2; 1045 1046 case CIM_UINT16: 1047 case CIM_SINT32: 1048 case CIM_UINT32: return VT_I4; 1049 1050 case CIM_SINT64: return VT_I8; 1051 case CIM_UINT64: return VT_UI8; 1052 1053 case CIM_REAL32: return VT_R4; 1054 1055 default: 1056 ERR("unhandled type %u\n", type); 1057 break; 1058 } 1059 return 0; 1060 } 1061 1062 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE basetype ) 1063 { 1064 SAFEARRAY *ret; 1065 VARTYPE vartype = to_vartype( basetype ); 1066 LONG i; 1067 1068 if (!array || !(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL; 1069 1070 for (i = 0; i < array->count; i++) 1071 { 1072 void *ptr = (char *)array->ptr + i * array->elem_size; 1073 if (vartype == VT_BSTR) 1074 { 1075 BSTR str = SysAllocString( *(const WCHAR **)ptr ); 1076 if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK) 1077 { 1078 SysFreeString( str ); 1079 SafeArrayDestroy( ret ); 1080 return NULL; 1081 } 1082 SysFreeString( str ); 1083 } 1084 else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK) 1085 { 1086 SafeArrayDestroy( ret ); 1087 return NULL; 1088 } 1089 } 1090 return ret; 1091 } 1092 1093 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret ) 1094 { 1095 if (type & VT_ARRAY) 1096 { 1097 V_VT( ret ) = type; 1098 V_ARRAY( ret ) = val_ptr; 1099 return; 1100 } 1101 switch (type) 1102 { 1103 case VT_BOOL: 1104 V_BOOL( ret ) = val; 1105 break; 1106 case VT_BSTR: 1107 V_BSTR( ret ) = val_ptr; 1108 break; 1109 case VT_I1: 1110 V_I1( ret ) = val; 1111 break; 1112 case VT_UI1: 1113 V_UI1( ret ) = val; 1114 break; 1115 case VT_I2: 1116 V_I2( ret ) = val; 1117 break; 1118 case VT_UI2: 1119 V_UI2( ret ) = val; 1120 break; 1121 case VT_I4: 1122 V_I4( ret ) = val; 1123 break; 1124 case VT_UI4: 1125 V_UI4( ret ) = val; 1126 break; 1127 case VT_NULL: 1128 break; 1129 case VT_R4: 1130 V_R4( ret ) = *(FLOAT *)&val; 1131 break; 1132 default: 1133 ERR("unhandled variant type %u\n", type); 1134 return; 1135 } 1136 V_VT( ret ) = type; 1137 } 1138 1139 static HRESULT map_view_index( const struct view *view, UINT index, UINT *table_index, UINT *result_index ) 1140 { 1141 if (!view->table) return WBEM_E_NOT_FOUND; 1142 1143 switch (view->type) 1144 { 1145 case VIEW_TYPE_SELECT: 1146 *table_index = 0; 1147 *result_index = index; 1148 break; 1149 1150 case VIEW_TYPE_ASSOCIATORS: 1151 *table_index = *result_index = index; 1152 break; 1153 1154 default: 1155 ERR( "unhandled view type %u\n", view->type ); 1156 return WBEM_E_FAILED; 1157 } 1158 return S_OK; 1159 } 1160 1161 struct table *get_view_table( const struct view *view, UINT index ) 1162 { 1163 switch (view->type) 1164 { 1165 case VIEW_TYPE_SELECT: 1166 return view->table[0]; 1167 1168 case VIEW_TYPE_ASSOCIATORS: 1169 return view->table[index]; 1170 1171 default: 1172 ERR( "unhandled view type %u\n", view->type ); 1173 return NULL; 1174 } 1175 } 1176 1177 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret, CIMTYPE *type, 1178 LONG *flavor ) 1179 { 1180 HRESULT hr; 1181 UINT column, row, table_index, result_index; 1182 struct table *table; 1183 VARTYPE vartype; 1184 void *val_ptr = NULL; 1185 LONGLONG val; 1186 1187 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr; 1188 1189 if (is_system_prop( name )) return get_system_propval( view, table_index, result_index, name, ret, type, flavor ); 1190 if (!view->result_count || !is_result_prop( view, name )) return WBEM_E_NOT_FOUND; 1191 1192 table = view->table[table_index]; 1193 hr = get_column_index( table, name, &column ); 1194 if (hr != S_OK || is_method( table, column )) return WBEM_E_NOT_FOUND; 1195 1196 row = view->result[result_index]; 1197 hr = get_value( table, row, column, &val ); 1198 if (hr != S_OK) return hr; 1199 1200 if (type) *type = table->columns[column].type & COL_TYPE_MASK; 1201 if (flavor) *flavor = 0; 1202 1203 if (!ret) return S_OK; 1204 1205 vartype = to_vartype( table->columns[column].type & CIM_TYPE_MASK ); 1206 if (table->columns[column].type & CIM_FLAG_ARRAY) 1207 { 1208 CIMTYPE basetype = table->columns[column].type & CIM_TYPE_MASK; 1209 1210 val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype ); 1211 if (!val_ptr) vartype = VT_NULL; 1212 else vartype |= VT_ARRAY; 1213 set_variant( vartype, val, val_ptr, ret ); 1214 return S_OK; 1215 } 1216 1217 switch (table->columns[column].type & COL_TYPE_MASK) 1218 { 1219 case CIM_STRING: 1220 case CIM_REFERENCE: 1221 case CIM_DATETIME: 1222 if (val) 1223 { 1224 vartype = VT_BSTR; 1225 val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val ); 1226 } 1227 else 1228 vartype = VT_NULL; 1229 break; 1230 case CIM_SINT64: 1231 vartype = VT_BSTR; 1232 val_ptr = get_value_bstr( table, row, column ); 1233 break; 1234 case CIM_UINT64: 1235 vartype = VT_BSTR; 1236 val_ptr = get_value_bstr( table, row, column ); 1237 break; 1238 case CIM_BOOLEAN: 1239 case CIM_SINT8: 1240 case CIM_UINT8: 1241 case CIM_SINT16: 1242 case CIM_UINT16: 1243 case CIM_SINT32: 1244 case CIM_UINT32: 1245 case CIM_REAL32: 1246 break; 1247 default: 1248 ERR("unhandled column type %u\n", table->columns[column].type); 1249 return WBEM_E_FAILED; 1250 } 1251 1252 set_variant( vartype, val, val_ptr, ret ); 1253 return S_OK; 1254 } 1255 1256 static CIMTYPE to_cimtype( VARTYPE type ) 1257 { 1258 switch (type) 1259 { 1260 case VT_BOOL: return CIM_BOOLEAN; 1261 case VT_BSTR: return CIM_STRING; 1262 case VT_I1: return CIM_SINT8; 1263 case VT_UI1: return CIM_UINT8; 1264 case VT_I2: return CIM_SINT16; 1265 case VT_UI2: return CIM_UINT16; 1266 case VT_I4: return CIM_SINT32; 1267 case VT_UI4: return CIM_UINT32; 1268 case VT_I8: return CIM_SINT64; 1269 case VT_UI8: return CIM_UINT64; 1270 default: 1271 ERR("unhandled type %u\n", type); 1272 break; 1273 } 1274 return 0; 1275 } 1276 1277 static struct array *to_array( VARIANT *var, CIMTYPE *type ) 1278 { 1279 struct array *ret; 1280 LONG bound, i; 1281 VARTYPE vartype; 1282 CIMTYPE basetype; 1283 1284 if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL; 1285 if (!(basetype = to_cimtype( vartype ))) return NULL; 1286 if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL; 1287 if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL; 1288 1289 ret->count = bound + 1; 1290 ret->elem_size = get_type_size( basetype ); 1291 if (!(ret->ptr = heap_alloc_zero( ret->count * ret->elem_size ))) 1292 { 1293 heap_free( ret ); 1294 return NULL; 1295 } 1296 for (i = 0; i < ret->count; i++) 1297 { 1298 void *ptr = (char *)ret->ptr + i * ret->elem_size; 1299 if (vartype == VT_BSTR) 1300 { 1301 BSTR str; 1302 if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK) 1303 { 1304 destroy_array( ret, basetype ); 1305 return NULL; 1306 } 1307 *(WCHAR **)ptr = heap_strdupW( str ); 1308 SysFreeString( str ); 1309 if (!*(WCHAR **)ptr) 1310 { 1311 destroy_array( ret, basetype ); 1312 return NULL; 1313 } 1314 } 1315 else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK) 1316 { 1317 destroy_array( ret, basetype ); 1318 return NULL; 1319 } 1320 } 1321 *type = basetype | CIM_FLAG_ARRAY; 1322 return ret; 1323 } 1324 1325 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type ) 1326 { 1327 if (!var) 1328 { 1329 *val = 0; 1330 return S_OK; 1331 } 1332 if (V_VT( var ) & VT_ARRAY) 1333 { 1334 *val = (INT_PTR)to_array( var, type ); 1335 if (!*val) return E_OUTOFMEMORY; 1336 return S_OK; 1337 } 1338 switch (V_VT( var )) 1339 { 1340 case VT_BOOL: 1341 *val = V_BOOL( var ); 1342 *type = CIM_BOOLEAN; 1343 break; 1344 case VT_BSTR: 1345 *val = (INT_PTR)heap_strdupW( V_BSTR( var ) ); 1346 if (!*val) return E_OUTOFMEMORY; 1347 *type = CIM_STRING; 1348 break; 1349 case VT_I2: 1350 *val = V_I2( var ); 1351 *type = CIM_SINT16; 1352 break; 1353 case VT_UI2: 1354 *val = V_UI2( var ); 1355 *type = CIM_UINT16; 1356 break; 1357 case VT_I4: 1358 *val = V_I4( var ); 1359 *type = CIM_SINT32; 1360 break; 1361 case VT_UI4: 1362 *val = V_UI4( var ); 1363 *type = CIM_UINT32; 1364 break; 1365 case VT_NULL: 1366 *val = 0; 1367 break; 1368 default: 1369 ERR("unhandled type %u\n", V_VT( var )); 1370 return WBEM_E_FAILED; 1371 } 1372 return S_OK; 1373 } 1374 1375 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type ) 1376 { 1377 HRESULT hr; 1378 UINT row, column, table_index, result_index; 1379 struct table *table; 1380 LONGLONG val; 1381 1382 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr; 1383 1384 table = view->table[table_index]; 1385 hr = get_column_index( table, name, &column ); 1386 if (hr != S_OK) 1387 { 1388 FIXME("no support for creating new properties\n"); 1389 return WBEM_E_FAILED; 1390 } 1391 if (is_method( table, column ) || !(table->columns[column].type & COL_FLAG_DYNAMIC)) 1392 return WBEM_E_FAILED; 1393 1394 hr = to_longlong( var, &val, &type ); 1395 if (hr != S_OK) return hr; 1396 1397 row = view->result[result_index]; 1398 return set_value( table, row, column, val, type ); 1399 } 1400 1401 HRESULT get_properties( const struct view *view, UINT index, LONG flags, SAFEARRAY **props ) 1402 { 1403 SAFEARRAY *sa; 1404 BSTR str; 1405 UINT i, table_index, result_index, num_props; 1406 struct table *table; 1407 HRESULT hr; 1408 LONG j; 1409 1410 if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr; 1411 1412 num_props = count_result_properties( view, table_index ); 1413 if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY; 1414 1415 table = view->table[table_index]; 1416 for (i = 0, j = 0; i < table->num_cols; i++) 1417 { 1418 BOOL is_system; 1419 1420 if (is_method( table, i )) continue; 1421 if (!is_result_prop( view, table->columns[i].name )) continue; 1422 1423 is_system = is_system_prop( table->columns[i].name ); 1424 if ((flags & WBEM_FLAG_NONSYSTEM_ONLY) && is_system) continue; 1425 else if ((flags & WBEM_FLAG_SYSTEM_ONLY) && !is_system) continue; 1426 1427 str = SysAllocString( table->columns[i].name ); 1428 if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK) 1429 { 1430 SysFreeString( str ); 1431 SafeArrayDestroy( sa ); 1432 return E_OUTOFMEMORY; 1433 } 1434 SysFreeString( str ); 1435 j++; 1436 } 1437 *props = sa; 1438 return S_OK; 1439 } 1440