~ubuntu-branches/ubuntu/precise/kde-runtime/precise-updates

« back to all changes in this revision

Viewing changes to nepomuk/services/storage/datamanagementmodel.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-11-20 15:46:42 UTC
  • mfrom: (18.1.5 precise-proposed)
  • Revision ID: package-import@ubuntu.com-20141120154642-hyesdbuvsk78ihtz
Tags: 4:4.8.5-0ubuntu0.3
* SECURITY UPDATE: Insufficient Input Validation By IO Slaves and
  Webkit Part
 - Add upstream_CVE-2014-8600.diff to escape protocol twice: once
   for i18n, and once for HTML
 - https://www.kde.org/info/security/advisory-20141113-1.txt
 - CVE-2014-8600
 - LP: #1393479

Show diffs side-by-side

added added

removed removed

Lines of Context:
407
407
    //
408
408
    // Do the actual work
409
409
    //
410
 
    addProperty(uriHash, property, resolvedNodes, app);
 
410
    addProperty(uriHash, property, resolvedNodes, app, true /* signal propertyChanged */);
411
411
}
412
412
 
413
413
 
524
524
    //
525
525
    const QStringList uriHashN3 = resourceHashToN3(uriHash);
526
526
    if(!uriHashN3.isEmpty()) {
527
 
        const QSet<Soprano::Node> existingValues = QSet<Soprano::Node>::fromList(resolvedNodes.values());
 
527
        QHash<QUrl, QList<Soprano::Node> > valuesToRemove;
 
528
        const QSet<Soprano::Node> setValues = QSet<Soprano::Node>::fromList(resolvedNodes.values());
528
529
        QSet<QUrl> graphs;
529
530
        QList<Soprano::BindingSet> existing
530
531
                = executeQuery(QString::fromLatin1("select ?r ?v ?g where { graph ?g { ?r %1 ?v . FILTER(?r in (%2)) . } . }")
532
533
                                    uriHashN3.join(QLatin1String(","))),
533
534
                               Soprano::Query::QueryLanguageSparql).allBindings();
534
535
        Q_FOREACH(const Soprano::BindingSet& binding, existing) {
535
 
            if(!existingValues.contains(binding["v"])) {
 
536
            if(!setValues.contains(binding["v"])) {
536
537
                removeAllStatements(binding["r"], property, binding["v"]);
537
538
                graphs.insert(binding["g"].uri());
538
 
                d->m_watchManager->removeProperty(binding["r"], property, binding["v"]);
 
539
                valuesToRemove[binding["r"].uri()].append(binding["v"]);
539
540
            }
540
541
        }
541
542
        removeTrailingGraphs(graphs);
542
 
    }
543
 
 
544
 
 
545
 
    //
546
 
    // And finally add the rest of the statements (only if there is anything to add)
547
 
    //
548
 
    if(!nodes.isEmpty()) {
549
 
        addProperty(uriHash, property, resolvedNodes, app);
 
543
 
 
544
        // construct the lists of old and new values
 
545
        QHash<QUrl, QList<Soprano::Node> > addedValues;
 
546
 
 
547
        //
 
548
        // And finally add the rest of the statements (only if there is anything to add)
 
549
        //
 
550
        if(!nodes.isEmpty()) {
 
551
            addedValues = addProperty(uriHash, property, resolvedNodes, app);
 
552
        }
 
553
 
 
554
        //
 
555
        // Inform interested parties about the changes
 
556
        //
 
557
        QSet<QUrl> allChangedResources = uriHash.values().toSet();
 
558
        allChangedResources.remove(QUrl());
 
559
        foreach(const QUrl& res, allChangedResources) {
 
560
            const QList<Soprano::Node> added = addedValues.value(res);
 
561
            const QList<Soprano::Node> removed = valuesToRemove.value(res);
 
562
            if(!added.isEmpty() || !removed.isEmpty()) {
 
563
                d->m_watchManager->changeProperty(res,
 
564
                                                  property,
 
565
                                                  added,
 
566
                                                  removed);
 
567
            }
 
568
        }
550
569
    }
551
570
}
552
571
 
626
645
    //
627
646
    QUrl mtimeGraph;
628
647
    QSet<QUrl> graphs;
629
 
    const QString propertyN3 = Soprano::Node::resourceToN3(property);
630
648
    foreach( const QUrl & res, resolvedResources ) {
631
649
        const QList<Soprano::BindingSet> valueGraphs
632
650
                = executeQuery(QString::fromLatin1("select ?g ?v where { graph ?g { %1 %2 ?v . } . FILTER(?v in (%3)) . }")
633
651
                               .arg(Soprano::Node::resourceToN3(res),
634
 
                                    propertyN3,
 
652
                                    Soprano::Node::resourceToN3(property),
635
653
                                    nodesToN3(resolvedNodes).join(QLatin1String(","))),
636
654
                               Soprano::Query::QueryLanguageSparql).allBindings();
637
655
 
 
656
        QSet<Soprano::Node> removedValues;
638
657
        foreach(const Soprano::BindingSet& binding, valueGraphs) {
 
658
            const Soprano::Node v = binding["v"];
639
659
            graphs.insert( binding["g"].uri() );
640
 
            removeAllStatements( res, property, binding["v"] );
641
 
            d->m_watchManager->removeProperty( res, property, binding["v"]);
 
660
            removeAllStatements( res, property, v );
 
661
            removedValues << v;
 
662
        }
 
663
 
 
664
        if(!removedValues.isEmpty()) {
 
665
            d->m_watchManager->changeProperty( res, property, QList<Soprano::Node>(), removedValues.toList() );
642
666
        }
643
667
 
644
668
        // we only update the mtime in case we actually remove anything
727
751
    QSet<QUrl> graphs;
728
752
    foreach( const QUrl & res, resolvedResources ) {
729
753
        QSet<Soprano::Node> propertiesToRemove;
730
 
        QList<QPair<Soprano::Node, Soprano::Node> > propertyValues;
 
754
        QMultiHash<QUrl, Soprano::Node> propertyValues;
731
755
        Soprano::QueryResultIterator it
732
756
                = executeQuery(QString::fromLatin1("select distinct ?g ?p ?v where { graph ?g { %1 ?p ?v . } . FILTER(?p in (%2)) . }")
733
757
                               .arg(Soprano::Node::resourceToN3(res),
736
760
        while(it.next()) {
737
761
            graphs.insert(it["g"].uri());
738
762
            propertiesToRemove.insert(it["p"]);
739
 
            propertyValues.append(qMakePair(it["p"], it["v"]));
 
763
            propertyValues.insert( it["p"].uri(), it["v"] );
740
764
        }
741
765
 
742
766
        // remove the data
745
769
        }
746
770
 
747
771
        // inform interested parties
748
 
        for(QList<QPair<Soprano::Node, Soprano::Node> >::const_iterator it = propertyValues.constBegin();
749
 
            it != propertyValues.constEnd(); ++it) {
750
 
            d->m_watchManager->removeProperty(res, it->first.uri(), it->second);
 
772
        for(QMultiHash<QUrl, Soprano::Node>::const_iterator it = propertyValues.constBegin();
 
773
            it != propertyValues.constEnd(); ) {
 
774
            QList<Soprano::Node> values;
 
775
            values << it.value();
 
776
 
 
777
            const QUrl property = it.key();
 
778
            for( ++it; it != propertyValues.constEnd() && it.key() == property; ++it ) {
 
779
                values << it.value();
 
780
            }
 
781
 
 
782
            d->m_watchManager->changeProperty(res, property, QList<Soprano::Node>(), values);
751
783
        }
752
784
 
753
785
        // we only update the mtime in case we actually remove anything
1507
1539
 
1508
1540
            const Soprano::Error::Error error = d->m_classAndPropertyTree->lastError();
1509
1541
            if( error ) {
1510
 
                setError( error.message(), error.code() );
 
1542
                setError( error );
1511
1543
                return QHash<QUrl, QUrl>();
1512
1544
            }
1513
1545
            syncRes.insert( hit.key(), n );
1545
1577
                    }
1546
1578
                    else if(state == NonExistingFileUrl) {
1547
1579
                        setError(QString::fromLatin1("Cannot store information about non-existing local files. File '%1' does not exist.").arg(object.uri().toLocalFile()),
1548
 
                                Soprano::Error::ErrorInvalidArgument);
 
1580
                                 Soprano::Error::ErrorInvalidArgument);
1549
1581
                        return QHash<QUrl, QUrl>();
1550
1582
                    }
1551
1583
                    else if(state == ExistingFileUrl || state==SupportedUrl) {
1581
1613
                    else if(state == OtherUri) {
1582
1614
                        // We use resolveUrl to check if the otherUri exists. If it doesn't exist,
1583
1615
                        // then resolveUrl which set the last error
 
1616
                        // trueg: seems like a waste to not use the resolved uri here!
1584
1617
                        const QUrl legacyUri = resolveUrl( object.uri() );
1585
1618
                        if( lastError() )
1586
1619
                            return QHash<QUrl, QUrl>();
1593
1626
                    QUrl url = object.uri();
1594
1627
                    if( url.scheme() == QLatin1String("file") && !QFile::exists(url.toLocalFile()) ) {
1595
1628
                        setError(QString::fromLatin1("Cannot store information about non-existing local files. File '%1' does not exist.").arg(object.uri().toLocalFile()),
1596
 
                                Soprano::Error::ErrorInvalidArgument);
 
1629
                                 Soprano::Error::ErrorInvalidArgument);
1597
1630
                        return QHash<QUrl, QUrl>();
1598
1631
                    }
1599
1632
                }
1600
1633
            } // if object.isResurce
1601
1634
        } // while( it.hasNext() )
1602
 
 
1603
1635
        // The resource is now ready.
1604
1636
        syncResources << syncRes;
1605
1637
    }
2325
2357
 
2326
2358
 
2327
2359
// TODO: emit resource watcher resource creation signals
2328
 
void Nepomuk::DataManagementModel::addProperty(const QHash<QUrl, QUrl> &resources, const QUrl &property, const QHash<Soprano::Node, Soprano::Node> &nodes, const QString &app)
 
2360
QHash<QUrl, QList<Soprano::Node> > Nepomuk::DataManagementModel::addProperty(const QHash<QUrl, QUrl> &resources, const QUrl &property, const QHash<Soprano::Node, Soprano::Node> &nodes, const QString &app, bool signalPropertyChanged)
2329
2361
{
2330
2362
    kDebug() << resources << property << nodes << app;
2331
2363
    Q_ASSERT(!resources.isEmpty());
2339
2371
    if( maxCardinality == 1 ) {
2340
2372
        if( nodes.size() != 1 ) {
2341
2373
            setError(QString::fromLatin1("%1 has cardinality of 1. Cannot set more then one value.").arg(property.toString()), Soprano::Error::ErrorInvalidArgument);
2342
 
            return;
 
2374
            return QHash<QUrl, QList<Soprano::Node> >();
2343
2375
        }
2344
2376
    }
2345
2377
 
2360
2392
                graph = createGraph( app );
2361
2393
                if(!graph.isValid()) {
2362
2394
                    // error has been set in createGraph
2363
 
                    return;
 
2395
                    return QHash<QUrl, QList<Soprano::Node> >();
2364
2396
                }
2365
2397
            }
2366
2398
            const QUrl uri = createUri(ResourceUri);
2385
2417
                graph = createGraph( app );
2386
2418
                if(!graph.isValid()) {
2387
2419
                    // error has been set in createGraph
2388
 
                    return;
 
2420
                    return QHash<QUrl, QList<Soprano::Node> >();
2389
2421
                }
2390
2422
            }
2391
2423
            uri = createUri(ResourceUri);
2411
2443
    //
2412
2444
    if(!knownResources.isEmpty()) {
2413
2445
        const QString existingValuesQuery = QString::fromLatin1("select distinct ?r ?v ?g ?m "
2414
 
                                                                "(select count(*) where { graph ?g { ?s ?p ?o . } . FILTER(%5) . }) as ?cnt "
 
2446
                                                                "(select count(*) where { graph ?g { ?s ?p ?o . } . FILTER(%4) . }) as ?cnt "
2415
2447
                                                                "where { "
2416
2448
                                                                "graph ?g { ?r %2 ?v . } . "
2417
2449
                                                                "?m %1 ?g . "
2418
2450
                                                                "FILTER(?r in (%3)) . "
2419
 
                                                                "FILTER(?v in (%4)) . }")
 
2451
                                                                "FILTER(?v in (%5)) . }")
2420
2452
                .arg(Soprano::Node::resourceToN3(NRL::coreGraphMetadataFor()),
2421
2453
                     Soprano::Node::resourceToN3(property),
2422
2454
                     resourcesToN3(knownResources).join(QLatin1String(",")),
2423
 
                     nodesToN3(resolvedNodes).join(QLatin1String(",")),
2424
 
                     createResourceMetadataPropertyFilter(QLatin1String("?p")));
 
2455
                     createResourceMetadataPropertyFilter(QLatin1String("?p")),
 
2456
                     nodesToN3(resolvedNodes).join(QLatin1String(",")));
2425
2457
        QList<Soprano::BindingSet> existingValueBindings = executeQuery(existingValuesQuery, Soprano::Query::QueryLanguageSparql).allBindings();
2426
2458
        Q_FOREACH(const Soprano::BindingSet& binding, existingValueBindings) {
2427
2459
            kDebug() << "Existing value" << binding;
2431
2463
            const QUrl m = binding["m"].uri();
2432
2464
            const int cnt = binding["cnt"].literal().toInt();
2433
2465
 
2434
 
            // we handle this property here - thus, no need to handle it below
2435
 
            finalProperties.remove(qMakePair(r, v));
2436
 
 
2437
 
            // in case the app is the same there is no need to do anything
2438
 
            if(containsStatement(g, NAO::maintainedBy(), appRes, m)) {
2439
 
                continue;
2440
 
            }
2441
 
            else if(cnt == 1) {
2442
 
                // we can reuse the graph
2443
 
                addStatement(g, NAO::maintainedBy(), appRes, m);
2444
 
            }
2445
 
            else {
2446
 
                // we need to split the graph
2447
 
                // FIXME: do not split the same graph again and again. Check if the graph in question already is the one we created.
2448
 
                const QUrl newGraph = splitGraph(g, m, appRes);
2449
 
 
2450
 
                // and finally move the actual property over to the new graph
2451
 
                removeStatement(r, property, v, g);
2452
 
                addStatement(r, property, v, newGraph);
 
2466
            // in case we do not signal the changes we restrict the values already in the query
 
2467
            if(resolvedNodes.contains(v)) {
 
2468
                // we handle this property here - thus, no need to handle it below
 
2469
                finalProperties.remove(qMakePair(r, v));
 
2470
 
 
2471
                // in case the app is the same there is no need to do anything
 
2472
                if(containsStatement(g, NAO::maintainedBy(), appRes, m)) {
 
2473
                    continue;
 
2474
                }
 
2475
                else if(cnt == 1) {
 
2476
                    // we can reuse the graph
 
2477
                    addStatement(g, NAO::maintainedBy(), appRes, m);
 
2478
                }
 
2479
                else {
 
2480
                    // we need to split the graph
 
2481
                    // FIXME: do not split the same graph again and again. Check if the graph in question already is the one we created.
 
2482
                    const QUrl newGraph = splitGraph(g, m, appRes);
 
2483
 
 
2484
                    // and finally move the actual property over to the new graph
 
2485
                    removeStatement(r, property, v, g);
 
2486
                    addStatement(r, property, v, newGraph);
 
2487
                }
2453
2488
            }
2454
2489
        }
2455
2490
    }
2463
2498
            graph = createGraph( app );
2464
2499
            if(!graph.isValid()) {
2465
2500
                // error has been set in createGraph
2466
 
                return;
 
2501
                return QHash<QUrl, QList<Soprano::Node> >();
2467
2502
            }
2468
2503
        }
2469
2504
 
2470
2505
        // add all the data
2471
2506
        // TODO: check if using one big sparql insert improves performance
2472
 
        QSet<QUrl> finalResources;
 
2507
        QHash<QUrl, QList<Soprano::Node> > finalValuesPerResource;
2473
2508
        for(QSet<QPair<QUrl, Soprano::Node> >::const_iterator it = finalProperties.constBegin(); it != finalProperties.constEnd(); ++it) {
2474
2509
            addStatement(it->first, property, it->second, graph);
2475
2510
            if(property == NIE::url() && it->second.uri().scheme() == QLatin1String("file")) {
2476
2511
                addStatement(it->first, RDF::type(), NFO::FileDataObject(), graph);
2477
2512
            }
2478
 
            finalResources.insert(it->first);
2479
 
            d->m_watchManager->addProperty(it->first, property, it->second);
 
2513
            finalValuesPerResource[it->first].append(it->second);
 
2514
        }
 
2515
 
 
2516
        // inform interested parties
 
2517
        if(signalPropertyChanged) {
 
2518
            for(QHash<QUrl, QList<Soprano::Node> >::const_iterator it = finalValuesPerResource.constBegin(); it != finalValuesPerResource.constEnd(); ++it) {
 
2519
                d->m_watchManager->changeProperty(it.key(), property, it.value(), QList<Soprano::Node>());
 
2520
            }
2480
2521
        }
2481
2522
 
2482
2523
        // update modification date
2483
 
        Q_FOREACH(const QUrl& res, finalResources) {
 
2524
        Q_FOREACH(const QUrl& res, finalValuesPerResource.keys()) {
2484
2525
            updateModificationDate(res, graph, QDateTime::currentDateTime(), true);
2485
2526
        }
 
2527
 
 
2528
        return finalValuesPerResource;
2486
2529
    }
 
2530
 
 
2531
    return QHash<QUrl, QList<Soprano::Node> >();
2487
2532
}
2488
2533
 
2489
2534
bool Nepomuk::DataManagementModel::doesResourceExist(const QUrl &res, const QUrl& graph) const
2580
2625
    QHash<Soprano::Node, Soprano::Node> resolvedNodes;
2581
2626
    Q_FOREACH(const Soprano::Node& node, nodes) {
2582
2627
        if(node.isResource()) {
2583
 
            resolvedNodes.insert(node, resolveUrl(node.uri(), true));
 
2628
            const QUrl resolved = resolveUrl(node.uri(), true);
 
2629
            if(resolved.isEmpty() && lastError()) {
 
2630
                break;
 
2631
            }
 
2632
            resolvedNodes.insert(node, resolved);
2584
2633
        }
2585
2634
        else {
2586
2635
            resolvedNodes.insert(node, node);