diff options
author | Márcio Alexandre Silva Delgado <coadde@lavabit.com> | 2012-10-21 19:51:39 -0200 |
---|---|---|
committer | Márcio Alexandre Silva Delgado <coadde@lavabit.com> | 2012-10-21 19:51:39 -0200 |
commit | ee7f9096475e0ea57d9326d087f94e3df4c6512b (patch) | |
tree | 0e9b42a4cb590b3c59632a91b519e0bacac38bd3 /libre | |
parent | b4ce63a23bfc79192dfc546c4196ec651dd31393 (diff) | |
parent | b09b1d60e80ef66c0817fcc7466a20ec5a365520 (diff) | |
download | abslibre-ee7f9096475e0ea57d9326d087f94e3df4c6512b.tar.gz abslibre-ee7f9096475e0ea57d9326d087f94e3df4c6512b.tar.bz2 abslibre-ee7f9096475e0ea57d9326d087f94e3df4c6512b.zip |
Merge branch 'master' of ssh://parabolagnulinux.org:1863/srv/git/abslibre
Diffstat (limited to 'libre')
41 files changed, 3609 insertions, 5668 deletions
diff --git a/libre/apache-ant/PKGBUILD b/libre/apache-ant/PKGBUILD deleted file mode 100755 index 77e0dfe94..000000000 --- a/libre/apache-ant/PKGBUILD +++ /dev/null @@ -1,110 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> -# Maintainer (Arch): Paul Mattal <paul@archlinux.org> -# Contributor: Andrew Wright <andreww@photism.org> - -pkgname=apache-ant -pkgver=1.8.4 - -provides=("apache-ant-libre=$pkgver") -replaces=("apache-ant-libre") -conflicts=("apache-ant-libre") - -pkgrel=1.1 -pkgdesc="A Java-based build tool" -arch=('any') -license=('Apache') -url="http://ant.apache.org/" -_mirror=http://archive.apache.org/dist -source=($_mirror/ant/source/${pkgname}-${pkgver}-src.tar.bz2 - ${pkgname}.sh ${pkgname}.csh) -depends=('java-environment') - -# This list is adapted from https://ant.apache.org/manual/install.html#librarydependencies -declare -A _opts -_opts[junit]='to have JUnit on the classpath in javac tasks;/usr/share/java/junit.jar' -_opts[xalan-java]='<junitreport> task;/usr/share/java/xalan.jar' -_opts[antlr2]='<antlr> task;/usr/share/java/antlr2.jar::antlr.jar' -#_opts[java-bsf]='<script> task;/usr/share/java/bsf.jar' -#_opts[groovy]='Groovy with <script> and <scriptdef> tasks;/usr/share/java/groovy.jar' -_opts[java-asm2]='Groovy with <script> and <scriptdef> tasks;/usr/share/java/asm-2.jar::asm.jar /usr/share/java/asm-util-2.jar::asm-util.jar' -#_opts[netrexx]='<netrexx> task, Rexx with <script> task;/usr/share/java/netrexx.jar' -_opts[rhino]='Javascript with <script> task;/usr/share/java/js.jar' -_opts[jython]='Python with <script> task;/opt/jython/jython.jar' -#_opts[jacl]='TCL with <script> task;/usr/share/java/jacl.jar' -#_opts[tcljava]='TCL with <script> task;/usr/share/java/tcljava.jar' -_opts[beanshell>=1.3]='BeanShell with <script> task;/usr/share/java/bsh.jar::beanshell.jar' -#_opts[jruby]='Ruby with <script> task;/usr/share/java/jruby.jar' -#_opts[judo]='Judoscript with <script> task;/usr/share/java/judo.jar' -_opts[java-commons-logging]='CommonsLoggingListener;/usr/share/java/commons-logging/commons-logging.jar' -#_opts[java-log4j]='Log4jListener;/usr/share/java/log4j.jar' -#_opts[java-commons-net>=1.4.0]='<ftp>, <rexec> and <telnet> tasks;/usr/share/java/commons-net.jar' -#_opts[java-bcel]="'classfileset' data type, JavaClassHelper for ClassConstants filter reader;/usr/share/java/bcel.jar" -#_opts[java-mail]='<mimemail> task, mime encoding with <mail>;/usr/share/java/mail.jar' -#_opts[java-activation]='<mimemail> task, mime encoding with <mail>;/usr/share/java/activation.jar' -#_opts[jdepend]='<jdepend> task;/usr/share/java/jdepend.jar' -#_opts[java-xmlcommons-resolver>=1.1beta]="external files for 'xmlcatalog' datatype;/usr/share/java/resolver.jar" -#_opts[java-jsch>=0.1.42]='<sshexec> and <scp> tasks;/usr/share/java/jsch.jar' -#_opts[java-advanced-imaging]='<image> task/usr/share/java/jai/*.jar' - -for pkg in "${!_opts[@]}"; do - optdepends+=("$pkg: ${_opts[$pkg]%;*}") - makedepends+=("$pkg") -done - -build() { - # This directory is what becomes - # http://archive.apache.org/dist/ant/binaries/${pkgname}-${pkgver}-bin.tar.bz2 - # which is what Arch uses - rm -rf "${srcdir}"/${pkgname}-${pkgver}-bin - mkdir -p "${srcdir}"/${pkgname}-${pkgver}-bin - - cd "${srcdir}"/${pkgname}-${pkgver} - # Symlink to external optional libraries - for jar in ${_opts[@]#*;}; do - ln -sf ${jar%::*} lib/optional/`basename ${jar/*::}` - done - # Build - source "/etc/profile.d/jdk.sh" # Get the JAVA_HOME env var - sh build.sh -Ddist.dir="${srcdir}"/${pkgname}-${pkgver}-bin dist -} - -package() { - cd "${srcdir}"/${pkgname}-${pkgver}-bin - source "${srcdir}"/${pkgname}.sh # Get the ANT_HOME env var - source "/etc/profile.d/jdk.sh" # Get the JAVA_HOME env var - - ## Install profile.d script - install -d "${pkgdir}"/etc/profile.d - install -m755 "${srcdir}"/${pkgname}.{csh,sh} "${pkgdir}"/etc/profile.d/ - - ## Install the main distribution - install -d "${pkgdir}"/${ANT_HOME} - cp -Rp * "${pkgdir}"/${ANT_HOME} - - ## Fix the distribution - # Remove Windows .bat/.cmd files - rm -f "${pkgdir}"/${ANT_HOME}/bin/*.{bat,cmd} - # Fix python2 path - sed -i 's|/usr/bin/python|/usr/bin/python2|' "${pkgdir}"/${ANT_HOME}/bin/runant.py - # Symlink to external optional libraries - for jar in ${_opts[@]#*;}; do - ln -sf ${jar%::*} "${pkgdir}"/${ANT_HOME}/lib/`basename ${jar/*::}` - done - - ## Symlink the /opt distribution to the normal places - install -d "${pkgdir}"/usr/bin - install -d "${pkgdir}"/usr/share/doc/${pkgname} - install -d "${pkgdir}"/usr/share/licenses/${pkgname} - - cd "${pkgdir}"/${ANT_HOME} - for prog in bin/*; do - ln -sf ${ANT_HOME}/$prog "${pkgdir}"/usr/bin - done - ln -sf ${ANT_HOME}/{README,WHATSNEW} "${pkgdir}"/usr/share/doc/${pkgname} - ln -sf ${ANT_HOME}/docs "${pkgdir}"/usr/share/doc/${pkgname}/html - ln -sf ${ANT_HOME}/{LICENSE,NOTICE} "${pkgdir}"/usr/share/licenses/${pkgname} -} - -md5sums=('c474fa9d0c35a24037c23b6e476862c1' - 'bd63c881be406f515fc4d22635e8326a' - 'aaa615512cbe1ed7f3b62c1ff46802f8') diff --git a/libre/apache-ant/apache-ant.csh b/libre/apache-ant/apache-ant.csh deleted file mode 100755 index fdc04b2f8..000000000 --- a/libre/apache-ant/apache-ant.csh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/csh -setenv ANT_HOME /opt/apache-ant diff --git a/libre/apache-ant/apache-ant.sh b/libre/apache-ant/apache-ant.sh deleted file mode 100755 index 6e4809da5..000000000 --- a/libre/apache-ant/apache-ant.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -export ANT_HOME=/opt/apache-ant diff --git a/libre/django13/PKGBUILD b/libre/django13/PKGBUILD new file mode 100644 index 000000000..554acccc7 --- /dev/null +++ b/libre/django13/PKGBUILD @@ -0,0 +1,47 @@ +# $Id$ +# Maintainer: Dan McGee <dan@archlinux.org> +# Contributor: Shahar Weiss <sweiss4@gmx.net> + +pkgname=django +pkgver=1.3.1 +pkgrel=2 +pkgdesc="A high-level Python Web framework." +arch=('any') +license=('BSD') +url="http://www.djangoproject.com/" +depends=('python2') +makedepends=('python2-distribute') +optdepends=('mysql-python: for MySQL backend' + 'python2-psycopg2: for PostgreSQL backend') +source=("https://www.djangoproject.com/m/releases/1.3/Django-$pkgver.tar.gz" + diff-django_branches_releases_1.3.X-from-16768-to-17460.diff) +md5sums=('62d8642fd06b9a0bf8544178f8500767' + 'd09d8f9e156b9aa1b580a1b43209b99f') +sha256sums=('af9118c4e8a063deb0b8cda901fcff2b805e7cf496c93fd43507163f3cde156b' + '8e08b5b5bbe7c042a1df4d5615a9d068ec6718fd00bef627c0a9a9e48ee58c15') + +build() { + cd "$srcdir/Django-$pkgver" + patch -Np1 -i ../diff-django_branches_releases_1.3.X-from-16768-to-17460.diff + python2 setup.py build +} + +package() { + cd "$srcdir/Django-$pkgver" + python2 setup.py install --root="$pkgdir" --optimize=1 + + install -Dm644 extras/django_bash_completion \ + "$pkgdir"/etc/bash_completion.d/django + + find "$pkgdir"/usr/lib/python2.7/site-packages/django/ -name '*.py' | \ + xargs sed -i "s|#!/usr/bin/env python$|#!/usr/bin/env python2|" + + install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE +} + +_pkgname=$pkgname +pkgname=django13 +pkgdesc+=" (legacy version for ParabolaWeb)" +pkgrel+=.1 +provides=("$_pkgname=$pkgver") +conflicts=("$_pkgname") diff --git a/libre/django13/PKGBUILD.orig b/libre/django13/PKGBUILD.orig new file mode 100644 index 000000000..c593c5626 --- /dev/null +++ b/libre/django13/PKGBUILD.orig @@ -0,0 +1,40 @@ +# $Id$ +# Maintainer: Dan McGee <dan@archlinux.org> +# Contributor: Shahar Weiss <sweiss4@gmx.net> + +pkgname=django +pkgver=1.3.1 +pkgrel=2 +pkgdesc="A high-level Python Web framework." +arch=('any') +license=('BSD') +url="http://www.djangoproject.com/" +depends=('python2') +makedepends=('python2-distribute') +optdepends=('mysql-python: for MySQL backend' + 'python2-psycopg2: for PostgreSQL backend') +source=("http://media.djangoproject.com/releases/1.3/Django-$pkgver.tar.gz" + diff-django_branches_releases_1.3.X-from-16771-to-17460.diff) +md5sums=('62d8642fd06b9a0bf8544178f8500767' + 'ea3d6cbde2fc2332ffe7f901cb60a974') +sha256sums=('af9118c4e8a063deb0b8cda901fcff2b805e7cf496c93fd43507163f3cde156b' + '84e2652a8249e58fdbbd43bce7cd8d6bb2159058be6a675ebe15661ca3ee9ffc') + +build() { + cd "$srcdir/Django-$pkgver" + patch -Np0 < ../diff-django_branches_releases_1.3.X-from-16771-to-17460.diff + python2 setup.py build +} + +package() { + cd "$srcdir/Django-$pkgver" + python2 setup.py install --root="$pkgdir" --optimize=1 + + install -Dm644 extras/django_bash_completion \ + "$pkgdir"/etc/bash_completion.d/django + + find "$pkgdir"/usr/lib/python2.7/site-packages/django/ -name '*.py' | \ + xargs sed -i "s|#!/usr/bin/env python$|#!/usr/bin/env python2|" + + install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE +} diff --git a/libre/django13/diff-django_branches_releases_1.3.X-from-16768-to-17460.diff b/libre/django13/diff-django_branches_releases_1.3.X-from-16768-to-17460.diff new file mode 100644 index 000000000..c6819c1ab --- /dev/null +++ b/libre/django13/diff-django_branches_releases_1.3.X-from-16768-to-17460.diff @@ -0,0 +1,1573 @@ +diff --git a/README b/README +index c7d225c..47bfd33 100644 +--- a/README ++++ b/README +@@ -28,7 +28,7 @@ http://code.djangoproject.com/newticket + To get more help: + + * Join the #django channel on irc.freenode.net. Lots of helpful people +- hang out there. Read the archives at http://botland.oebfare.com/logger/django/. ++ hang out there. Read the archives at http://django-irc-logs.com/. + + * Join the django-users mailing list, or read the archives, at + http://groups.google.com/group/django-users. +diff --git a/django/contrib/admin/media/css/forms.css b/django/contrib/admin/media/css/forms.css +index 1cedf24..35d0ed7 100644 +--- a/django/contrib/admin/media/css/forms.css ++++ b/django/contrib/admin/media/css/forms.css +@@ -352,9 +352,3 @@ fieldset.monospace textarea { + .empty-form { + display: none; + } +- +-/* IE7 specific bug fixes */ +- +-.submit-row input { +- float: right; +-} +\ No newline at end of file +diff --git a/django/contrib/gis/db/backends/spatialite/compiler.py b/django/contrib/gis/db/backends/spatialite/compiler.py +deleted file mode 100644 +index 3f81ae6..0000000 +--- a/django/contrib/gis/db/backends/spatialite/compiler.py ++++ /dev/null +@@ -1,32 +0,0 @@ +-from django.db.backends.util import typecast_timestamp +-from django.db.models.sql import compiler +-from django.db.models.sql.constants import MULTI +-from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler +- +-SQLCompiler = compiler.SQLCompiler +- +-class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler): +- pass +- +-class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler): +- pass +- +-class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler): +- pass +- +-class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler): +- pass +- +-class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler): +- pass +- +-class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- """ +- This is overridden for GeoDjango to properly cast date columns, see #16757. +- """ +- def results_iter(self): +- offset = len(self.query.extra_select) +- for rows in self.execute_sql(MULTI): +- for row in rows: +- date = typecast_timestamp(str(row[offset])) +- yield date +diff --git a/django/contrib/gis/db/backends/spatialite/creation.py b/django/contrib/gis/db/backends/spatialite/creation.py +index c107d96..ee5f9db 100644 +--- a/django/contrib/gis/db/backends/spatialite/creation.py ++++ b/django/contrib/gis/db/backends/spatialite/creation.py +@@ -56,14 +56,6 @@ class SpatiaLiteCreation(DatabaseCreation): + interactive=False, + database=self.connection.alias) + +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) +- + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache + for cache_alias in settings.CACHES: +diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py +index 1dc612c..e6f8409 100644 +--- a/django/contrib/gis/db/backends/spatialite/operations.py ++++ b/django/contrib/gis/db/backends/spatialite/operations.py +@@ -48,7 +48,7 @@ def get_dist_ops(operator): + return (SpatiaLiteDistance(operator),) + + class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations): +- compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler' ++ compiler_module = 'django.contrib.gis.db.models.sql.compiler' + name = 'spatialite' + spatialite = True + version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)') +diff --git a/django/contrib/gis/db/models/sql/compiler.py b/django/contrib/gis/db/models/sql/compiler.py +index 782ce78..405a000 100644 +--- a/django/contrib/gis/db/models/sql/compiler.py ++++ b/django/contrib/gis/db/models/sql/compiler.py +@@ -1,7 +1,7 @@ + from itertools import izip +-from django.db.backends.util import truncate_name ++from django.db.backends.util import truncate_name, typecast_timestamp + from django.db.models.sql import compiler +-from django.db.models.sql.constants import TABLE_NAME ++from django.db.models.sql.constants import TABLE_NAME, MULTI + from django.db.models.sql.query import get_proxied_model + + SQLCompiler = compiler.SQLCompiler +@@ -194,7 +194,7 @@ class GeoSQLCompiler(compiler.SQLCompiler): + # We resolve the rest of the columns if we're on Oracle or if + # the `geo_values` attribute is defined. + for value, field in map(None, row[index_start:], fields): +- values.append(self.query.convert_values(value, field, connection=self.connection)) ++ values.append(self.query.convert_values(value, field, self.connection)) + else: + values.extend(row[index_start:]) + return tuple(values) +@@ -275,4 +275,24 @@ class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler): + pass + + class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- pass ++ """ ++ This is overridden for GeoDjango to properly cast date columns, since ++ `GeoQuery.resolve_columns` is used for spatial values. ++ See #14648, #16757. ++ """ ++ def results_iter(self): ++ if self.connection.ops.oracle: ++ from django.db.models.fields import DateTimeField ++ fields = [DateTimeField()] ++ else: ++ needs_string_cast = self.connection.features.needs_datetime_string_cast ++ ++ offset = len(self.query.extra_select) ++ for rows in self.execute_sql(MULTI): ++ for row in rows: ++ date = row[offset] ++ if self.connection.ops.oracle: ++ date = self.resolve_columns(row, fields)[offset] ++ elif needs_string_cast: ++ date = typecast_timestamp(str(date)) ++ yield date +diff --git a/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz b/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz +index 68bf54c..8937637 100644 +Binary files a/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz and b/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz differ +diff --git a/django/contrib/gis/tests/relatedapp/models.py b/django/contrib/gis/tests/relatedapp/models.py +index 2e9a62b..aec4e15 100644 +--- a/django/contrib/gis/tests/relatedapp/models.py ++++ b/django/contrib/gis/tests/relatedapp/models.py +@@ -36,6 +36,7 @@ class Parcel(models.Model): + # These use the GeoManager but do not have any geographic fields. + class Author(models.Model): + name = models.CharField(max_length=100) ++ dob = models.DateField() + objects = models.GeoManager() + + class Article(models.Model): +diff --git a/django/contrib/gis/tests/relatedapp/tests.py b/django/contrib/gis/tests/relatedapp/tests.py +index 250783b..1a6197c 100644 +--- a/django/contrib/gis/tests/relatedapp/tests.py ++++ b/django/contrib/gis/tests/relatedapp/tests.py +@@ -1,3 +1,4 @@ ++from datetime import date + from django.test import TestCase + + from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint +@@ -281,4 +282,11 @@ class RelatedGeoModelTest(TestCase): + # evaluated as list generation swallows TypeError in CPython. + sql = str(qs.query) + ++ def test16_annotated_date_queryset(self): ++ "Ensure annotated date querysets work if spatial backend is used. See #14648." ++ birth_years = [dt.year for dt in ++ list(Author.objects.annotate(num_books=Count('books')).dates('dob', 'year'))] ++ birth_years.sort() ++ self.assertEqual([1950, 1974], birth_years) ++ + # TODO: Related tests for KML, GML, and distance lookups. +diff --git a/django/contrib/sites/management.py b/django/contrib/sites/management.py +index 1987274..9bf5a14 100644 +--- a/django/contrib/sites/management.py ++++ b/django/contrib/sites/management.py +@@ -3,15 +3,34 @@ Creates the default Site object. + """ + + from django.db.models import signals ++from django.db import connections ++from django.db import router + from django.contrib.sites.models import Site + from django.contrib.sites import models as site_app ++from django.core.management.color import no_style + + def create_default_site(app, created_models, verbosity, db, **kwargs): +- if Site in created_models: ++ # Only create the default sites in databases where Django created the table ++ if Site in created_models and router.allow_syncdb(db, Site) : ++ # The default settings set SITE_ID = 1, and some tests in Django's test ++ # suite rely on this value. However, if database sequences are reused ++ # (e.g. in the test suite after flush/syncdb), it isn't guaranteed that ++ # the next id will be 1, so we coerce it. See #15573 and #16353. This ++ # can also crop up outside of tests - see #15346. + if verbosity >= 2: + print "Creating example.com Site object" +- s = Site(domain="example.com", name="example.com") +- s.save(using=db) ++ Site(pk=1, domain="example.com", name="example.com").save(using=db) ++ ++ # We set an explicit pk instead of relying on auto-incrementation, ++ # so we need to reset the database sequence. ++ sequence_sql = connections[db].ops.sequence_reset_sql(no_style(), [Site]) ++ if sequence_sql: ++ if verbosity >= 2: ++ print "Resetting sequence" ++ cursor = connections[db].cursor() ++ for command in sequence_sql: ++ cursor.execute(command) ++ + Site.objects.clear_cache() + + signals.post_syncdb.connect(create_default_site, sender=site_app) +diff --git a/django/contrib/sites/tests.py b/django/contrib/sites/tests.py +index 17ab1f2..828badb 100644 +--- a/django/contrib/sites/tests.py ++++ b/django/contrib/sites/tests.py +@@ -15,6 +15,12 @@ class SitesFrameworkTests(TestCase): + def tearDown(self): + Site._meta.installed = self.old_Site_meta_installed + ++ def test_save_another(self): ++ # Regression for #17415 ++ # On some backends the sequence needs reset after save with explicit ID. ++ # Test that there is no sequence collisions by saving another site. ++ Site(domain="example2.com", name="example2.com").save() ++ + def test_site_manager(self): + # Make sure that get_current() does not return a deleted Site object. + s = Site.objects.get_current() +diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py +index e4ce462..039ebb8 100644 +--- a/django/core/management/commands/shell.py ++++ b/django/core/management/commands/shell.py +@@ -13,9 +13,8 @@ class Command(NoArgsCommand): + + def ipython(self): + try: +- from IPython.frontend.terminal.embed import TerminalInteractiveShell +- shell = TerminalInteractiveShell() +- shell.mainloop() ++ from IPython import embed ++ embed() + except ImportError: + # IPython < 0.11 + # Explicitly pass an empty list as arguments, because otherwise +diff --git a/django/core/validators.py b/django/core/validators.py +index a93c6ac..9dcc2bc 100644 +--- a/django/core/validators.py ++++ b/django/core/validators.py +@@ -147,7 +147,8 @@ class EmailValidator(RegexValidator): + + email_re = re.compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom +- r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string ++ # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 ++ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' + r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain + validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid') + +diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py +index 57e3f77..ef594b7 100644 +--- a/django/db/backends/creation.py ++++ b/django/db/backends/creation.py +@@ -374,15 +374,6 @@ class BaseDatabaseCreation(object): + verbosity=max(verbosity - 1, 0), + interactive=False, + database=self.connection.alias) +- +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- if 'django.contrib.sites' in settings.INSTALLED_APPS: +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) + + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache +diff --git a/django/http/__init__.py b/django/http/__init__.py +index 68ac45d..07e5a46 100644 +--- a/django/http/__init__.py ++++ b/django/http/__init__.py +@@ -92,7 +92,7 @@ else: + if not _cookie_allows_colon_in_names: + def load(self, rawdata, ignore_parse_errors=False): + if ignore_parse_errors: +- self.bad_cookies = [] ++ self.bad_cookies = set() + self._BaseCookie__set = self._loose_set + super(SimpleCookie, self).load(rawdata) + if ignore_parse_errors: +@@ -106,8 +106,8 @@ else: + try: + self._strict_set(key, real_value, coded_value) + except Cookie.CookieError: +- self.bad_cookies.append(key) +- dict.__setitem__(self, key, None) ++ self.bad_cookies.add(key) ++ dict.__setitem__(self, key, Cookie.Morsel()) + + + class CompatCookie(SimpleCookie): +diff --git a/django/http/utils.py b/django/http/utils.py +index 5eea239..0180864 100644 +--- a/django/http/utils.py ++++ b/django/http/utils.py +@@ -76,7 +76,8 @@ def fix_IE_for_vary(request, response): + + # The first part of the Content-Type field will be the MIME type, + # everything after ';', such as character-set, can be ignored. +- if response['Content-Type'].split(';')[0] not in safe_mime_types: ++ mime_type = response.get('Content-Type', '').partition(';')[0] ++ if mime_type not in safe_mime_types: + try: + del response['Vary'] + except KeyError: +diff --git a/docs/howto/deployment/modpython.txt b/docs/howto/deployment/modpython.txt +index f5030e9..693f942 100644 +--- a/docs/howto/deployment/modpython.txt ++++ b/docs/howto/deployment/modpython.txt +@@ -293,11 +293,14 @@ of the admin app, but this is not the case when you use any other server + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +diff --git a/docs/howto/deployment/modwsgi.txt b/docs/howto/deployment/modwsgi.txt +index de3a5b6..fdf9d27 100644 +--- a/docs/howto/deployment/modwsgi.txt ++++ b/docs/howto/deployment/modwsgi.txt +@@ -127,11 +127,14 @@ of the admin app, but this is not the case when you use any other server + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +diff --git a/docs/index.txt b/docs/index.txt +index 0cf066e..20a7cec 100644 +--- a/docs/index.txt ++++ b/docs/index.txt +@@ -28,7 +28,7 @@ Having trouble? We'd like to help! + .. _archives of the django-users mailing list: http://groups.google.com/group/django-users/ + .. _post a question: http://groups.google.com/group/django-users/ + .. _#django IRC channel: irc://irc.freenode.net/django +-.. _IRC logs: http://botland.oebfare.com/logger/django/ ++.. _IRC logs: http://django-irc-logs.com/ + .. _ticket tracker: http://code.djangoproject.com/ + + First steps +diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt +index 3f0f998..ca29d15 100644 +--- a/docs/internals/deprecation.txt ++++ b/docs/internals/deprecation.txt +@@ -177,6 +177,12 @@ their deprecation, as per the :ref:`Django deprecation policy + required to end with a trailing slash to ensure there is a consistent + way to combine paths in templates. + ++ * Translations located under the so-called *project path* will be ++ ignored during the translation building process performed at runtime. ++ The :setting:`LOCALE_PATHS` setting can be used for the same task by ++ including the filesystem path to a ``locale`` directory containing ++ non-app-specific translations in its value. ++ + * 2.0 + * ``django.views.defaults.shortcut()``. This function has been moved + to ``django.contrib.contenttypes.views.shortcut()`` as part of the +diff --git a/docs/internals/release-process.txt b/docs/internals/release-process.txt +index 2a56f0b..799a59e 100644 +--- a/docs/internals/release-process.txt ++++ b/docs/internals/release-process.txt +@@ -99,6 +99,13 @@ varying levels: + * Security fixes will be applied to the current trunk and the previous two + minor releases. + ++* Documentation fixes will generally be more freely backported to the last ++ release branch (at the discretion of the committer), and don't need to meet ++ the "critical fixes only" bar as it's highly advantageous to have the docs ++ for the last release be up-to-date and correct, and the downside of ++ backporting (risk of introducing regressions) is much less of a concern ++ with doc fixes. ++ + As a concrete example, consider a moment in time halfway between the release of + Django 1.3 and 1.4. At this point in time: + +@@ -111,6 +118,9 @@ Django 1.3 and 1.4. At this point in time: + ``1.2.X`` branch. Security fixes will trigger the release of ``1.3.1``, + ``1.2.1``, etc. + ++* Documentation fixes will be applied to trunk, and if easily backported, to ++ the ``1.3.X`` branch. ++ + .. _release-process: + + Release process +diff --git a/docs/intro/index.txt b/docs/intro/index.txt +index bc61be7..19290a5 100644 +--- a/docs/intro/index.txt ++++ b/docs/intro/index.txt +@@ -31,6 +31,6 @@ place: read this material to quickly get up and running. + + .. _python: http://python.org/ + .. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers +- .. _dive into python: http://diveintopython.org/ ++ .. _dive into python: http://diveintopython.net/ + .. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20 + .. _books about Python: http://wiki.python.org/moin/PythonBooks +\ No newline at end of file +diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt +index 2f2e049..4dc1e5c 100644 +--- a/docs/intro/tutorial01.txt ++++ b/docs/intro/tutorial01.txt +@@ -59,7 +59,7 @@ This will create a ``mysite`` directory in your current directory. + can be run as a program. To do this, open Terminal.app and navigate (using + the ``cd`` command) to the directory where :doc:`django-admin.py + </ref/django-admin>` is installed, then run the command +- ``chmod +x django-admin.py``. ++ ``sudo chmod +x django-admin.py``. + + .. note:: + +@@ -692,10 +692,9 @@ Save these changes and start a new Python interactive shell by running + + For more information on model relations, see :doc:`Accessing related objects + </ref/models/relations>`. For more on how to use double underscores to perform +-field lookups via the API, see `Field lookups`__. For full details on the +-database API, see our :doc:`Database API reference </topics/db/queries>`. +- +-__ http://docs.djangoproject.com/en/1.2/topics/db/queries/#field-lookups ++field lookups via the API, see :ref:`Field lookups <field-lookups-intro>`. For ++full details on the database API, see our :doc:`Database API reference ++</topics/db/queries>`. + + When you're comfortable with the API, read :doc:`part 2 of this tutorial + </intro/tutorial02>` to get Django's automatic admin working. +diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt +index 4bd31fb..1e837e6 100644 +--- a/docs/intro/tutorial02.txt ++++ b/docs/intro/tutorial02.txt +@@ -40,22 +40,22 @@ activate the admin site for your installation, do these three things: + + .. parsed-literal:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + # Uncomment the next two lines to enable the admin: + **from django.contrib import admin** + **admin.autodiscover()** + + urlpatterns = patterns('', +- # Example: +- # (r'^mysite/', include('mysite.foo.urls')), ++ # Examples: ++ # url(r'^$', 'mysite.views.home', name='home'), ++ # url(r'^mysite/', include('mysite.foo.urls')), + +- # Uncomment the admin/doc line below and add 'django.contrib.admindocs' +- # to INSTALLED_APPS to enable admin documentation: +- # (r'^admin/doc/', include('django.contrib.admindocs.urls')), ++ # Uncomment the admin/doc line below to enable admin documentation: ++ # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: +- **(r'^admin/', include(admin.site.urls)),** ++ **url(r'^admin/', include(admin.site.urls)),** + ) + + (The bold lines are the ones that needed to be uncommented.) +diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt +index 41a62a7..566ba55 100644 +--- a/docs/intro/tutorial03.txt ++++ b/docs/intro/tutorial03.txt +@@ -78,17 +78,17 @@ point at that file:: + + Time for an example. Edit ``mysite/urls.py`` so it looks like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^admin/', include(admin.site.urls)), + ) + + This is worth a review. When somebody requests a page from your Web site -- say, +@@ -112,7 +112,7 @@ what you can do with them. And there's no need to add URL cruft such as ``.php`` + -- unless you have a sick sense of humor, in which case you can do something + like this:: + +- (r'^polls/latest\.php$', 'polls.views.index'), ++ url(r'^polls/latest\.php$', 'polls.views.index'), + + But, don't do that. It's silly. + +@@ -357,22 +357,23 @@ the list is empty. + Write a 404 (page not found) view + ================================= + +-When you raise :exc:`~django.http.Http404` from within a view, Django will load +-a special view devoted to handling 404 errors. It finds it by looking for the +-variable ``handler404``, which is a string in Python dotted syntax -- the same +-format the normal URLconf callbacks use. A 404 view itself has nothing special: +-It's just a normal view. +- +-You normally won't have to bother with writing 404 views. By default, URLconfs +-have the following line up top:: +- +- from django.conf.urls.defaults import * ++When you raise :exc:`~django.http.Http404` from within a view, Django ++will load a special view devoted to handling 404 errors. It finds it ++by looking for the variable ``handler404`` in your root URLconf (and ++only in your root URLconf; setting ``handler404`` anywhere else will ++have no effect), which is a string in Python dotted syntax -- the same ++format the normal URLconf callbacks use. A 404 view itself has nothing ++special: It's just a normal view. + +-That takes care of setting ``handler404`` in the current module. As you can see +-in ``django/conf/urls/defaults.py``, ``handler404`` is set to +-:func:`django.views.defaults.page_not_found` by default. ++You normally won't have to bother with writing 404 views. If you don't set ++``handler404``, the built-in view :func:`django.views.defaults.page_not_found` ++is used by default. In this case, you still have one obligation: To create a ++``404.html`` template in the root of your template directory. The default 404 ++view will use that template for all 404 errors. If :setting:`DEBUG` is set to ++``False`` (in your settings module) and if you didn't create a ``404.html`` ++file, an ``Http500`` is raised instead. So remember to create a ``404.html``. + +-Four more things to note about 404 views: ++A couple more things to note about 404 views: + + * If :setting:`DEBUG` is set to ``True`` (in your settings module) then your + 404 view will never be used (and thus the ``404.html`` template will never +@@ -381,21 +382,12 @@ Four more things to note about 404 views: + * The 404 view is also called if Django doesn't find a match after checking + every regular expression in the URLconf. + +- * If you don't define your own 404 view -- and simply use the default, which +- is recommended -- you still have one obligation: To create a ``404.html`` +- template in the root of your template directory. The default 404 view will +- use that template for all 404 errors. +- +- * If :setting:`DEBUG` is set to ``False`` (in your settings module) and if +- you didn't create a ``404.html`` file, an ``Http500`` is raised instead. +- So remember to create a ``404.html``. +- + Write a 500 (server error) view + =============================== + +-Similarly, URLconfs may define a ``handler500``, which points to a view to call +-in case of server errors. Server errors happen when you have runtime errors in +-view code. ++Similarly, your root URLconf may define a ``handler500``, which points ++to a view to call in case of server errors. Server errors happen when ++you have runtime errors in view code. + + Use the template system + ======================= +@@ -432,10 +424,10 @@ Take some time to play around with the views and template system. As you edit + the URLconf, you may notice there's a fair bit of redundancy in it:: + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + Namely, ``polls.views`` is in every callback. +@@ -445,10 +437,10 @@ common prefixes. You can factor out the common prefixes and add them as the + first argument to :func:`~django.conf.urls.defaults.patterns`, like so:: + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + This is functionally identical to the previous formatting. It's just a bit +@@ -459,20 +451,20 @@ callback in your URLconf, you can concatenate multiple + :func:`~django.conf.urls.defaults.patterns`. Your full ``mysite/urls.py`` might + now look like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + urlpatterns += patterns('', +- (r'^admin/', include(admin.site.urls)), ++ url(r'^admin/', include(admin.site.urls)), + ) + + Decoupling the URLconfs +@@ -502,8 +494,8 @@ Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/', include('polls.urls')), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/', include('polls.urls')), ++ url(r'^admin/', include(admin.site.urls)), + ) + + :func:`~django.conf.urls.defaults.include` simply references another URLconf. +@@ -526,13 +518,13 @@ URLconf by removing the leading "polls/" from each line, and removing the + lines registering the admin site. Your ``polls/urls.py`` file should now look like + this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + The idea behind :func:`~django.conf.urls.defaults.include` and URLconf +diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt +index ded5cb2..4c2f2d4 100644 +--- a/docs/intro/tutorial04.txt ++++ b/docs/intro/tutorial04.txt +@@ -218,13 +218,13 @@ Read on for details. + First, open the ``polls/urls.py`` URLconf. It looks like this, according to the + tutorial so far:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + Change it like so:: +@@ -234,12 +234,12 @@ Change it like so:: + from polls.models import Poll + + urlpatterns = patterns('', +- (r'^$', ++ url(r'^$', + ListView.as_view( + queryset=Poll.objects.order_by('-pub_date')[:5], + context_object_name='latest_poll_list', + template_name='polls/index.html')), +- (r'^(?P<pk>\d+)/$', ++ url(r'^(?P<pk>\d+)/$', + DetailView.as_view( + model=Poll, + template_name='polls/detail.html')), +@@ -248,7 +248,7 @@ Change it like so:: + model=Poll, + template_name='polls/results.html'), + name='poll_results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + We're using two generic views here: +diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt +index beff94e..7394c3a 100644 +--- a/docs/ref/contrib/admin/index.txt ++++ b/docs/ref/contrib/admin/index.txt +@@ -19,8 +19,10 @@ There are six steps in activating the Django admin site: + 1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS` + setting. + +- 2. Admin has two dependencies - :mod:`django.contrib.auth` and +- :mod:`django.contrib.contenttypes`. If these applications are not ++ 2. The admin has four dependencies - :mod:`django.contrib.auth`, ++ :mod:`django.contrib.contenttypes`, ++ :mod:`django.contrib.messages` and ++ :mod:`django.contrib.sessions`. If these applications are not + in your :setting:`INSTALLED_APPS` list, add them. + + 3. Determine which of your application's models should be editable in the +@@ -542,7 +544,7 @@ subclass:: + Fields in ``list_filter`` can also span relations using the ``__`` lookup:: + + class UserAdminWithLookup(UserAdmin): +- list_filter = ('groups__name') ++ list_filter = ('groups__name',) + + .. attribute:: ModelAdmin.list_per_page + +diff --git a/docs/ref/contrib/gis/geoip.txt b/docs/ref/contrib/gis/geoip.txt +index 6503be7..f5c45e1 100644 +--- a/docs/ref/contrib/gis/geoip.txt ++++ b/docs/ref/contrib/gis/geoip.txt +@@ -144,7 +144,7 @@ parameters. + Returns a dictionary of city information for the given query. Some + of the values in the dictionary may be undefined (``None``). + +-.. method:: GeoIPcountry(query) ++.. method:: GeoIP.country(query) + + Returns a dictionary with the country code and country for the given + query. +diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt +index ca3212d..ee7e01c 100644 +--- a/docs/ref/contrib/messages.txt ++++ b/docs/ref/contrib/messages.txt +@@ -210,6 +210,10 @@ If you're using the context processor, your template should be rendered with a + ``RequestContext``. Otherwise, ensure ``messages`` is available to + the template context. + ++Even if you know there is only just one message, you should still iterate over ++the ``messages`` sequence, because otherwise the message storage will not be cleared ++for the next request. ++ + Creating custom message levels + ------------------------------ + +diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt +index 89bc43f..58b86ea 100644 +--- a/docs/ref/django-admin.txt ++++ b/docs/ref/django-admin.txt +@@ -1156,7 +1156,7 @@ variable. + Note that this option is unnecessary in ``manage.py``, because it takes care of + setting the Python path for you. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + .. django-admin-option:: --settings + +diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt +index 3728a09..52c0869 100644 +--- a/docs/ref/models/instances.txt ++++ b/docs/ref/models/instances.txt +@@ -470,7 +470,7 @@ the URL. For example, if your URLconf contained a line such as:: + + Similarly, if you had a URLconf entry that looked like:: + +- (r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view) ++ (r'/archive/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', archive_view) + + ...you could reference this using ``permalink()`` as follows:: + +@@ -478,8 +478,8 @@ Similarly, if you had a URLconf entry that looked like:: + def get_absolute_url(self): + return ('archive_view', (), { + 'year': self.created.year, +- 'month': self.created.month, +- 'day': self.created.day}) ++ 'month': self.created.strftime('%m'), ++ 'day': self.created.strftime('%d')}) + + Notice that we specify an empty sequence for the second parameter in this case, + because we only want to pass keyword parameters, not positional ones. +diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt +index 4530439..c1beab0 100644 +--- a/docs/ref/models/options.txt ++++ b/docs/ref/models/options.txt +@@ -166,6 +166,13 @@ Django quotes column and table names behind the scenes. + >>> answer.get_previous_in_order() + <Answer: 1> + ++.. admonition:: Changing order_with_respect_to ++ ++ ``order_with_respect_to`` adds an additional field/database column ++ named ``_order``, so be sure to handle that as you would any other ++ change to your models if you add or change ``order_with_respect_to`` ++ after your initial :djadmin:`syncdb`. ++ + ``ordering`` + ------------ + +@@ -238,6 +245,12 @@ Django quotes column and table names behind the scenes. + + unique_together = ("driver", "restaurant") + ++ A :class:`~django.db.models.ManyToManyField` cannot be included in ++ unique_together (it's not even clear what that would mean). If you ++ need to validate uniqueness related to a ++ :class:`~django.db.models.ManyToManyField`, look at signals or ++ using an explicit :attr:`through <ManyToManyField.through>` model. ++ + ``verbose_name`` + ---------------- + +diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt +index e83142e..ad25dce 100644 +--- a/docs/ref/signals.txt ++++ b/docs/ref/signals.txt +@@ -352,12 +352,16 @@ post_syncdb + .. data:: django.db.models.signals.post_syncdb + :module: + +-Sent by :djadmin:`syncdb` after it installs an application. ++Sent by :djadmin:`syncdb` command after it installs an application, and ++:djadmin:`flush` command. + + Any handlers that listen to this signal need to be written in a particular + place: a ``management`` module in one of your :setting:`INSTALLED_APPS`. If + handlers are registered anywhere else they may not be loaded by +-:djadmin:`syncdb`. ++:djadmin:`syncdb`. It is important that handlers of this signal perform ++idempotent changes (e.g. no database alterations) as this may cause the ++:djadmin:`flush` management command to fail if it also ran during the ++:djadmin:`syncdb` command. + + Arguments sent with this signal: + +diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt +index 7d24c1d..6c7057a 100644 +--- a/docs/ref/templates/builtins.txt ++++ b/docs/ref/templates/builtins.txt +@@ -1868,7 +1868,7 @@ slice + Returns a slice of the list. + + Uses the same syntax as Python's list slicing. See +-http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice ++http://diveintopython.net/native_data_types/lists.html#odbchelper.list.slice + for an introduction. + + Example:: +diff --git a/docs/releases/0.95.txt b/docs/releases/0.95.txt +index 7409bff..3632c31 100644 +--- a/docs/releases/0.95.txt ++++ b/docs/releases/0.95.txt +@@ -92,15 +92,15 @@ changes is described in the `Removing The Magic`_ wiki page. There is also an + easy checklist_ for reference when undertaking the porting operation. + + .. _Removing The Magic: http://code.djangoproject.com/wiki/RemovingTheMagic +-.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet1 ++.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet + + Problem reports and getting help + ================================ + +-Need help resolving a problem with Django? The documentation in the distribution +-is also available online_ at the `Django Web site`_. The :doc:`FAQ </faq/index>` +-document is especially recommended, as it contains a number of issues that come +-up time and again. ++Need help resolving a problem with Django? The documentation in the ++distribution is also available :doc:`online </index>` at the `Django Web ++site`_. The :doc:`FAQ </faq/index>` document is especially recommended, as it ++contains a number of issues that come up time and again. + + For more personalized help, the `django-users`_ mailing list is a very active + list, with more than 2,000 subscribers who can help you solve any sort of +@@ -113,7 +113,6 @@ there's a #django channel on irc.freenode.net that is regularly populated by + Django users and developers from around the world. Friendly people are usually + available at any hour of the day -- to help, or just to chat. + +-.. _online: http://www.djangoproject.com/documentation/0.95/ + .. _Django Web site: http://www.djangoproject.com/ + .. _django-users: http://groups.google.com/group/django-users + +diff --git a/docs/releases/0.96.txt b/docs/releases/0.96.txt +index 1224360..8874ccb 100644 +--- a/docs/releases/0.96.txt ++++ b/docs/releases/0.96.txt +@@ -50,12 +50,10 @@ aside from any necessary security fixes, it will not be actively + maintained, and it will be removed in a future release of Django. + + Also, note that some features, like the new :setting:`DATABASE_OPTIONS` +-setting (see the `databases documentation`_ for details), are only +-available on the "mysql" backend, and will not be made available for ++setting (see the :doc:`databases documentation </ref/databases>` for details), ++are only available on the "mysql" backend, and will not be made available for + "mysql_old". + +-.. _databases documentation: http://www.djangoproject.com/documentation/0.96/databases/ +- + Database constraint names changed + --------------------------------- + +@@ -164,10 +162,8 @@ Although the ``newforms`` library will continue to evolve, it's ready for use + for most common cases. We recommend that anyone new to form handling skip the + old forms system and start with the new. + +-For more information about ``django.newforms``, read the `newforms +-documentation`_. +- +-.. _newforms documentation: http://www.djangoproject.com/documentation/0.96/newforms/ ++For more information about ``django.newforms``, read the :doc:`newforms ++documentation </topics/forms/index>`. + + URLconf improvements + -------------------- +@@ -216,19 +212,15 @@ The test framework + ------------------ + + Django now includes a test framework so you can start transmuting fear into +-boredom (with apologies to Kent Beck). You can write tests based on doctest_ +-or unittest_ and test your views with a simple test client. ++boredom (with apologies to Kent Beck). You can write tests based on ++:mod:`doctest` or :mod:`unittest` and test your views with a simple test client. + + There is also new support for "fixtures" -- initial data, stored in any of the +-supported `serialization formats`_, that will be loaded into your database at the +-start of your tests. This makes testing with real data much easier. +- +-See `the testing documentation`_ for the full details. ++supported :doc:`serialization formats </topics/serialization>`, that will be ++loaded into your database at the start of your tests. This makes testing with ++real data much easier. + +-.. _doctest: http://docs.python.org/library/doctest.html +-.. _unittest: http://docs.python.org/library/unittest.html +-.. _the testing documentation: http://www.djangoproject.com/documentation/0.96/testing/ +-.. _serialization formats: http://www.djangoproject.com/documentation/0.96/serialization/ ++See :doc:`the testing documentation </topics/testing>` for the full details. + + Improvements to the admin interface + ----------------------------------- +diff --git a/docs/releases/1.0.1.txt b/docs/releases/1.0.1.txt +index 780dc53..3550e7c 100644 +--- a/docs/releases/1.0.1.txt ++++ b/docs/releases/1.0.1.txt +@@ -6,10 +6,10 @@ Welcome to Django 1.0.1! + + This is the first "bugfix" release in the Django 1.0 series, improving + the stability and performance of the Django 1.0 codebase. As such, +-Django 1.0.1 contains no new features (and, pursuant to `our +-compatibility policy`_, maintains backwards compatibility with Django +-1.0), but does contain a number of fixes and other +-improvements. Django 1.0.1 is a recommended upgrade for any ++Django 1.0.1 contains no new features (and, pursuant to :doc:`our ++compatibility policy </misc/api-stability/>`, maintains backwards ++compatibility with Django 1.0), but does contain a number of fixes ++and other improvements. Django 1.0.1 is a recommended upgrade for any + development or deployment currently using or targeting Django 1.0. + + +@@ -46,8 +46,9 @@ highlights: + + * A fix to the application of autoescaping for literal strings passed + to the ``join`` template filter. Previously, literal strings passed +- to ``join`` were automatically escaped, contrary to `the documented +- behavior for autoescaping and literal strings`_. Literal strings ++ to ``join`` were automatically escaped, contrary to :ref:`the ++ documented behavior for autoescaping and literal strings ++ <string-literals-and-automatic-escaping>`. Literal strings + passed to ``join`` are no longer automatically escaped, meaning you + must now manually escape them; this is an incompatibility if you + were relying on this bug, but not if you were relying on escaping +@@ -60,6 +61,4 @@ highlights: + documentation, including both corrections to existing documents and + expanded and new documentation. + +-.. _our compatibility policy: http://docs.djangoproject.com/en/dev/misc/api-stability/ + .. _the Subversion log of the 1.0.X branch: http://code.djangoproject.com/log/django/branches/releases/1.0.X +-.. _the documented behavior for autoescaping and literal strings: http://docs.djangoproject.com/en/dev/topics/templates/#string-literals-and-automatic-escaping +diff --git a/docs/releases/1.2.6.txt b/docs/releases/1.2.6.txt +new file mode 100644 +index 0000000..cfd1d9c +--- /dev/null ++++ b/docs/releases/1.2.6.txt +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.6 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.2.6! ++ ++This is the sixth bugfix/security release in the Django 1.2 series, fixing ++several security issues present in Django 1.2.5. Django 1.2.6 is a ++recommended upgrade for all users of any Django release in the 1.2.X series. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +diff --git a/docs/releases/1.2.7.txt b/docs/releases/1.2.7.txt +new file mode 100644 +index 0000000..c0cf698 +--- /dev/null ++++ b/docs/releases/1.2.7.txt +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.7 release notes ++========================== ++ ++*September 10, 2011* ++ ++Welcome to Django 1.2.7! ++ ++This is the seventh bugfix/security release in the Django 1.2 series. It ++replaces Django 1.2.6 due to problems with the 1.2.6 release tarball. ++Django 1.2.7 is a recommended upgrade for all users of any Django release in ++the 1.2.X series. ++ ++For more information, see the `release advisory`_. ++ ++.. _release advisory: https://www.djangoproject.com/weblog/2011/sep/10/127/ +diff --git a/docs/releases/1.3.1.txt b/docs/releases/1.3.1.txt +new file mode 100644 +index 0000000..4c28916 +--- /dev/null ++++ b/docs/releases/1.3.1.txt +@@ -0,0 +1,16 @@ ++========================== ++Django 1.3.1 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.3.1! ++ ++This is the first security release in the Django 1.3 series, fixing several ++security issues in Django 1.3. Django 1.3.1 is a recommended upgrade for ++all users of Django 1.3. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +diff --git a/docs/releases/index.txt b/docs/releases/index.txt +index 8d23c28..40fe5b0 100644 +--- a/docs/releases/index.txt ++++ b/docs/releases/index.txt +@@ -19,6 +19,7 @@ Final releases + .. toctree:: + :maxdepth: 1 + ++ 1.3.1 + 1.3 + + 1.2 release +@@ -26,6 +27,8 @@ Final releases + .. toctree:: + :maxdepth: 1 + ++ 1.2.7 ++ 1.2.6 + 1.2.5 + 1.2.4 + 1.2.2 +diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt +index 635f18f..5a2608a 100644 +--- a/docs/topics/auth.txt ++++ b/docs/topics/auth.txt +@@ -1251,16 +1251,19 @@ can or cannot do with Task instances, specific to your application:: + ... + class Meta: + permissions = ( +- ("can_view", "Can see available tasks"), +- ("can_change_status", "Can change the status of tasks"), +- ("can_close", "Can remove a task by setting its status as closed"), ++ ("view_task", "Can see available tasks"), ++ ("change_task_status", "Can change the status of tasks"), ++ ("close_task", "Can remove a task by setting its status as closed"), + ) + + The only thing this does is create those extra permissions when you run + :djadmin:`manage.py syncdb <syncdb>`. Your code is in charge of checking the + value of these permissions when an user is trying to access the functionality + provided by the application (viewing tasks, changing the status of tasks, +-closing tasks.) ++closing tasks.) Continuing the above example, the following checks if a user may ++view tasks:: ++ ++ user.has_perm('app.view_task') + + API reference + ------------- +diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt +index 8ef4ea2..9b68353 100644 +--- a/docs/topics/cache.txt ++++ b/docs/topics/cache.txt +@@ -99,8 +99,9 @@ To use Memcached with Django: + on your chosen memcached binding) + + * Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values, +- where ``ip`` is the IP address of the Memcached daemon and +- ``port`` is the port on which Memcached is running. ++ where ``ip`` is the IP address of the Memcached daemon and ``port`` is the ++ port on which Memcached is running, or to a ``unix:path`` value, where ++ ``path`` is the path to a Memcached Unix socket file. + + In this example, Memcached is running on localhost (127.0.0.1) port 11211, using + the ``python-memcached`` binding:: +@@ -112,6 +113,16 @@ the ``python-memcached`` binding:: + } + } + ++In this example, Memcached is available through a local Unix socket file ++:file:`/tmp/memcached.sock` using the ``python-memcached`` binding:: ++ ++ CACHES = { ++ 'default': { ++ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', ++ 'LOCATION': 'unix:/tmp/memcached.sock', ++ } ++ } ++ + One excellent feature of Memcached is its ability to share cache over multiple + servers. This means you can run Memcached daemons on multiple machines, and the + program will treat the group of machines as a *single* cache, without the need +@@ -526,9 +537,10 @@ you may expect. But once a particular URL (e.g., ``/foo/23/``) has been + requested, subsequent requests to that URL will use the cache. + + ``cache_page`` can also take an optional keyword argument, ``cache``, +-which directs the decorator to use a specific cache alias when caching view +-results. By default, the ``default`` alias will be used, but you can specify +-any cache alias you want:: ++which directs the decorator to use a specific cache (from your ++:setting:`CACHES` setting) when caching view results. By default, the ++``default`` cache will be used, but you can specify any cache you ++want:: + + @cache_page(60 * 15, cache="special_cache") + def my_view(request): +diff --git a/docs/topics/class-based-views.txt b/docs/topics/class-based-views.txt +index 3831046..4da48ec 100644 +--- a/docs/topics/class-based-views.txt ++++ b/docs/topics/class-based-views.txt +@@ -380,7 +380,7 @@ Next, we'll write the ``PublisherBookListView`` view itself:: + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +@@ -396,7 +396,7 @@ use it in the template:: + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt +index 0e18205..af76344 100644 +--- a/docs/topics/db/models.txt ++++ b/docs/topics/db/models.txt +@@ -324,11 +324,10 @@ whatever you want. For example:: + should work; all are optional. + + For details on accessing backwards-related objects, see the +- `Following relationships backward example`_. +- ++ :ref:`Following relationships backward example <backwards-related-objects>`. ++ + For sample code, see the `Many-to-one relationship model tests`_. + +- .. _Following relationships backward example: http://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects + .. _Many-to-one relationship model tests: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/many_to_one + + Many-to-many relationships +diff --git a/docs/topics/db/sql.txt b/docs/topics/db/sql.txt +index fe71736..d9b8b1a 100644 +--- a/docs/topics/db/sql.txt ++++ b/docs/topics/db/sql.txt +@@ -236,6 +236,30 @@ alias:: + # Your code here... + transaction.commit_unless_managed(using='my_db_alias') + ++By default, the Python DB API will return results without their field ++names, which means you end up with a ``list`` of values, rather than a ++``dict``. At a small performance cost, you can return results as a ++``dict`` by using something like this:: ++ ++ def dictfetchall(cursor): ++ "Returns all rows from a cursor as a dict" ++ desc = cursor.description ++ return [ ++ dict(zip([col[0] for col in desc], row)) ++ for row in cursor.fetchall() ++ ] ++ ++Here is an example of the difference between the two:: ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> cursor.fetchall() ++ ((54360982L, None), (54360880L, None)) ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> dictfetchall(cursor) ++ [{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}] ++ ++ + .. _transactions-and-raw-sql: + + Transactions and raw SQL +diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt +index 07bc5e3..24e000e 100644 +--- a/docs/topics/forms/modelforms.txt ++++ b/docs/topics/forms/modelforms.txt +@@ -332,13 +332,17 @@ Since the Author model has only 3 fields, 'name', 'title', and + .. note:: + + If you specify ``fields`` or ``exclude`` when creating a form with +- ``ModelForm``, then the fields that are not in the resulting form will not +- be set by the form's ``save()`` method. Django will prevent any attempt to +- save an incomplete model, so if the model does not allow the missing fields +- to be empty, and does not provide a default value for the missing fields, +- any attempt to ``save()`` a ``ModelForm`` with missing fields will fail. +- To avoid this failure, you must instantiate your model with initial values +- for the missing, but required fields:: ++ ``ModelForm``, then the fields that are not in the resulting form ++ will not be set by the form's ``save()`` method. Also, if you ++ manually add the excluded fields back to the form, they will not ++ be initialized from the model instance. ++ ++ Django will prevent any attempt to save an incomplete model, so if ++ the model does not allow the missing fields to be empty, and does ++ not provide a default value for the missing fields, any attempt to ++ ``save()`` a ``ModelForm`` with missing fields will fail. To ++ avoid this failure, you must instantiate your model with initial ++ values for the missing, but required fields:: + + author = Author(title='Mr') + form = PartialAuthorForm(request.POST, instance=author) +@@ -633,6 +637,12 @@ database. If a given instance's data didn't change in the bound data, the + instance won't be saved to the database and won't be included in the return + value (``instances``, in the above example). + ++When fields are missing from the form (for example because they have ++been excluded), these fields will not be set by the ``save()`` ++method. You can find more information about this restriction, which ++also holds for regular ``ModelForms``, in `Using a subset of fields on ++the form`_. ++ + Pass ``commit=False`` to return the unsaved model instances:: + + # don't save to the database +diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt +index 1caa801..7a0e724 100644 +--- a/docs/topics/http/urls.txt ++++ b/docs/topics/http/urls.txt +@@ -54,6 +54,10 @@ algorithm the system follows to determine which Python code to execute: + :class:`~django.http.HttpRequest` as its first argument and any values + captured in the regex as remaining arguments. + ++ 5. If no regex matches, or if an exception is raised during any ++ point in this process, Django invokes an appropriate ++ error-handling view. See `Error handling`_ below. ++ + Example + ======= + +@@ -99,10 +103,10 @@ Example requests: + * ``/articles/2003`` would not match any of these patterns, because each + pattern requires that the URL end with a slash. + +- * ``/articles/2003/03/3/`` would match the final pattern. Django would call +- the function ``news.views.article_detail(request, '2003', '03', '3')``. ++ * ``/articles/2003/03/03/`` would match the final pattern. Django would call ++ the function ``news.views.article_detail(request, '2003', '03', '03')``. + +-.. _Dive Into Python's explanation: http://diveintopython.org/regular_expressions/street_addresses.html#re.matching.2.3 ++.. _Dive Into Python's explanation: http://diveintopython.net/regular_expressions/street_addresses.html#re.matching.2.3 + + Named groups + ============ +@@ -123,7 +127,7 @@ Here's the above example URLconf, rewritten to use named groups:: + (r'^articles/2003/$', 'news.views.special_case_2003'), + (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'), + (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'), +- (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'), ++ (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', 'news.views.article_detail'), + ) + + This accomplishes exactly the same thing as the previous example, with one +@@ -134,8 +138,8 @@ arguments rather than positional arguments. For example: + ``news.views.month_archive(request, year='2005', month='03')``, instead + of ``news.views.month_archive(request, '2005', '03')``. + +- * A request to ``/articles/2003/03/3/`` would call the function +- ``news.views.article_detail(request, year='2003', month='03', day='3')``. ++ * A request to ``/articles/2003/03/03/`` would call the function ++ ``news.views.article_detail(request, year='2003', month='03', day='03')``. + + In practice, this means your URLconfs are slightly more explicit and less prone + to argument-order bugs -- and you can reorder the arguments in your views' +@@ -246,6 +250,31 @@ The ``prefix`` parameter has the same meaning as the first argument to + ``patterns()`` and is only relevant when you're passing a string as the + ``view`` parameter. + ++include ++------- ++ ++.. function:: include(<module or pattern_list>) ++ ++A function that takes a full Python import path to another URLconf module that ++should be "included" in this place. ++ ++:func:`include` also accepts as an argument an iterable that returns URL ++patterns. ++ ++See `Including other URLconfs`_ below. ++ ++Error handling ++============== ++ ++When Django can't find a regex matching the requested URL, or when an ++exception is raised, Django will invoke an error-handling view. The ++views to use for these cases are specified by two variables which can ++be set in your root URLconf. Setting these variables in any other ++URLconf will have no effect. ++ ++See the documentation on :ref:`customizing error views ++<customizing-error-views>` for more details. ++ + handler404 + ---------- + +@@ -275,19 +304,6 @@ value should suffice. + .. versionchanged:: 1.2 + Previous versions of Django only accepted strings representing import paths. + +-include +-------- +- +-.. function:: include(<module or pattern_list>) +- +-A function that takes a full Python import path to another URLconf module that +-should be "included" in this place. +- +-:func:`include` also accepts as an argument an iterable that returns URL +-patterns. +- +-See `Including other URLconfs`_ below. +- + Notes on capturing text in URLs + =============================== + +@@ -420,8 +436,8 @@ directly the pattern list as returned by `patterns`_ instead. For example:: + from django.conf.urls.defaults import * + + extra_patterns = patterns('', +- url(r'reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), +- url(r'charge/$', 'credit.views.charge', name='credit-charge'), ++ url(r'^reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), ++ url(r'^charge/$', 'credit.views.charge', name='credit-charge'), + ) + + urlpatterns = patterns('', +diff --git a/docs/topics/http/views.txt b/docs/topics/http/views.txt +index 99359ab..83a52cb 100644 +--- a/docs/topics/http/views.txt ++++ b/docs/topics/http/views.txt +@@ -122,6 +122,8 @@ In order to use the ``Http404`` exception to its fullest, you should create a + template that is displayed when a 404 error is raised. This template should be + called ``404.html`` and located in the top level of your template tree. + ++.. _customizing-error-views: ++ + Customizing error views + ======================= + +diff --git a/docs/topics/i18n/internationalization.txt b/docs/topics/i18n/internationalization.txt +index 5d50fa7..a83299c 100644 +--- a/docs/topics/i18n/internationalization.txt ++++ b/docs/topics/i18n/internationalization.txt +@@ -477,7 +477,7 @@ for use within the translation block. Examples:: + + You can use multiple expressions inside a single ``blocktrans`` tag:: + +- {% blocktrans with book_t=book|title and author_t=author|title %} ++ {% blocktrans with book_t=book|title author_t=author|title %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + +diff --git a/docs/topics/settings.txt b/docs/topics/settings.txt +index 61ddf8c..bda51f2 100644 +--- a/docs/topics/settings.txt ++++ b/docs/topics/settings.txt +@@ -39,7 +39,7 @@ The value of ``DJANGO_SETTINGS_MODULE`` should be in Python path syntax, e.g. + ``mysite.settings``. Note that the settings module should be on the + Python `import search path`_. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + The django-admin.py utility + --------------------------- +diff --git a/docs/topics/templates.txt b/docs/topics/templates.txt +index 83269ae..fc2cd3f 100644 +--- a/docs/topics/templates.txt ++++ b/docs/topics/templates.txt +@@ -555,6 +555,8 @@ variable that needs escaping. When auto-escaping is on, there's no danger of + the ``escape`` filter *double-escaping* data -- the ``escape`` filter does not + affect auto-escaped variables. + ++.. _string-literals-and-automatic-escaping: ++ + String literals and automatic escaping + -------------------------------------- + +diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt +index 0a86f0d..8262b57 100644 +--- a/docs/topics/testing.txt ++++ b/docs/topics/testing.txt +@@ -1586,7 +1586,7 @@ skipUnlessDBFeature + Skip the decorated test if the named database feature is *not* + supported. + +-For example, the following test will not be executed if the database ++For example, the following test will only be executed if the database + supports transactions (e.g., it would run under PostgreSQL, but *not* + under MySQL with MyISAM tables):: + +diff --git a/tests/modeltests/validators/tests.py b/tests/modeltests/validators/tests.py +index e585262..4bd5827 100644 +--- a/tests/modeltests/validators/tests.py ++++ b/tests/modeltests/validators/tests.py +@@ -28,6 +28,9 @@ TEST_DATA = ( + (validate_email, 'abc', ValidationError), + (validate_email, 'a @x.cz', ValidationError), + (validate_email, 'something@@somewhere.com', ValidationError), ++ # Quoted-string format (CR not allowed) ++ (validate_email, '"\\\011"@here.com', None), ++ (validate_email, '"\\\012"@here.com', ValidationError), + + (validate_slug, 'slug-ok', None), + (validate_slug, 'longer-slug-still-ok', None), +diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py +index 2e2932f..6aabfe6 100644 +--- a/tests/regressiontests/httpwrappers/tests.py ++++ b/tests/regressiontests/httpwrappers/tests.py +@@ -281,3 +281,9 @@ class CookieTests(unittest.TestCase): + Test that a single non-standard cookie name doesn't affect all cookies. Ticket #13007. + """ + self.assertTrue('good_cookie' in parse_cookie('good_cookie=yes;bad:cookie=yes').keys()) ++ ++ def test_repeated_nonstandard_keys(self): ++ """ ++ Test that a repeated non-standard name doesn't affect all cookies. Ticket #15852 ++ """ ++ self.assertTrue('good_cookie' in parse_cookie('a,=b; a,=c; good_cookie=yes').keys()) +diff --git a/tests/regressiontests/utils/http.py b/tests/regressiontests/utils/http.py +index 83a4a7f..666d04f 100644 +--- a/tests/regressiontests/utils/http.py ++++ b/tests/regressiontests/utils/http.py +@@ -1,5 +1,7 @@ + from django.utils import http + from django.utils import unittest ++from django.http import HttpResponse, utils ++from django.test import RequestFactory + + class TestUtilsHttp(unittest.TestCase): + +@@ -21,3 +23,49 @@ class TestUtilsHttp(unittest.TestCase): + self.assertFalse(http.same_origin('http://foo.com', 'http://foo.com.evil.com')) + # Different port + self.assertFalse(http.same_origin('http://foo.com:8000', 'http://foo.com:8001')) ++ ++ def test_fix_IE_for_vary(self): ++ """ ++ Regression for #16632. ++ ++ `fix_IE_for_vary` shouldn't crash when there's no Content-Type header. ++ """ ++ ++ # functions to generate responses ++ def response_with_unsafe_content_type(): ++ r = HttpResponse(content_type="text/unsafe") ++ r['Vary'] = 'Cookie' ++ return r ++ ++ def no_content_response_with_unsafe_content_type(): ++ # 'Content-Type' always defaulted, so delete it ++ r = response_with_unsafe_content_type() ++ del r['Content-Type'] ++ return r ++ ++ # request with & without IE user agent ++ rf = RequestFactory() ++ request = rf.get('/') ++ ie_request = rf.get('/', HTTP_USER_AGENT='MSIE') ++ ++ # not IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ # not IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ diff --git a/libre/django13/diff-django_branches_releases_1.3.X-from-16771-to-17460.diff b/libre/django13/diff-django_branches_releases_1.3.X-from-16771-to-17460.diff new file mode 100644 index 000000000..ebbf80993 --- /dev/null +++ b/libre/django13/diff-django_branches_releases_1.3.X-from-16771-to-17460.diff @@ -0,0 +1,1575 @@ +Index: django/http/__init__.py +=================================================================== +--- django/http/__init__.py (revision 16771) ++++ django/http/__init__.py (revision 17460) +@@ -92,7 +92,7 @@ + if not _cookie_allows_colon_in_names: + def load(self, rawdata, ignore_parse_errors=False): + if ignore_parse_errors: +- self.bad_cookies = [] ++ self.bad_cookies = set() + self._BaseCookie__set = self._loose_set + super(SimpleCookie, self).load(rawdata) + if ignore_parse_errors: +@@ -106,8 +106,8 @@ + try: + self._strict_set(key, real_value, coded_value) + except Cookie.CookieError: +- self.bad_cookies.append(key) +- dict.__setitem__(self, key, None) ++ self.bad_cookies.add(key) ++ dict.__setitem__(self, key, Cookie.Morsel()) + + + class CompatCookie(SimpleCookie): +Index: django/http/utils.py +=================================================================== +--- django/http/utils.py (revision 16771) ++++ django/http/utils.py (revision 17460) +@@ -76,7 +76,8 @@ + + # The first part of the Content-Type field will be the MIME type, + # everything after ';', such as character-set, can be ignored. +- if response['Content-Type'].split(';')[0] not in safe_mime_types: ++ mime_type = response.get('Content-Type', '').partition(';')[0] ++ if mime_type not in safe_mime_types: + try: + del response['Vary'] + except KeyError: +Index: django/db/backends/creation.py +=================================================================== +--- django/db/backends/creation.py (revision 16771) ++++ django/db/backends/creation.py (revision 17460) +@@ -374,15 +374,6 @@ + verbosity=max(verbosity - 1, 0), + interactive=False, + database=self.connection.alias) +- +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- if 'django.contrib.sites' in settings.INSTALLED_APPS: +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) + + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache +Index: django/core/validators.py +=================================================================== +--- django/core/validators.py (revision 16771) ++++ django/core/validators.py (revision 17460) +@@ -147,7 +147,8 @@ + + email_re = re.compile( + r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom +- r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string ++ # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 ++ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' + r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain + validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid') + +Index: django/core/management/commands/shell.py +=================================================================== +--- django/core/management/commands/shell.py (revision 16771) ++++ django/core/management/commands/shell.py (revision 17460) +@@ -13,9 +13,8 @@ + + def ipython(self): + try: +- from IPython.frontend.terminal.embed import TerminalInteractiveShell +- shell = TerminalInteractiveShell() +- shell.mainloop() ++ from IPython import embed ++ embed() + except ImportError: + # IPython < 0.11 + # Explicitly pass an empty list as arguments, because otherwise +Index: django/contrib/gis/db/models/sql/compiler.py +=================================================================== +--- django/contrib/gis/db/models/sql/compiler.py (revision 16771) ++++ django/contrib/gis/db/models/sql/compiler.py (revision 17460) +@@ -1,7 +1,7 @@ + from itertools import izip +-from django.db.backends.util import truncate_name ++from django.db.backends.util import truncate_name, typecast_timestamp + from django.db.models.sql import compiler +-from django.db.models.sql.constants import TABLE_NAME ++from django.db.models.sql.constants import TABLE_NAME, MULTI + from django.db.models.sql.query import get_proxied_model + + SQLCompiler = compiler.SQLCompiler +@@ -194,7 +194,7 @@ + # We resolve the rest of the columns if we're on Oracle or if + # the `geo_values` attribute is defined. + for value, field in map(None, row[index_start:], fields): +- values.append(self.query.convert_values(value, field, connection=self.connection)) ++ values.append(self.query.convert_values(value, field, self.connection)) + else: + values.extend(row[index_start:]) + return tuple(values) +@@ -275,4 +275,24 @@ + pass + + class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- pass ++ """ ++ This is overridden for GeoDjango to properly cast date columns, since ++ `GeoQuery.resolve_columns` is used for spatial values. ++ See #14648, #16757. ++ """ ++ def results_iter(self): ++ if self.connection.ops.oracle: ++ from django.db.models.fields import DateTimeField ++ fields = [DateTimeField()] ++ else: ++ needs_string_cast = self.connection.features.needs_datetime_string_cast ++ ++ offset = len(self.query.extra_select) ++ for rows in self.execute_sql(MULTI): ++ for row in rows: ++ date = row[offset] ++ if self.connection.ops.oracle: ++ date = self.resolve_columns(row, fields)[offset] ++ elif needs_string_cast: ++ date = typecast_timestamp(str(date)) ++ yield date +Index: django/contrib/gis/db/backends/spatialite/compiler.py +=================================================================== +--- django/contrib/gis/db/backends/spatialite/compiler.py (revision 16771) ++++ django/contrib/gis/db/backends/spatialite/compiler.py (revision 17460) +@@ -1,32 +0,0 @@ +-from django.db.backends.util import typecast_timestamp +-from django.db.models.sql import compiler +-from django.db.models.sql.constants import MULTI +-from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler +- +-SQLCompiler = compiler.SQLCompiler +- +-class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler): +- pass +- +-class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler): +- pass +- +-class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler): +- pass +- +-class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler): +- pass +- +-class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler): +- pass +- +-class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler): +- """ +- This is overridden for GeoDjango to properly cast date columns, see #16757. +- """ +- def results_iter(self): +- offset = len(self.query.extra_select) +- for rows in self.execute_sql(MULTI): +- for row in rows: +- date = typecast_timestamp(str(row[offset])) +- yield date +Index: django/contrib/gis/db/backends/spatialite/operations.py +=================================================================== +--- django/contrib/gis/db/backends/spatialite/operations.py (revision 16771) ++++ django/contrib/gis/db/backends/spatialite/operations.py (revision 17460) +@@ -48,7 +48,7 @@ + return (SpatiaLiteDistance(operator),) + + class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations): +- compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler' ++ compiler_module = 'django.contrib.gis.db.models.sql.compiler' + name = 'spatialite' + spatialite = True + version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)') +Index: django/contrib/gis/db/backends/spatialite/creation.py +=================================================================== +--- django/contrib/gis/db/backends/spatialite/creation.py (revision 16771) ++++ django/contrib/gis/db/backends/spatialite/creation.py (revision 17460) +@@ -56,14 +56,6 @@ + interactive=False, + database=self.connection.alias) + +- # One effect of calling syncdb followed by flush is that the id of the +- # default site may or may not be 1, depending on how the sequence was +- # reset. If the sites app is loaded, then we coerce it. +- from django.db.models import get_model +- Site = get_model('sites', 'Site') +- if Site is not None and Site.objects.using(self.connection.alias).count() == 1: +- Site.objects.using(self.connection.alias).update(id=settings.SITE_ID) +- + from django.core.cache import get_cache + from django.core.cache.backends.db import BaseDatabaseCache + for cache_alias in settings.CACHES: +Index: django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz +=================================================================== +Cannot display: file marked as a binary type. +svn:mime-type = application/octet-stream +Index: django/contrib/gis/tests/relatedapp/tests.py +=================================================================== +--- django/contrib/gis/tests/relatedapp/tests.py (revision 16771) ++++ django/contrib/gis/tests/relatedapp/tests.py (revision 17460) +@@ -1,3 +1,4 @@ ++from datetime import date + from django.test import TestCase + + from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint +@@ -281,4 +282,11 @@ + # evaluated as list generation swallows TypeError in CPython. + sql = str(qs.query) + ++ def test16_annotated_date_queryset(self): ++ "Ensure annotated date querysets work if spatial backend is used. See #14648." ++ birth_years = [dt.year for dt in ++ list(Author.objects.annotate(num_books=Count('books')).dates('dob', 'year'))] ++ birth_years.sort() ++ self.assertEqual([1950, 1974], birth_years) ++ + # TODO: Related tests for KML, GML, and distance lookups. +Index: django/contrib/gis/tests/relatedapp/models.py +=================================================================== +--- django/contrib/gis/tests/relatedapp/models.py (revision 16771) ++++ django/contrib/gis/tests/relatedapp/models.py (revision 17460) +@@ -36,6 +36,7 @@ + # These use the GeoManager but do not have any geographic fields. + class Author(models.Model): + name = models.CharField(max_length=100) ++ dob = models.DateField() + objects = models.GeoManager() + + class Article(models.Model): +Index: django/contrib/sites/management.py +=================================================================== +--- django/contrib/sites/management.py (revision 16771) ++++ django/contrib/sites/management.py (revision 17460) +@@ -3,15 +3,34 @@ + """ + + from django.db.models import signals ++from django.db import connections ++from django.db import router + from django.contrib.sites.models import Site + from django.contrib.sites import models as site_app ++from django.core.management.color import no_style + + def create_default_site(app, created_models, verbosity, db, **kwargs): +- if Site in created_models: ++ # Only create the default sites in databases where Django created the table ++ if Site in created_models and router.allow_syncdb(db, Site) : ++ # The default settings set SITE_ID = 1, and some tests in Django's test ++ # suite rely on this value. However, if database sequences are reused ++ # (e.g. in the test suite after flush/syncdb), it isn't guaranteed that ++ # the next id will be 1, so we coerce it. See #15573 and #16353. This ++ # can also crop up outside of tests - see #15346. + if verbosity >= 2: + print "Creating example.com Site object" +- s = Site(domain="example.com", name="example.com") +- s.save(using=db) ++ Site(pk=1, domain="example.com", name="example.com").save(using=db) ++ ++ # We set an explicit pk instead of relying on auto-incrementation, ++ # so we need to reset the database sequence. ++ sequence_sql = connections[db].ops.sequence_reset_sql(no_style(), [Site]) ++ if sequence_sql: ++ if verbosity >= 2: ++ print "Resetting sequence" ++ cursor = connections[db].cursor() ++ for command in sequence_sql: ++ cursor.execute(command) ++ + Site.objects.clear_cache() + + signals.post_syncdb.connect(create_default_site, sender=site_app) +Index: django/contrib/sites/tests.py +=================================================================== +--- django/contrib/sites/tests.py (revision 16771) ++++ django/contrib/sites/tests.py (revision 17460) +@@ -15,6 +15,12 @@ + def tearDown(self): + Site._meta.installed = self.old_Site_meta_installed + ++ def test_save_another(self): ++ # Regression for #17415 ++ # On some backends the sequence needs reset after save with explicit ID. ++ # Test that there is no sequence collisions by saving another site. ++ Site(domain="example2.com", name="example2.com").save() ++ + def test_site_manager(self): + # Make sure that get_current() does not return a deleted Site object. + s = Site.objects.get_current() +Index: django/contrib/admin/media/css/forms.css +=================================================================== +--- django/contrib/admin/media/css/forms.css (revision 16771) ++++ django/contrib/admin/media/css/forms.css (revision 17460) +@@ -352,9 +352,3 @@ + .empty-form { + display: none; + } +- +-/* IE7 specific bug fixes */ +- +-.submit-row input { +- float: right; +-} +\ No newline at end of file +Index: tests/modeltests/validators/tests.py +=================================================================== +--- tests/modeltests/validators/tests.py (revision 16771) ++++ tests/modeltests/validators/tests.py (revision 17460) +@@ -28,6 +28,9 @@ + (validate_email, 'abc', ValidationError), + (validate_email, 'a @x.cz', ValidationError), + (validate_email, 'something@@somewhere.com', ValidationError), ++ # Quoted-string format (CR not allowed) ++ (validate_email, '"\\\011"@here.com', None), ++ (validate_email, '"\\\012"@here.com', ValidationError), + + (validate_slug, 'slug-ok', None), + (validate_slug, 'longer-slug-still-ok', None), +Index: tests/regressiontests/utils/http.py +=================================================================== +--- tests/regressiontests/utils/http.py (revision 16771) ++++ tests/regressiontests/utils/http.py (revision 17460) +@@ -1,5 +1,7 @@ + from django.utils import http + from django.utils import unittest ++from django.http import HttpResponse, utils ++from django.test import RequestFactory + + class TestUtilsHttp(unittest.TestCase): + +@@ -21,3 +23,49 @@ + self.assertFalse(http.same_origin('http://foo.com', 'http://foo.com.evil.com')) + # Different port + self.assertFalse(http.same_origin('http://foo.com:8000', 'http://foo.com:8001')) ++ ++ def test_fix_IE_for_vary(self): ++ """ ++ Regression for #16632. ++ ++ `fix_IE_for_vary` shouldn't crash when there's no Content-Type header. ++ """ ++ ++ # functions to generate responses ++ def response_with_unsafe_content_type(): ++ r = HttpResponse(content_type="text/unsafe") ++ r['Vary'] = 'Cookie' ++ return r ++ ++ def no_content_response_with_unsafe_content_type(): ++ # 'Content-Type' always defaulted, so delete it ++ r = response_with_unsafe_content_type() ++ del r['Content-Type'] ++ return r ++ ++ # request with & without IE user agent ++ rf = RequestFactory() ++ request = rf.get('/') ++ ie_request = rf.get('/', HTTP_USER_AGENT='MSIE') ++ ++ # not IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, unsafe_content_type ++ response = response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ # not IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(request, response) ++ self.assertTrue('Vary' in response) ++ ++ # IE, no_content ++ response = no_content_response_with_unsafe_content_type() ++ utils.fix_IE_for_vary(ie_request, response) ++ self.assertFalse('Vary' in response) ++ ++ +Index: tests/regressiontests/httpwrappers/tests.py +=================================================================== +--- tests/regressiontests/httpwrappers/tests.py (revision 16771) ++++ tests/regressiontests/httpwrappers/tests.py (revision 17460) +@@ -281,3 +281,9 @@ + Test that a single non-standard cookie name doesn't affect all cookies. Ticket #13007. + """ + self.assertTrue('good_cookie' in parse_cookie('good_cookie=yes;bad:cookie=yes').keys()) ++ ++ def test_repeated_nonstandard_keys(self): ++ """ ++ Test that a repeated non-standard name doesn't affect all cookies. Ticket #15852 ++ """ ++ self.assertTrue('good_cookie' in parse_cookie('a,=b; a,=c; good_cookie=yes').keys()) +Index: docs/index.txt +=================================================================== +--- docs/index.txt (revision 16771) ++++ docs/index.txt (revision 17460) +@@ -28,7 +28,7 @@ + .. _archives of the django-users mailing list: http://groups.google.com/group/django-users/ + .. _post a question: http://groups.google.com/group/django-users/ + .. _#django IRC channel: irc://irc.freenode.net/django +-.. _IRC logs: http://botland.oebfare.com/logger/django/ ++.. _IRC logs: http://django-irc-logs.com/ + .. _ticket tracker: http://code.djangoproject.com/ + + First steps +Index: docs/intro/tutorial01.txt +=================================================================== +--- docs/intro/tutorial01.txt (revision 16771) ++++ docs/intro/tutorial01.txt (revision 17460) +@@ -59,7 +59,7 @@ + can be run as a program. To do this, open Terminal.app and navigate (using + the ``cd`` command) to the directory where :doc:`django-admin.py + </ref/django-admin>` is installed, then run the command +- ``chmod +x django-admin.py``. ++ ``sudo chmod +x django-admin.py``. + + .. note:: + +@@ -692,10 +692,9 @@ + + For more information on model relations, see :doc:`Accessing related objects + </ref/models/relations>`. For more on how to use double underscores to perform +-field lookups via the API, see `Field lookups`__. For full details on the +-database API, see our :doc:`Database API reference </topics/db/queries>`. ++field lookups via the API, see :ref:`Field lookups <field-lookups-intro>`. For ++full details on the database API, see our :doc:`Database API reference ++</topics/db/queries>`. + +-__ http://docs.djangoproject.com/en/1.2/topics/db/queries/#field-lookups +- + When you're comfortable with the API, read :doc:`part 2 of this tutorial + </intro/tutorial02>` to get Django's automatic admin working. +Index: docs/intro/tutorial02.txt +=================================================================== +--- docs/intro/tutorial02.txt (revision 16771) ++++ docs/intro/tutorial02.txt (revision 17460) +@@ -40,22 +40,22 @@ + + .. parsed-literal:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + # Uncomment the next two lines to enable the admin: + **from django.contrib import admin** + **admin.autodiscover()** + + urlpatterns = patterns('', +- # Example: +- # (r'^mysite/', include('mysite.foo.urls')), ++ # Examples: ++ # url(r'^$', 'mysite.views.home', name='home'), ++ # url(r'^mysite/', include('mysite.foo.urls')), + +- # Uncomment the admin/doc line below and add 'django.contrib.admindocs' +- # to INSTALLED_APPS to enable admin documentation: +- # (r'^admin/doc/', include('django.contrib.admindocs.urls')), ++ # Uncomment the admin/doc line below to enable admin documentation: ++ # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: +- **(r'^admin/', include(admin.site.urls)),** ++ **url(r'^admin/', include(admin.site.urls)),** + ) + + (The bold lines are the ones that needed to be uncommented.) +Index: docs/intro/tutorial03.txt +=================================================================== +--- docs/intro/tutorial03.txt (revision 16771) ++++ docs/intro/tutorial03.txt (revision 17460) +@@ -78,17 +78,17 @@ + + Time for an example. Edit ``mysite/urls.py`` so it looks like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^admin/', include(admin.site.urls)), + ) + + This is worth a review. When somebody requests a page from your Web site -- say, +@@ -112,7 +112,7 @@ + -- unless you have a sick sense of humor, in which case you can do something + like this:: + +- (r'^polls/latest\.php$', 'polls.views.index'), ++ url(r'^polls/latest\.php$', 'polls.views.index'), + + But, don't do that. It's silly. + +@@ -357,23 +357,24 @@ + Write a 404 (page not found) view + ================================= + +-When you raise :exc:`~django.http.Http404` from within a view, Django will load +-a special view devoted to handling 404 errors. It finds it by looking for the +-variable ``handler404``, which is a string in Python dotted syntax -- the same +-format the normal URLconf callbacks use. A 404 view itself has nothing special: +-It's just a normal view. ++When you raise :exc:`~django.http.Http404` from within a view, Django ++will load a special view devoted to handling 404 errors. It finds it ++by looking for the variable ``handler404`` in your root URLconf (and ++only in your root URLconf; setting ``handler404`` anywhere else will ++have no effect), which is a string in Python dotted syntax -- the same ++format the normal URLconf callbacks use. A 404 view itself has nothing ++special: It's just a normal view. + +-You normally won't have to bother with writing 404 views. By default, URLconfs +-have the following line up top:: ++You normally won't have to bother with writing 404 views. If you don't set ++``handler404``, the built-in view :func:`django.views.defaults.page_not_found` ++is used by default. In this case, you still have one obligation: To create a ++``404.html`` template in the root of your template directory. The default 404 ++view will use that template for all 404 errors. If :setting:`DEBUG` is set to ++``False`` (in your settings module) and if you didn't create a ``404.html`` ++file, an ``Http500`` is raised instead. So remember to create a ``404.html``. + +- from django.conf.urls.defaults import * ++A couple more things to note about 404 views: + +-That takes care of setting ``handler404`` in the current module. As you can see +-in ``django/conf/urls/defaults.py``, ``handler404`` is set to +-:func:`django.views.defaults.page_not_found` by default. +- +-Four more things to note about 404 views: +- + * If :setting:`DEBUG` is set to ``True`` (in your settings module) then your + 404 view will never be used (and thus the ``404.html`` template will never + be rendered) because the traceback will be displayed instead. +@@ -381,21 +382,12 @@ + * The 404 view is also called if Django doesn't find a match after checking + every regular expression in the URLconf. + +- * If you don't define your own 404 view -- and simply use the default, which +- is recommended -- you still have one obligation: To create a ``404.html`` +- template in the root of your template directory. The default 404 view will +- use that template for all 404 errors. +- +- * If :setting:`DEBUG` is set to ``False`` (in your settings module) and if +- you didn't create a ``404.html`` file, an ``Http500`` is raised instead. +- So remember to create a ``404.html``. +- + Write a 500 (server error) view + =============================== + +-Similarly, URLconfs may define a ``handler500``, which points to a view to call +-in case of server errors. Server errors happen when you have runtime errors in +-view code. ++Similarly, your root URLconf may define a ``handler500``, which points ++to a view to call in case of server errors. Server errors happen when ++you have runtime errors in view code. + + Use the template system + ======================= +@@ -432,10 +424,10 @@ + the URLconf, you may notice there's a fair bit of redundancy in it:: + + urlpatterns = patterns('', +- (r'^polls/$', 'polls.views.index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^polls/$', 'polls.views.index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + Namely, ``polls.views`` is in every callback. +@@ -445,10 +437,10 @@ + first argument to :func:`~django.conf.urls.defaults.patterns`, like so:: + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + This is functionally identical to the previous formatting. It's just a bit +@@ -459,20 +451,20 @@ + :func:`~django.conf.urls.defaults.patterns`. Your full ``mysite/urls.py`` might + now look like this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + from django.contrib import admin + admin.autodiscover() + + urlpatterns = patterns('polls.views', +- (r'^polls/$', 'index'), +- (r'^polls/(?P<poll_id>\d+)/$', 'detail'), +- (r'^polls/(?P<poll_id>\d+)/results/$', 'results'), +- (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^polls/$', 'index'), ++ url(r'^polls/(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + urlpatterns += patterns('', +- (r'^admin/', include(admin.site.urls)), ++ url(r'^admin/', include(admin.site.urls)), + ) + + Decoupling the URLconfs +@@ -502,8 +494,8 @@ + admin.autodiscover() + + urlpatterns = patterns('', +- (r'^polls/', include('polls.urls')), +- (r'^admin/', include(admin.site.urls)), ++ url(r'^polls/', include('polls.urls')), ++ url(r'^admin/', include(admin.site.urls)), + ) + + :func:`~django.conf.urls.defaults.include` simply references another URLconf. +@@ -526,13 +518,13 @@ + lines registering the admin site. Your ``polls/urls.py`` file should now look like + this:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + The idea behind :func:`~django.conf.urls.defaults.include` and URLconf +Index: docs/intro/index.txt +=================================================================== +--- docs/intro/index.txt (revision 16771) ++++ docs/intro/index.txt (revision 17460) +@@ -31,6 +31,6 @@ + + .. _python: http://python.org/ + .. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers +- .. _dive into python: http://diveintopython.org/ ++ .. _dive into python: http://diveintopython.net/ + .. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20 + .. _books about Python: http://wiki.python.org/moin/PythonBooks +\ No newline at end of file +Index: docs/intro/tutorial04.txt +=================================================================== +--- docs/intro/tutorial04.txt (revision 16771) ++++ docs/intro/tutorial04.txt (revision 17460) +@@ -218,13 +218,13 @@ + First, open the ``polls/urls.py`` URLconf. It looks like this, according to the + tutorial so far:: + +- from django.conf.urls.defaults import * ++ from django.conf.urls.defaults import patterns, include, url + + urlpatterns = patterns('polls.views', +- (r'^$', 'index'), +- (r'^(?P<poll_id>\d+)/$', 'detail'), +- (r'^(?P<poll_id>\d+)/results/$', 'results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'vote'), ++ url(r'^$', 'index'), ++ url(r'^(?P<poll_id>\d+)/$', 'detail'), ++ url(r'^(?P<poll_id>\d+)/results/$', 'results'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), + ) + + Change it like so:: +@@ -234,12 +234,12 @@ + from polls.models import Poll + + urlpatterns = patterns('', +- (r'^$', ++ url(r'^$', + ListView.as_view( + queryset=Poll.objects.order_by('-pub_date')[:5], + context_object_name='latest_poll_list', + template_name='polls/index.html')), +- (r'^(?P<pk>\d+)/$', ++ url(r'^(?P<pk>\d+)/$', + DetailView.as_view( + model=Poll, + template_name='polls/detail.html')), +@@ -248,7 +248,7 @@ + model=Poll, + template_name='polls/results.html'), + name='poll_results'), +- (r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), ++ url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), + ) + + We're using two generic views here: +Index: docs/internals/release-process.txt +=================================================================== +--- docs/internals/release-process.txt (revision 16771) ++++ docs/internals/release-process.txt (revision 17460) +@@ -99,6 +99,13 @@ + * Security fixes will be applied to the current trunk and the previous two + minor releases. + ++* Documentation fixes will generally be more freely backported to the last ++ release branch (at the discretion of the committer), and don't need to meet ++ the "critical fixes only" bar as it's highly advantageous to have the docs ++ for the last release be up-to-date and correct, and the downside of ++ backporting (risk of introducing regressions) is much less of a concern ++ with doc fixes. ++ + As a concrete example, consider a moment in time halfway between the release of + Django 1.3 and 1.4. At this point in time: + +@@ -111,6 +118,9 @@ + ``1.2.X`` branch. Security fixes will trigger the release of ``1.3.1``, + ``1.2.1``, etc. + ++* Documentation fixes will be applied to trunk, and if easily backported, to ++ the ``1.3.X`` branch. ++ + .. _release-process: + + Release process +Index: docs/internals/deprecation.txt +=================================================================== +--- docs/internals/deprecation.txt (revision 16771) ++++ docs/internals/deprecation.txt (revision 17460) +@@ -177,6 +177,12 @@ + required to end with a trailing slash to ensure there is a consistent + way to combine paths in templates. + ++ * Translations located under the so-called *project path* will be ++ ignored during the translation building process performed at runtime. ++ The :setting:`LOCALE_PATHS` setting can be used for the same task by ++ including the filesystem path to a ``locale`` directory containing ++ non-app-specific translations in its value. ++ + * 2.0 + * ``django.views.defaults.shortcut()``. This function has been moved + to ``django.contrib.contenttypes.views.shortcut()`` as part of the +Index: docs/howto/deployment/modpython.txt +=================================================================== +--- docs/howto/deployment/modpython.txt (revision 16771) ++++ docs/howto/deployment/modpython.txt (revision 17460) +@@ -293,11 +293,14 @@ + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +Index: docs/howto/deployment/modwsgi.txt +=================================================================== +--- docs/howto/deployment/modwsgi.txt (revision 16771) ++++ docs/howto/deployment/modwsgi.txt (revision 17460) +@@ -127,11 +127,14 @@ + arrangement. You're responsible for setting up Apache, or whichever media + server you're using, to serve the admin files. + +-The admin files live in (:file:`django/contrib/admin/static/admin`) of the ++The admin files live in (:file:`django/contrib/admin/media/admin`) of the + Django distribution. + +-We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle +-the admin files, but here are two other approaches: ++We **strongly** recommend using :mod:`django.contrib.staticfiles` to handle the ++admin files (this means using the :djadmin:`collectstatic` management command ++to collect the static files in :setting:`STATIC_ROOT`, and then configuring ++your webserver to serve :setting:`STATIC_ROOT` at :setting:`STATIC_URL`), but ++here are two other approaches: + + 1. Create a symbolic link to the admin static files from within your + document root. +Index: docs/topics/auth.txt +=================================================================== +--- docs/topics/auth.txt (revision 16771) ++++ docs/topics/auth.txt (revision 17460) +@@ -1251,17 +1251,20 @@ + ... + class Meta: + permissions = ( +- ("can_view", "Can see available tasks"), +- ("can_change_status", "Can change the status of tasks"), +- ("can_close", "Can remove a task by setting its status as closed"), ++ ("view_task", "Can see available tasks"), ++ ("change_task_status", "Can change the status of tasks"), ++ ("close_task", "Can remove a task by setting its status as closed"), + ) + + The only thing this does is create those extra permissions when you run + :djadmin:`manage.py syncdb <syncdb>`. Your code is in charge of checking the + value of these permissions when an user is trying to access the functionality + provided by the application (viewing tasks, changing the status of tasks, +-closing tasks.) ++closing tasks.) Continuing the above example, the following checks if a user may ++view tasks:: + ++ user.has_perm('app.view_task') ++ + API reference + ------------- + +Index: docs/topics/http/urls.txt +=================================================================== +--- docs/topics/http/urls.txt (revision 16771) ++++ docs/topics/http/urls.txt (revision 17460) +@@ -54,6 +54,10 @@ + :class:`~django.http.HttpRequest` as its first argument and any values + captured in the regex as remaining arguments. + ++ 5. If no regex matches, or if an exception is raised during any ++ point in this process, Django invokes an appropriate ++ error-handling view. See `Error handling`_ below. ++ + Example + ======= + +@@ -99,10 +103,10 @@ + * ``/articles/2003`` would not match any of these patterns, because each + pattern requires that the URL end with a slash. + +- * ``/articles/2003/03/3/`` would match the final pattern. Django would call +- the function ``news.views.article_detail(request, '2003', '03', '3')``. ++ * ``/articles/2003/03/03/`` would match the final pattern. Django would call ++ the function ``news.views.article_detail(request, '2003', '03', '03')``. + +-.. _Dive Into Python's explanation: http://diveintopython.org/regular_expressions/street_addresses.html#re.matching.2.3 ++.. _Dive Into Python's explanation: http://diveintopython.net/regular_expressions/street_addresses.html#re.matching.2.3 + + Named groups + ============ +@@ -123,7 +127,7 @@ + (r'^articles/2003/$', 'news.views.special_case_2003'), + (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'), + (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'), +- (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'), ++ (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', 'news.views.article_detail'), + ) + + This accomplishes exactly the same thing as the previous example, with one +@@ -134,8 +138,8 @@ + ``news.views.month_archive(request, year='2005', month='03')``, instead + of ``news.views.month_archive(request, '2005', '03')``. + +- * A request to ``/articles/2003/03/3/`` would call the function +- ``news.views.article_detail(request, year='2003', month='03', day='3')``. ++ * A request to ``/articles/2003/03/03/`` would call the function ++ ``news.views.article_detail(request, year='2003', month='03', day='03')``. + + In practice, this means your URLconfs are slightly more explicit and less prone + to argument-order bugs -- and you can reorder the arguments in your views' +@@ -246,6 +250,31 @@ + ``patterns()`` and is only relevant when you're passing a string as the + ``view`` parameter. + ++include ++------- ++ ++.. function:: include(<module or pattern_list>) ++ ++A function that takes a full Python import path to another URLconf module that ++should be "included" in this place. ++ ++:func:`include` also accepts as an argument an iterable that returns URL ++patterns. ++ ++See `Including other URLconfs`_ below. ++ ++Error handling ++============== ++ ++When Django can't find a regex matching the requested URL, or when an ++exception is raised, Django will invoke an error-handling view. The ++views to use for these cases are specified by two variables which can ++be set in your root URLconf. Setting these variables in any other ++URLconf will have no effect. ++ ++See the documentation on :ref:`customizing error views ++<customizing-error-views>` for more details. ++ + handler404 + ---------- + +@@ -275,19 +304,6 @@ + .. versionchanged:: 1.2 + Previous versions of Django only accepted strings representing import paths. + +-include +-------- +- +-.. function:: include(<module or pattern_list>) +- +-A function that takes a full Python import path to another URLconf module that +-should be "included" in this place. +- +-:func:`include` also accepts as an argument an iterable that returns URL +-patterns. +- +-See `Including other URLconfs`_ below. +- + Notes on capturing text in URLs + =============================== + +@@ -420,8 +436,8 @@ + from django.conf.urls.defaults import * + + extra_patterns = patterns('', +- url(r'reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), +- url(r'charge/$', 'credit.views.charge', name='credit-charge'), ++ url(r'^reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), ++ url(r'^charge/$', 'credit.views.charge', name='credit-charge'), + ) + + urlpatterns = patterns('', +Index: docs/topics/http/views.txt +=================================================================== +--- docs/topics/http/views.txt (revision 16771) ++++ docs/topics/http/views.txt (revision 17460) +@@ -122,6 +122,8 @@ + template that is displayed when a 404 error is raised. This template should be + called ``404.html`` and located in the top level of your template tree. + ++.. _customizing-error-views: ++ + Customizing error views + ======================= + +Index: docs/topics/i18n/internationalization.txt +=================================================================== +--- docs/topics/i18n/internationalization.txt (revision 16771) ++++ docs/topics/i18n/internationalization.txt (revision 17460) +@@ -477,7 +477,7 @@ + + You can use multiple expressions inside a single ``blocktrans`` tag:: + +- {% blocktrans with book_t=book|title and author_t=author|title %} ++ {% blocktrans with book_t=book|title author_t=author|title %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + +Index: docs/topics/cache.txt +=================================================================== +--- docs/topics/cache.txt (revision 16771) ++++ docs/topics/cache.txt (revision 17460) +@@ -99,8 +99,9 @@ + on your chosen memcached binding) + + * Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values, +- where ``ip`` is the IP address of the Memcached daemon and +- ``port`` is the port on which Memcached is running. ++ where ``ip`` is the IP address of the Memcached daemon and ``port`` is the ++ port on which Memcached is running, or to a ``unix:path`` value, where ++ ``path`` is the path to a Memcached Unix socket file. + + In this example, Memcached is running on localhost (127.0.0.1) port 11211, using + the ``python-memcached`` binding:: +@@ -112,6 +113,16 @@ + } + } + ++In this example, Memcached is available through a local Unix socket file ++:file:`/tmp/memcached.sock` using the ``python-memcached`` binding:: ++ ++ CACHES = { ++ 'default': { ++ 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', ++ 'LOCATION': 'unix:/tmp/memcached.sock', ++ } ++ } ++ + One excellent feature of Memcached is its ability to share cache over multiple + servers. This means you can run Memcached daemons on multiple machines, and the + program will treat the group of machines as a *single* cache, without the need +@@ -526,9 +537,10 @@ + requested, subsequent requests to that URL will use the cache. + + ``cache_page`` can also take an optional keyword argument, ``cache``, +-which directs the decorator to use a specific cache alias when caching view +-results. By default, the ``default`` alias will be used, but you can specify +-any cache alias you want:: ++which directs the decorator to use a specific cache (from your ++:setting:`CACHES` setting) when caching view results. By default, the ++``default`` cache will be used, but you can specify any cache you ++want:: + + @cache_page(60 * 15, cache="special_cache") + def my_view(request): +Index: docs/topics/db/models.txt +=================================================================== +--- docs/topics/db/models.txt (revision 16771) ++++ docs/topics/db/models.txt (revision 17460) +@@ -324,11 +324,10 @@ + should work; all are optional. + + For details on accessing backwards-related objects, see the +- `Following relationships backward example`_. +- ++ :ref:`Following relationships backward example <backwards-related-objects>`. ++ + For sample code, see the `Many-to-one relationship model tests`_. + +- .. _Following relationships backward example: http://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects + .. _Many-to-one relationship model tests: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/many_to_one + + Many-to-many relationships +Index: docs/topics/db/sql.txt +=================================================================== +--- docs/topics/db/sql.txt (revision 16771) ++++ docs/topics/db/sql.txt (revision 17460) +@@ -236,6 +236,30 @@ + # Your code here... + transaction.commit_unless_managed(using='my_db_alias') + ++By default, the Python DB API will return results without their field ++names, which means you end up with a ``list`` of values, rather than a ++``dict``. At a small performance cost, you can return results as a ++``dict`` by using something like this:: ++ ++ def dictfetchall(cursor): ++ "Returns all rows from a cursor as a dict" ++ desc = cursor.description ++ return [ ++ dict(zip([col[0] for col in desc], row)) ++ for row in cursor.fetchall() ++ ] ++ ++Here is an example of the difference between the two:: ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> cursor.fetchall() ++ ((54360982L, None), (54360880L, None)) ++ ++ >>> cursor.execute("SELECT id, parent_id from test LIMIT 2"); ++ >>> dictfetchall(cursor) ++ [{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}] ++ ++ + .. _transactions-and-raw-sql: + + Transactions and raw SQL +Index: docs/topics/forms/modelforms.txt +=================================================================== +--- docs/topics/forms/modelforms.txt (revision 16771) ++++ docs/topics/forms/modelforms.txt (revision 17460) +@@ -332,14 +332,18 @@ + .. note:: + + If you specify ``fields`` or ``exclude`` when creating a form with +- ``ModelForm``, then the fields that are not in the resulting form will not +- be set by the form's ``save()`` method. Django will prevent any attempt to +- save an incomplete model, so if the model does not allow the missing fields +- to be empty, and does not provide a default value for the missing fields, +- any attempt to ``save()`` a ``ModelForm`` with missing fields will fail. +- To avoid this failure, you must instantiate your model with initial values +- for the missing, but required fields:: ++ ``ModelForm``, then the fields that are not in the resulting form ++ will not be set by the form's ``save()`` method. Also, if you ++ manually add the excluded fields back to the form, they will not ++ be initialized from the model instance. + ++ Django will prevent any attempt to save an incomplete model, so if ++ the model does not allow the missing fields to be empty, and does ++ not provide a default value for the missing fields, any attempt to ++ ``save()`` a ``ModelForm`` with missing fields will fail. To ++ avoid this failure, you must instantiate your model with initial ++ values for the missing, but required fields:: ++ + author = Author(title='Mr') + form = PartialAuthorForm(request.POST, instance=author) + form.save() +@@ -633,6 +637,12 @@ + instance won't be saved to the database and won't be included in the return + value (``instances``, in the above example). + ++When fields are missing from the form (for example because they have ++been excluded), these fields will not be set by the ``save()`` ++method. You can find more information about this restriction, which ++also holds for regular ``ModelForms``, in `Using a subset of fields on ++the form`_. ++ + Pass ``commit=False`` to return the unsaved model instances:: + + # don't save to the database +Index: docs/topics/class-based-views.txt +=================================================================== +--- docs/topics/class-based-views.txt (revision 16771) ++++ docs/topics/class-based-views.txt (revision 17460) +@@ -380,7 +380,7 @@ + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +@@ -396,7 +396,7 @@ + class PublisherBookListView(ListView): + + context_object_name = "book_list" +- template_name = "books/books_by_publisher.html", ++ template_name = "books/books_by_publisher.html" + + def get_queryset(self): + self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0]) +Index: docs/topics/testing.txt +=================================================================== +--- docs/topics/testing.txt (revision 16771) ++++ docs/topics/testing.txt (revision 17460) +@@ -1586,7 +1586,7 @@ + Skip the decorated test if the named database feature is *not* + supported. + +-For example, the following test will not be executed if the database ++For example, the following test will only be executed if the database + supports transactions (e.g., it would run under PostgreSQL, but *not* + under MySQL with MyISAM tables):: + +Index: docs/topics/templates.txt +=================================================================== +--- docs/topics/templates.txt (revision 16771) ++++ docs/topics/templates.txt (revision 17460) +@@ -555,6 +555,8 @@ + the ``escape`` filter *double-escaping* data -- the ``escape`` filter does not + affect auto-escaped variables. + ++.. _string-literals-and-automatic-escaping: ++ + String literals and automatic escaping + -------------------------------------- + +Index: docs/topics/settings.txt +=================================================================== +--- docs/topics/settings.txt (revision 16771) ++++ docs/topics/settings.txt (revision 17460) +@@ -39,7 +39,7 @@ + ``mysite.settings``. Note that the settings module should be on the + Python `import search path`_. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + The django-admin.py utility + --------------------------- +Index: docs/releases/1.2.6.txt +=================================================================== +--- docs/releases/1.2.6.txt (revision 0) ++++ docs/releases/1.2.6.txt (revision 17460) +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.6 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.2.6! ++ ++This is the sixth bugfix/security release in the Django 1.2 series, fixing ++several security issues present in Django 1.2.5. Django 1.2.6 is a ++recommended upgrade for all users of any Django release in the 1.2.X series. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +Index: docs/releases/1.2.7.txt +=================================================================== +--- docs/releases/1.2.7.txt (revision 0) ++++ docs/releases/1.2.7.txt (revision 17460) +@@ -0,0 +1,16 @@ ++========================== ++Django 1.2.7 release notes ++========================== ++ ++*September 10, 2011* ++ ++Welcome to Django 1.2.7! ++ ++This is the seventh bugfix/security release in the Django 1.2 series. It ++replaces Django 1.2.6 due to problems with the 1.2.6 release tarball. ++Django 1.2.7 is a recommended upgrade for all users of any Django release in ++the 1.2.X series. ++ ++For more information, see the `release advisory`_. ++ ++.. _release advisory: https://www.djangoproject.com/weblog/2011/sep/10/127/ +Index: docs/releases/index.txt +=================================================================== +--- docs/releases/index.txt (revision 16771) ++++ docs/releases/index.txt (revision 17460) +@@ -19,6 +19,7 @@ + .. toctree:: + :maxdepth: 1 + ++ 1.3.1 + 1.3 + + 1.2 release +@@ -26,6 +27,8 @@ + .. toctree:: + :maxdepth: 1 + ++ 1.2.7 ++ 1.2.6 + 1.2.5 + 1.2.4 + 1.2.2 +Index: docs/releases/0.95.txt +=================================================================== +--- docs/releases/0.95.txt (revision 16771) ++++ docs/releases/0.95.txt (revision 17460) +@@ -92,15 +92,15 @@ + easy checklist_ for reference when undertaking the porting operation. + + .. _Removing The Magic: http://code.djangoproject.com/wiki/RemovingTheMagic +-.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet1 ++.. _checklist: http://code.djangoproject.com/wiki/MagicRemovalCheatSheet + + Problem reports and getting help + ================================ + +-Need help resolving a problem with Django? The documentation in the distribution +-is also available online_ at the `Django Web site`_. The :doc:`FAQ </faq/index>` +-document is especially recommended, as it contains a number of issues that come +-up time and again. ++Need help resolving a problem with Django? The documentation in the ++distribution is also available :doc:`online </index>` at the `Django Web ++site`_. The :doc:`FAQ </faq/index>` document is especially recommended, as it ++contains a number of issues that come up time and again. + + For more personalized help, the `django-users`_ mailing list is a very active + list, with more than 2,000 subscribers who can help you solve any sort of +@@ -113,7 +113,6 @@ + Django users and developers from around the world. Friendly people are usually + available at any hour of the day -- to help, or just to chat. + +-.. _online: http://www.djangoproject.com/documentation/0.95/ + .. _Django Web site: http://www.djangoproject.com/ + .. _django-users: http://groups.google.com/group/django-users + +Index: docs/releases/0.96.txt +=================================================================== +--- docs/releases/0.96.txt (revision 16771) ++++ docs/releases/0.96.txt (revision 17460) +@@ -50,12 +50,10 @@ + maintained, and it will be removed in a future release of Django. + + Also, note that some features, like the new :setting:`DATABASE_OPTIONS` +-setting (see the `databases documentation`_ for details), are only +-available on the "mysql" backend, and will not be made available for ++setting (see the :doc:`databases documentation </ref/databases>` for details), ++are only available on the "mysql" backend, and will not be made available for + "mysql_old". + +-.. _databases documentation: http://www.djangoproject.com/documentation/0.96/databases/ +- + Database constraint names changed + --------------------------------- + +@@ -164,11 +162,9 @@ + for most common cases. We recommend that anyone new to form handling skip the + old forms system and start with the new. + +-For more information about ``django.newforms``, read the `newforms +-documentation`_. ++For more information about ``django.newforms``, read the :doc:`newforms ++documentation </topics/forms/index>`. + +-.. _newforms documentation: http://www.djangoproject.com/documentation/0.96/newforms/ +- + URLconf improvements + -------------------- + +@@ -216,20 +212,16 @@ + ------------------ + + Django now includes a test framework so you can start transmuting fear into +-boredom (with apologies to Kent Beck). You can write tests based on doctest_ +-or unittest_ and test your views with a simple test client. ++boredom (with apologies to Kent Beck). You can write tests based on ++:mod:`doctest` or :mod:`unittest` and test your views with a simple test client. + + There is also new support for "fixtures" -- initial data, stored in any of the +-supported `serialization formats`_, that will be loaded into your database at the +-start of your tests. This makes testing with real data much easier. ++supported :doc:`serialization formats </topics/serialization>`, that will be ++loaded into your database at the start of your tests. This makes testing with ++real data much easier. + +-See `the testing documentation`_ for the full details. ++See :doc:`the testing documentation </topics/testing>` for the full details. + +-.. _doctest: http://docs.python.org/library/doctest.html +-.. _unittest: http://docs.python.org/library/unittest.html +-.. _the testing documentation: http://www.djangoproject.com/documentation/0.96/testing/ +-.. _serialization formats: http://www.djangoproject.com/documentation/0.96/serialization/ +- + Improvements to the admin interface + ----------------------------------- + +Index: docs/releases/1.0.1.txt +=================================================================== +--- docs/releases/1.0.1.txt (revision 16771) ++++ docs/releases/1.0.1.txt (revision 17460) +@@ -6,10 +6,10 @@ + + This is the first "bugfix" release in the Django 1.0 series, improving + the stability and performance of the Django 1.0 codebase. As such, +-Django 1.0.1 contains no new features (and, pursuant to `our +-compatibility policy`_, maintains backwards compatibility with Django +-1.0), but does contain a number of fixes and other +-improvements. Django 1.0.1 is a recommended upgrade for any ++Django 1.0.1 contains no new features (and, pursuant to :doc:`our ++compatibility policy </misc/api-stability/>`, maintains backwards ++compatibility with Django 1.0), but does contain a number of fixes ++and other improvements. Django 1.0.1 is a recommended upgrade for any + development or deployment currently using or targeting Django 1.0. + + +@@ -46,8 +46,9 @@ + + * A fix to the application of autoescaping for literal strings passed + to the ``join`` template filter. Previously, literal strings passed +- to ``join`` were automatically escaped, contrary to `the documented +- behavior for autoescaping and literal strings`_. Literal strings ++ to ``join`` were automatically escaped, contrary to :ref:`the ++ documented behavior for autoescaping and literal strings ++ <string-literals-and-automatic-escaping>`. Literal strings + passed to ``join`` are no longer automatically escaped, meaning you + must now manually escape them; this is an incompatibility if you + were relying on this bug, but not if you were relying on escaping +@@ -60,6 +61,4 @@ + documentation, including both corrections to existing documents and + expanded and new documentation. + +-.. _our compatibility policy: http://docs.djangoproject.com/en/dev/misc/api-stability/ + .. _the Subversion log of the 1.0.X branch: http://code.djangoproject.com/log/django/branches/releases/1.0.X +-.. _the documented behavior for autoescaping and literal strings: http://docs.djangoproject.com/en/dev/topics/templates/#string-literals-and-automatic-escaping +Index: docs/releases/1.3.1.txt +=================================================================== +--- docs/releases/1.3.1.txt (revision 0) ++++ docs/releases/1.3.1.txt (revision 17460) +@@ -0,0 +1,16 @@ ++========================== ++Django 1.3.1 release notes ++========================== ++ ++*September 9, 2011* ++ ++Welcome to Django 1.3.1! ++ ++This is the first security release in the Django 1.3 series, fixing several ++security issues in Django 1.3. Django 1.3.1 is a recommended upgrade for ++all users of Django 1.3. ++ ++For a full list of issues addressed in this release, see the `security ++advisory`_. ++ ++.. _security advisory: https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ +Index: docs/ref/models/instances.txt +=================================================================== +--- docs/ref/models/instances.txt (revision 16771) ++++ docs/ref/models/instances.txt (revision 17460) +@@ -470,7 +470,7 @@ + + Similarly, if you had a URLconf entry that looked like:: + +- (r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view) ++ (r'/archive/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', archive_view) + + ...you could reference this using ``permalink()`` as follows:: + +@@ -478,8 +478,8 @@ + def get_absolute_url(self): + return ('archive_view', (), { + 'year': self.created.year, +- 'month': self.created.month, +- 'day': self.created.day}) ++ 'month': self.created.strftime('%m'), ++ 'day': self.created.strftime('%d')}) + + Notice that we specify an empty sequence for the second parameter in this case, + because we only want to pass keyword parameters, not positional ones. +Index: docs/ref/models/options.txt +=================================================================== +--- docs/ref/models/options.txt (revision 16771) ++++ docs/ref/models/options.txt (revision 17460) +@@ -166,6 +166,13 @@ + >>> answer.get_previous_in_order() + <Answer: 1> + ++.. admonition:: Changing order_with_respect_to ++ ++ ``order_with_respect_to`` adds an additional field/database column ++ named ``_order``, so be sure to handle that as you would any other ++ change to your models if you add or change ``order_with_respect_to`` ++ after your initial :djadmin:`syncdb`. ++ + ``ordering`` + ------------ + +@@ -238,6 +245,12 @@ + + unique_together = ("driver", "restaurant") + ++ A :class:`~django.db.models.ManyToManyField` cannot be included in ++ unique_together (it's not even clear what that would mean). If you ++ need to validate uniqueness related to a ++ :class:`~django.db.models.ManyToManyField`, look at signals or ++ using an explicit :attr:`through <ManyToManyField.through>` model. ++ + ``verbose_name`` + ---------------- + +Index: docs/ref/templates/builtins.txt +=================================================================== +--- docs/ref/templates/builtins.txt (revision 16771) ++++ docs/ref/templates/builtins.txt (revision 17460) +@@ -1868,7 +1868,7 @@ + Returns a slice of the list. + + Uses the same syntax as Python's list slicing. See +-http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice ++http://diveintopython.net/native_data_types/lists.html#odbchelper.list.slice + for an introduction. + + Example:: +Index: docs/ref/contrib/gis/geoip.txt +=================================================================== +--- docs/ref/contrib/gis/geoip.txt (revision 16771) ++++ docs/ref/contrib/gis/geoip.txt (revision 17460) +@@ -144,7 +144,7 @@ + Returns a dictionary of city information for the given query. Some + of the values in the dictionary may be undefined (``None``). + +-.. method:: GeoIPcountry(query) ++.. method:: GeoIP.country(query) + + Returns a dictionary with the country code and country for the given + query. +Index: docs/ref/contrib/messages.txt +=================================================================== +--- docs/ref/contrib/messages.txt (revision 16771) ++++ docs/ref/contrib/messages.txt (revision 17460) +@@ -210,6 +210,10 @@ + ``RequestContext``. Otherwise, ensure ``messages`` is available to + the template context. + ++Even if you know there is only just one message, you should still iterate over ++the ``messages`` sequence, because otherwise the message storage will not be cleared ++for the next request. ++ + Creating custom message levels + ------------------------------ + +Index: docs/ref/contrib/admin/index.txt +=================================================================== +--- docs/ref/contrib/admin/index.txt (revision 16771) ++++ docs/ref/contrib/admin/index.txt (revision 17460) +@@ -19,8 +19,10 @@ + 1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS` + setting. + +- 2. Admin has two dependencies - :mod:`django.contrib.auth` and +- :mod:`django.contrib.contenttypes`. If these applications are not ++ 2. The admin has four dependencies - :mod:`django.contrib.auth`, ++ :mod:`django.contrib.contenttypes`, ++ :mod:`django.contrib.messages` and ++ :mod:`django.contrib.sessions`. If these applications are not + in your :setting:`INSTALLED_APPS` list, add them. + + 3. Determine which of your application's models should be editable in the +@@ -542,7 +544,7 @@ + Fields in ``list_filter`` can also span relations using the ``__`` lookup:: + + class UserAdminWithLookup(UserAdmin): +- list_filter = ('groups__name') ++ list_filter = ('groups__name',) + + .. attribute:: ModelAdmin.list_per_page + +Index: docs/ref/django-admin.txt +=================================================================== +--- docs/ref/django-admin.txt (revision 16771) ++++ docs/ref/django-admin.txt (revision 17460) +@@ -1156,7 +1156,7 @@ + Note that this option is unnecessary in ``manage.py``, because it takes care of + setting the Python path for you. + +-.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html ++.. _import search path: http://diveintopython.net/getting_to_know_python/everything_is_an_object.html + + .. django-admin-option:: --settings + +Index: docs/ref/signals.txt +=================================================================== +--- docs/ref/signals.txt (revision 16771) ++++ docs/ref/signals.txt (revision 17460) +@@ -352,12 +352,16 @@ + .. data:: django.db.models.signals.post_syncdb + :module: + +-Sent by :djadmin:`syncdb` after it installs an application. ++Sent by :djadmin:`syncdb` command after it installs an application, and ++:djadmin:`flush` command. + + Any handlers that listen to this signal need to be written in a particular + place: a ``management`` module in one of your :setting:`INSTALLED_APPS`. If + handlers are registered anywhere else they may not be loaded by +-:djadmin:`syncdb`. ++:djadmin:`syncdb`. It is important that handlers of this signal perform ++idempotent changes (e.g. no database alterations) as this may cause the ++:djadmin:`flush` management command to fail if it also ran during the ++:djadmin:`syncdb` command. + + Arguments sent with this signal: + +Index: README +=================================================================== +--- README (revision 16771) ++++ README (revision 17460) +@@ -28,7 +28,7 @@ + To get more help: + + * Join the #django channel on irc.freenode.net. Lots of helpful people +- hang out there. Read the archives at http://botland.oebfare.com/logger/django/. ++ hang out there. Read the archives at http://django-irc-logs.com/. + + * Join the django-users mailing list, or read the archives, at + http://groups.google.com/group/django-users. diff --git a/libre/java-asm2/PKGBUILD b/libre/java-asm2/PKGBUILD deleted file mode 100755 index 4853d79c0..000000000 --- a/libre/java-asm2/PKGBUILD +++ /dev/null @@ -1,76 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> - -_pkgname=asm -pkgname=java-asm2 -_pkgver=2 -pkgver=2.2.3 -pkgrel=4 -pkgdesc="An all purpose Java bytecode manipulation and analysis framework." -arch=('any') -url="http://asm.ow2.org/" -license=('custom:BSD3') -depends=('java-runtime') -makedepends=( - apache-ant - java-ow-util-ant-tasks -) -source=("http://download.forge.objectweb.org/$_pkgname/$_pkgname-$pkgver.tar.gz") - -_M2_LOCALREPO='/usr/share/maven/repository' -_ow_util_ant_tasks='/usr/share/java/ow_util_ant_tasks.jar' -_m2_packages=( - asm - asm-analysis - asm-attrs - asm-commons - asm-tree - asm-util - asm-xml - asm-all) - -build() { - cd "$srcdir/$_pkgname-$pkgver" - - mkdir -p test/lib - - echo "objectweb.ant.tasks.path $_ow_util_ant_tasks" >> build.properties - ant dist - - # This will make package() easier: - cd output/dist/lib - ln -s all/* . -} - -package() { - cd "$srcdir/$_pkgname-$pkgver" - - # Install license file - install -Dm644 LICENSE.txt "$pkgdir/usr/share/licenses/$pkgname/LICENSE" - - # Install documentation - cd output/dist - install -d "$pkgdir/usr/share/doc/$pkgname" - cp -r doc/javadoc/user "$pkgdir/usr/share/doc/$pkgname/javadoc" - cp -r examples "$pkgdir/usr/share/doc/$pkgname/examples" - - # Install Apache Maven modules - cd lib - install -d "$pkgdir"/usr/share/java/asm - for pkg in "${_m2_packages[@]}"; do - dir="$_M2_LOCALREPO"/asm/$pkg/$pkgver - # Create the Maven directory - install -d "$pkgdir$dir" - # Install the files - cp $pkg-$pkgver.* "$pkgdir$dir" - # Symlink them to /usr/share/java - ln -s "$dir"/$pkg-$pkgver.jar "$pkgdir"/usr/share/java/asm/ - ln -s asm/$pkg-$pkgver.jar "$pkgdir"/usr/share/java/$pkg-$_pkgver.jar - done - - # Install a README file about the -all files - cd "$srcdir/$_pkgname-$pkgver" - install -m644 output/dist/lib/all/README.txt \ - "$pkgdir"/usr/share/java/asm/README-$pkgver.txt -} - -md5sums=('7a92c87bf067925685cf68dcc0dd8998') diff --git a/libre/java-asm3/PKGBUILD b/libre/java-asm3/PKGBUILD deleted file mode 100755 index 7e66a5b5a..000000000 --- a/libre/java-asm3/PKGBUILD +++ /dev/null @@ -1,78 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> - -_pkgname=asm -pkgname=java-asm3 -_pkgver=3 -pkgver=3.3.1 -pkgrel=4.1 -pkgdesc="An all purpose Java bytecode manipulation and analysis framework." -arch=('any') -url="http://asm.ow2.org/" -license=('custom:BSD3') -depends=('java-runtime') -makedepends=( - apache-ant - java-ow-util-ant-tasks -) -source=("http://download.forge.objectweb.org/$_pkgname/$_pkgname-$pkgver.tar.gz") - -_M2_LOCALREPO='/usr/share/maven/repository' -_ow_util_ant_tasks='/usr/share/java/ow_util_ant_tasks.jar' -_m2_packages=( - asm - asm-analysis - asm-commons - asm-parent - asm-tree - asm-util - asm-xml - asm-all - asm-debug-all) - -build() { - cd "$srcdir/$_pkgname-$pkgver" - - rm cobertura.ser # We regenerate this - rm examples/jasmin/test/jasmin.jar - - echo "objectweb.ant.tasks.path $_ow_util_ant_tasks" >> build.properties - ant dist - - # This will make package() easier: - cd output/dist/lib - ln -s all/* . -} - -package() { - cd "$srcdir/$_pkgname-$pkgver" - - # Install license file - install -Dm644 LICENSE.txt "$pkgdir/usr/share/licenses/$pkgname/LICENSE" - - # Install documentation - cd output/dist - install -d "$pkgdir/usr/share/doc/$pkgname" - cp -r doc/javadoc/user "$pkgdir/usr/share/doc/$pkgname/javadoc" - cp -r examples "$pkgdir/usr/share/doc/$pkgname/examples" - - # Install Apache Maven modules - cd lib - install -d "$pkgdir"/usr/share/java/asm - for pkg in "${_m2_packages[@]}"; do - dir="$_M2_LOCALREPO"/asm/$pkg/$pkgver - # Create the Maven directory - install -d "$pkgdir$dir" - # Install the files - cp $pkg-$pkgver.* "$pkgdir$dir" - # Symlink them to /usr/share/java - ln -s "$dir"/$pkg-$pkgver.jar "$pkgdir"/usr/share/java/asm/ - ln -s asm/$pkg-$pkgver.jar "$pkgdir"/usr/share/java/$pkg-$_pkgver.jar - done - - # Install a README file about the -all files - cd "$srcdir/$_pkgname-$pkgver" - install -m644 output/dist/lib/all/README.txt \ - "$pkgdir"/usr/share/java/asm/README-$pkgver.txt -} - -md5sums=('433024df8176f09922646316e415631c') diff --git a/libre/java-ow-util-ant-tasks/PKGBUILD b/libre/java-ow-util-ant-tasks/PKGBUILD deleted file mode 100755 index 023048188..000000000 --- a/libre/java-ow-util-ant-tasks/PKGBUILD +++ /dev/null @@ -1,27 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> - -pkgname=java-ow-util-ant-tasks -pkgver=1.3.2 -pkgrel=1 -pkgdesc="ObjectWeb utility Ant tasks library" -arch=('any') -url="http://forge.ow2.org/projects/monolog" -license=('LGPL') -depends=('java-environment') -makedepends=('apache-ant' 'xalan-java' 'java-asm2') -source=("http://repo.parabolagnulinux.org/sources/${pkgname}-${pkgver}-1-any.src.tar.xz") - -build() { - cd "$srcdir/$pkgname-$pkgver" - ln -s /usr/share/java/asm-2.jar externals - ln -s /usr/share/java/xalan.jar externals - ant jar -} - -package() { - cd "$srcdir/$pkgname-$pkgver" - install -d "$pkgdir"/usr/share/java - install -m644 "output/lib/ow_util_ant_tasks.jar" "$pkgdir"/usr/share/java -} - -md5sums=('339b3eb4b2960473a42f5f781afbeca6') diff --git a/libre/java-ow-util-ant-tasks/SRCBUILD b/libre/java-ow-util-ant-tasks/SRCBUILD deleted file mode 100755 index 01241907d..000000000 --- a/libre/java-ow-util-ant-tasks/SRCBUILD +++ /dev/null @@ -1,29 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> - -pkgname=java-ow-util-ant-tasks -pkgver=1.3.2 -pkgrel=1 -pkgdesc="ObjectWeb utility Ant tasks library" -arch=('any') -url="http://forge.ow2.org/projects/monolog" -license=('LGPL') -source=("http://download.forge.objectweb.org/monolog/ow_util_ant_tasks_$pkgver.zip") -noextract=("ow_util_ant_tasks_$pkgver.zip") - -build() { - cd "$srcdir" - mkdir $pkgname-$pkgver - cd $pkgname-$pkgver - bsdtar xf "$srcdir"/ow_util_ant_tasks_$pkgver.zip - rm -rf output - rm externals/* -} - - -package() { - PKGEXT=${SRCEXT} - PKGDEST=${SRCDEST} - cp -a "$srcdir/$pkgname-$pkgver" "$pkgdir/" -} - -md5sums=('cd602bf75a0feab480fa97739955b84e') diff --git a/libre/maven-libre/PKGBUILD b/libre/maven-libre/PKGBUILD deleted file mode 100755 index 2bd99940e..000000000 --- a/libre/maven-libre/PKGBUILD +++ /dev/null @@ -1,76 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> -# Maintainer (Arch): Sergej Pupykin <pupykin.s+arch@gmail.com> -# Contributor: William Rea <sillywilly@gmail.com> - -_pkgname=maven -pkgname=maven-libre -pkgver=3.0.4 - -provides=("$_pkgname=$pkgver") -replaces=("$_pkgname") -conflicts=("$_pkgname") - -pkgrel=1 -pkgdesc="A Java project management and project comprehension tool" -arch=('any') -url="http://maven.apache.org" -license=('Apache') -depends=('java-environment') -makedepends=('apache-ant') -backup=('etc/maven/settings.xml') - -_mirror=http://archive.apache.org/dist -source=($_mirror/maven/source/apache-maven-$pkgver-src.tar.gz - maven.sh maven.csh) - -_M2_LOCALREPO="/usr/share/maven/repository" - -# FIXME: This also does tasks for package() -build() { - cd $srcdir/apache-maven-$pkgver - - . /etc/profile.d/jre.sh - . /etc/profile.d/jdk.sh - - export MAVEN_OPTS=-Xmx512m - export M2_HOME="$pkgdir"/opt/maven - export PATH="$PATH:$M2_HOME/bin" - - # FIXME: Downloads many deps from Internet. They should be - # packaged separately and added to depends=() - install -d "$pkgdir`dirname $_M2_LOCALREPO`" - cp -r $_M2_LOCALREPO "$pkgdir$_M2_LOCALREPO" - install -d "$pkgdir"/opt - ant -Dmaven.repo.local="$pkgdir$_M2_LOCALREPO" - rm "$pkgdir"/opt/maven/*.txt -} - -package() { - install -d "$pkgdir$_M2_LOCALREPO" - - # Install config file in /etc - # Unlike the other directories, we symlink from the system to /opt/maven - # because that way all conf files stay in /etc - install -d "$pkgdir"/etc/maven - sed "55i<localRepository>$_M2_LOCALREPO</localRepository>" \ - < "$pkgdir"/opt/maven/conf/settings.xml \ - > "$pkgdir"/etc/maven/settings.xml - rm -rf "$pkgdir"/opt/maven/conf - ln -s /etc/maven "$pkgdir"/opt/maven/conf - - # Install profile.d settings - install -d "$pkgdir"/etc/profile.d - install -m 755 "$srcdir"/maven.{csh,sh} "$pkgdir"/etc/profile.d - - # Link executables to /usr/bin - install -d "$pkgdir"/usr/bin - ln -s /opt/maven/bin/{mvn,mvnDebug,mvnyjp} "$pkgdir"/usr/bin - - # Link jar files to appropriate place in /usr/share - install -d "$pkgdir"/usr/share/java - ln -s /opt/maven/lib "$pkgdir"/usr/share/java/maven -} - -md5sums=('17ca94d5be05a78c6ab12425b7a0ee10' - '58820067a4d7384477daa134023d9b57' - 'e2bbdeffed100cd51d05b2ba8ebd6321') diff --git a/libre/maven-libre/maven.csh b/libre/maven-libre/maven.csh deleted file mode 100755 index f5750cfc8..000000000 --- a/libre/maven-libre/maven.csh +++ /dev/null @@ -1,2 +0,0 @@ -setenv MAVEN_OPTS -Xmx512m -setenv M2_HOME=/opt/maven diff --git a/libre/maven-libre/maven.sh b/libre/maven-libre/maven.sh deleted file mode 100755 index b6655cc22..000000000 --- a/libre/maven-libre/maven.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -export MAVEN_OPTS=-Xmx512m -export M2_HOME=/opt/maven diff --git a/libre/parabolaweb-git/Makefile b/libre/parabolaweb-git/Makefile deleted file mode 100755 index 55115aba3..000000000 --- a/libre/parabolaweb-git/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -all: - makepkg - -python_packages=south -python2_packages=markdown|psycopg2|pyinotify|pytz -requirements= https://projects.parabolagnulinux.org/parabolaweb.git/plain/requirements_prod.txt - -requirements_prod.txt: WEB - rm -f $@ - wget --no-check-certificate $(requirements) - -deps-ver.txt: requirements_prod.txt - sed -r -e 's/.*/\L&/' -e 's/==/=/' \ - -e 's/^(${python_packages})/python-&/' \ - -e 's/^(${python2_packages})/python2-&/' $< >$@ - -deps-nover.txt: deps-ver.txt - sed 's/[<>=].*//' $< >$@ - -clean: - rm requirements_prod.txt deps-ver.txt deps-nover.txt - -WEB: FORCE -FORCE: PHONY -PHONY: -.PHONY: PHONY diff --git a/libre/parabolaweb-git/PKGBUILD b/libre/parabolaweb-git/PKGBUILD deleted file mode 100755 index 4641ea8d3..000000000 --- a/libre/parabolaweb-git/PKGBUILD +++ /dev/null @@ -1,43 +0,0 @@ -# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> - -pkgname=parabolaweb-git -pkgver=20120506 -pkgrel=3 -pkgdesc="The Parabola website, fork of archweb" -arch=('any') -url="https://projects.parabolagnulinux.org/parabolaweb.git/" -license=('GPL2') - -_deps_file=deps-ver.txt -#_deps_file=deps-nover.txt -make "$_deps_file" 1>&2 -depends=('python2' 'git' 'libretools' `cat $_deps_file`) - -source=('parabolaweb.init.sh' 'parabolaweb.update.sh.in') - -# These will make it install into /http/srv/web -_install_dir=/srv/http -_gitname=web - -_gitroot=https://projects.parabolagnulinux.org/parabolaweb.git -_gitbranch="master" - -build() { - cd "${srcdir}" - sed \ - -e "s|^_install_dir=.*|_install_dir='$_install_dir'|" \ - -e "s|^_gitname=.*|_gitname='$_gitname'|" \ - -e "s|^_gitroot=.*|_gitroot='$_gitroot'|" \ - -e "s|^_gitbranch=.*|_gitbranch='$_gitbranch'|" \ - < parabolaweb.update.sh.in > parabolaweb.update.sh -} - -package() { - cd "${srcdir}" - install -d "${pkgdir}/${_install_dir}" - install -Dm755 parabolaweb.init.sh "${pkgdir}/etc/rc.d/parabolaweb" - install -Dm755 parabolaweb.update.sh "${pkgdir}/usr/sbin/parabolaweb.update" -} - -md5sums=('72bc7092e4e50a2aaca8b871644520d9' - 'f495b2e4623691925308cb4a1ec7e5a9') diff --git a/libre/parabolaweb-git/deps-ver.txt b/libre/parabolaweb-git/deps-ver.txt deleted file mode 100755 index 67fe6848b..000000000 --- a/libre/parabolaweb-git/deps-ver.txt +++ /dev/null @@ -1,7 +0,0 @@ -django=1.3.1 -python2-markdown>=2.0.3 -python2-psycopg2 -python-south>=0.7.3 -python2-pyinotify>=0.9.2 -python-memcached>=1.47 -python2-pytz>=2011n diff --git a/libre/parabolaweb-git/parabolaweb.init.sh b/libre/parabolaweb-git/parabolaweb.init.sh deleted file mode 100755 index cb9f2441e..000000000 --- a/libre/parabolaweb-git/parabolaweb.init.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -. /etc/rc.conf -. /etc/rc.d/functions - -HOST=127.0.0.1 -PORT=8090 # 80 is nginx -PIDFILE=/var/run/web/fcgi.pid - -case $1 in -start) - stat_busy "Starting ParabolaWeb" - if [[ -e /srv/http/web/manage.py ]]; then - sudo -u nobody \ - python2 /srv/http/web/manage.py runfcgi \ - host=${HOST} \ - port=${PORT} \ - pidfile=${PIDFILE} \ - --settings=settings - - add_daemon parabolaweb - stat_done - exit 0 - else - stat_fail - exit 1 - fi - ;; - -stop) - stat_busy "Stopping ParabolaWeb" - if [[ -f ${PIDFILE} ]]; then - pid=$(cat ${PIDFILE}) - kill ${pid} - rm_daemon parabolaweb - stat_done - else - stat_fail - exit 1 - fi - ;; - -restart) - $0 stop - $0 start - ;; - -*) - echo "Usage: $0 {start|stop|restart}" >&2 - exit 1 - -esac diff --git a/libre/parabolaweb-git/parabolaweb.update.sh.in b/libre/parabolaweb-git/parabolaweb.update.sh.in deleted file mode 100755 index 8c3aef0f0..000000000 --- a/libre/parabolaweb-git/parabolaweb.update.sh.in +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -set -e - -_install_dir=@INSTALL_DIR@ -_gitname=@GIT_NAME@ - -_gitroot=@GITROOT@ -_gitbranch=@GITBRANCH@ - -. /usr/bin/libremessages - -if [ ! -d "$_install_dir" ]; then - mkdir "$_install_dir" -fi -cd "$_install_dir" - -msg "Connecting to GIT server...." -if [ -d ${_gitname} ] ; then - msg2 "Updating existing tree" - cd ${_gitname} && git pull ${_gitroot} -else - msg2 "Cloning tree" - git clone ${_gitroot} ${_gitname} - cd ${_gitname} -fi -git checkout ${_gitbranch} -msg "GIT checkout done or server timeout" - -msg "Purging old .pyc files...." -find . -name '*.pyc' -delete - -msg "Checking configuration...." -if [ ! -f local_settings.py ]; then - cp local_settings.py.example local_settings.tmp.$$.py - if ${EDITOR:-xdg-open} local_settings.tmp.$$.py; then - mv local_settings.tmp.$$.py local_settings.py - else - rm local_settings.tmp.$$.py - msg "Failed to configure, exiting" - exit 1 - fi - msg "Creating database...." - ./manage.py syncdb -fi - -msg "Purging old .pyc files...." -find . -name '*.pyc' -delete - -msg "Updating database...." -msg2 "Running migrations...." -./manage.py migrate -msg2 "Loading fixtures...." -./manage.py loaddata */fixtures/*.json - -msg "Checking media/admin_media symlink...." -if [ ! -e media/admin-media ]; then - rm media/admin_media - ln -s /usr/lib/python2.7/site-packages/django/contrib/admin/media media/admin_media -fi diff --git a/libre/parabolaweb-git/requirements_prod.txt b/libre/parabolaweb-git/requirements_prod.txt deleted file mode 100755 index 78eb51250..000000000 --- a/libre/parabolaweb-git/requirements_prod.txt +++ /dev/null @@ -1,7 +0,0 @@ -Django==1.3.1 -Markdown>=2.0.3 -psycopg2 -South>=0.7.3 -pyinotify>=0.9.2 -python-memcached>=1.47 -pytz>=2011n diff --git a/libre/parabolaweb-utils/PKGBUILD b/libre/parabolaweb-utils/PKGBUILD new file mode 100644 index 000000000..cfb39d703 --- /dev/null +++ b/libre/parabolaweb-utils/PKGBUILD @@ -0,0 +1,46 @@ +# Maintainer: Luke Shumaker <lukeshu@sbcglobal.net> + +. helper.sh +# provides: +# _get_pkgver +# _get_depends +# _get_depends_nover (no version requirements) + +pkgname=parabolaweb-utils +pkgver=`_get_pkgver` +pkgrel=2 +pkgdesc="Utils for the Parabola website" +arch=('any') +url="https://projects.parabolagnulinux.org/parabolaweb.git/" +license=('GPL2') +depends=('python2' 'python2-flup' 'git' 'libretools' `_get_depends`) +backup=('etc/conf.d/parabolaweb') + +export pkgver + +source=(git://parabolagnulinux.org/parabolaweb.git + parabolaweb-update + parabolaweb-fcgi + parabolaweb.rc + parabolaweb.service + parabolaweb.conf) + +build() { + : +} + +package() { + cd "${srcdir}" + install -Dm755 parabolaweb-update "${pkgdir}/usr/sbin/parabolaweb-update" + install -Dm755 parabolaweb-fcgi "${pkgdir}/usr/sbin/parabolaweb-fcgi" + install -Dm755 parabolaweb.rc "${pkgdir}/etc/rc.d/parabolaweb" + install -Dm644 parabolaweb.service "${pkgdir}/usr/lib/systemd/system/parabolaweb.service" + install -Dm644 parabolaweb.conf "${pkgdir}/etc/conf.d/parabolaweb" +} + +md5sums=('SKIP' + 'dd05d6a4ea7cff7fdd789f59aeb9059a' + '520e20b8bbca64042b3afa76b0bec55f' + '1bce8fb832ad9e61cf8b96426ce843b5' + 'c7e292d2d1c3e846e5cfcd7283de0fe4' + 'fb291168d3f57a85f82216c4e74c9ccf') diff --git a/libre/parabolaweb-utils/helper.sh b/libre/parabolaweb-utils/helper.sh new file mode 100644 index 000000000..5ce4182b3 --- /dev/null +++ b/libre/parabolaweb-utils/helper.sh @@ -0,0 +1,39 @@ +_mksource() { + if [[ -z _DO_NOT_RUN_MKSOURCE ]]; then + _DO_NOT_RUN_MKSOURCE=true makepkg -o + fi +} + +_get_pkgver() { + if [[ -n $pkgver ]] && [[ $pkgver != 0.bogus ]]; then + echo $pkgver + else + _mksource 1>&2 + if [[ -f "${srcdir:-src}/parabolaweb/requirements_prod.txt" ]]; then + pushd "${srcdir:-src}/parabolaweb" >/dev/null + # get the date requirements_prod.txt was last modified + gitdate="$(git log -n1 --date=iso --format=format:'%cd' ./requirements_prod.txt)" + date -u +%Y%m%d.%H%M -d "$gitdate" + popd >/dev/null + else + echo 0.bogus + fi + fi +} + +_get_depends() { + _mksource 1>&2 + if [[ -f "${srcdir:-src}/parabolaweb/requirements_prod.txt" ]]; then + pushd "${srcdir:-src}" >/dev/null + python2_packages='markdown|psycopg2|pyinotify|pytz|south' + < parabolaweb/requirements_prod.txt sed -r \ + -e 's/.*/\L&/' -e 's/==/=/' \ + -e 's/^python-memcached/python2-memcached/' \ + -e "s/^(${python2_packages})/python2-&/" + popd >/dev/null + fi +} + +_get_depends_nover() { + _get_depends | sed 's/[<>=].*//' +} diff --git a/libre/parabolaweb-utils/parabolaweb-fcgi b/libre/parabolaweb-utils/parabolaweb-fcgi new file mode 100644 index 000000000..3dec02e10 --- /dev/null +++ b/libre/parabolaweb-utils/parabolaweb-fcgi @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +. /etc/conf.d/parabolaweb + +[[ -e /srv/http/web/manage.py ]] + +sudo -u "${WEBUSER:-$USER}" python2 /srv/http/web/manage.py runfcgi \ + host=${HOST} \ + port=${PORT} \ + --settings=settings \ + "$@" diff --git a/libre/parabolaweb-utils/parabolaweb-update b/libre/parabolaweb-utils/parabolaweb-update new file mode 100644 index 000000000..e4d65c2d9 --- /dev/null +++ b/libre/parabolaweb-utils/parabolaweb-update @@ -0,0 +1,81 @@ +#!/bin/bash +set -e + +_install_dir=/srv/http +_gitname=web +_gitroot=git://parabolagnulinux.org/parabolaweb.git +_gitbranch=master + +. /usr/bin/libremessages + +download() { + msg "Connecting to GIT server...." + cd "$_install_dir" + if [[ -d ${_gitname} ]]; then + msg2 "Updating existing tree" + cd ${_gitname} && git pull ${_gitroot} + else + msg2 "Cloning tree" + git clone ${_gitroot} ${_gitname} + cd ${_gitname} + fi + git checkout ${_gitbranch} + msg "GIT checkout done or server timeout" +} + +clean() { + msg "Purging old .pyc files...." + cd "$_install_dir/$_gitname" + find . -name '*.pyc' -delete +} + +configure() { + msg "Checking configuration...." + cd "$_install_dir/$_gitname" + if [[ ! -f local_settings.py ]]; then + msg2 "Configuration file missing, opening editor..." + cp local_settings.py.example local_settings.tmp.$$.py + if "$EDITOR" local_settings.tmp.$$.py; then + mv local_settings.tmp.$$.py local_settings.py + else + rm local_settings.tmp.$$.py + msg "Failed to configure, exiting" + exit 1 + fi + msg2 "Creating database...." + ./manage.py syncdb + else + msg2 "Current configuration checks out" + fi +} + +migrate() { + msg "Updating database...." + msg2 "Running migrations...." + ./manage.py migrate + msg2 "Loading fixtures...." + ./manage.py loaddata */fixtures/*.json +} + +main() { + if [[ -z "$EDITOR" ]]; then + error 'Please set the $EDITOR variable' + exit 1 + fi + + [[ ! -d "$_install_dir" ]] && mkdir "$_install_dir" + + download + clean + configure + clean + migrate + + msg "Checking media/admin_media symlink...." + if [ ! -e media/admin-media ]; then + rm media/admin_media + ln -s /usr/lib/python2.7/site-packages/django/contrib/admin/media media/admin_media + fi +} + +main "$@" diff --git a/libre/parabolaweb-utils/parabolaweb.conf b/libre/parabolaweb-utils/parabolaweb.conf new file mode 100644 index 000000000..c53b19cb8 --- /dev/null +++ b/libre/parabolaweb-utils/parabolaweb.conf @@ -0,0 +1,3 @@ +HOST=127.0.0.1 +PORT=8090 # 80 is nginx +WEBUSER=nobody diff --git a/libre/parabolaweb-utils/parabolaweb.rc b/libre/parabolaweb-utils/parabolaweb.rc new file mode 100644 index 000000000..087a3fcb0 --- /dev/null +++ b/libre/parabolaweb-utils/parabolaweb.rc @@ -0,0 +1,43 @@ +#!/bin/bash + +. /etc/rc.conf +. /etc/rc.d/functions + +PIDFILE=/run/web/parabolaweb.pid + +case $1 in +start) + stat_busy "Starting ParabolaWeb" + if parabolaweb-fcgi pidfile=${PIDFILE}; then + add_daemon parabolaweb + stat_done + exit 0 + else + stat_fail + exit 1 + fi + ;; + +stop) + stat_busy "Stopping ParabolaWeb" + if [[ -f ${PIDFILE} ]]; then + pid=$(cat ${PIDFILE}) + kill ${pid} + rm_daemon parabolaweb + stat_done + else + stat_fail + exit 1 + fi + ;; + +restart) + $0 stop + $0 start + ;; + +*) + echo "Usage: $0 {start|stop|restart}" >&2 + exit 1 + +esac diff --git a/libre/parabolaweb-utils/parabolaweb.service b/libre/parabolaweb-utils/parabolaweb.service new file mode 100644 index 000000000..d145e53d8 --- /dev/null +++ b/libre/parabolaweb-utils/parabolaweb.service @@ -0,0 +1,10 @@ +[Unit] +Description=ParabolaWeb + +[Service] +Type=forking +ExecStart=/usr/sbin/parabolaweb-fcgi pidfile=/run/web/parabolaweb.pid +PIDFile=/run/web/parabolaweb.pid + +[Install] +WantedBy=multi-user.target diff --git a/libre/tp_smapi-libre-lts/PKGBUILD b/libre/tp_smapi-libre-lts/PKGBUILD new file mode 100644 index 000000000..91ae34864 --- /dev/null +++ b/libre/tp_smapi-libre-lts/PKGBUILD @@ -0,0 +1,60 @@ +# Maintainer: Lukas Fleischer <archlinux at cryptocrack dot de> +# Contributor: xduugu +# Contributor: nh2 +# Contributor: Steven Davidovitz <steviedizzle ð gmail đ com> +# Contributor: Nick B <Shirakawasuna ð gmail đ com> +# Contributor: Christof Musik <christof ð senfdax đ de> +# Contributor: Stefan Rupp <archlinux ð stefanrupp đ de> +# Contributor: Ignas Anikevicius <anikevicius ð gmail đ com> +# Maintainer (Parabola): André Silva <emulatorman@lavabit.com> + +pkgname=tp_smapi-libre-lts +_pkgname=tp_smapi +_extramodules=/usr/lib/modules/extramodules-3.0-LIBRE-LTS +pkgver=0.41 +pkgrel=9 +pkgdesc="linux-libre-lts modules for ThinkPad's SMAPI functionality" +arch=('i686' 'x86_64') +url='https://github.com/evgeni/tp_smapi' +license=('GPL') +depends=('linux-libre-lts>=3.0' 'linux-libre-lts<3.1') +makedepends=('linux-libre-lts-headers>=3.0' 'linux-libre-lts-headers<3.1') +replaces=('tp_smapi-lts') +conflicts=('tp_smapi-lts') +provides=("tp_smapi-lts=${pkgver}") +install='tp_smapi-lts.install' +source=("https://github.com/downloads/evgeni/${_pkgname}/${_pkgname}-${pkgver}.tar.gz") +md5sums=('63c683415c764568f6bf17c7eabe4752') + +build() { + cd "${srcdir}/${_pkgname}-${pkgver}" + + _kernver=$(< "${_extramodules}/version") + + sed -ri -e "s/^(KVER\s*:=).*$/\1 ${_kernver}/" \ + -e "s#^(KBASE\s*:=).*\$#\1 ${_extramodules%/*}/${_kernver}#" Makefile + + make HDAPS=1 +} + +package() { + _kernver=$(< "${_extramodules}/version") + + make -C "${_extramodules%/*}/${_kernver}/build" \ + INSTALL_MOD_PATH="${pkgdir}/${_extramodules%%/lib/*}" \ + M="${srcdir}/${_pkgname}-${pkgver}" modules_install + + cd "${pkgdir}/${_extramodules%/*}" + mv "${_kernver}/extra" "${_extramodules##*/}" + rmdir "${_kernver}" + + # compress kernel modules + find "${pkgdir}" -name "*.ko" -exec gzip -9 {} + + + # load module on startup + echo tp_smapi > "${srcdir}/tp_smapi-lts.conf" + install -Dm644 "${srcdir}/tp_smapi-lts.conf" "${pkgdir}/usr/lib/modules-load.d/tp_smapi-lts.conf" + + # update kernel version in install file + sed -ri "s#^(extramodules=).*\$#\1${_extramodules}#" "${startdir}/tp_smapi-lts.install" +} diff --git a/libre/tp_smapi-libre-lts/tp_smapi-lts.install b/libre/tp_smapi-libre-lts/tp_smapi-lts.install new file mode 100644 index 000000000..2723fead7 --- /dev/null +++ b/libre/tp_smapi-libre-lts/tp_smapi-lts.install @@ -0,0 +1,13 @@ +extramodules=/usr/lib/modules/extramodules-3.0-LIBRE-LTS + +post_install() { + depmod -v $(< "$extramodules/version") &>/dev/null +} + +post_upgrade() { + post_install +} + +post_remove() { + post_install +} diff --git a/libre/virtualbox-libre-modules-lts/PKGBUILD b/libre/virtualbox-libre-modules-lts/PKGBUILD index dff627829..7a95b4c7b 100644 --- a/libre/virtualbox-libre-modules-lts/PKGBUILD +++ b/libre/virtualbox-libre-modules-lts/PKGBUILD @@ -7,8 +7,8 @@ pkgbase=virtualbox-libre-modules-lts pkgname=('virtualbox-libre-host-modules-lts' 'virtualbox-libre-guest-modules-lts') -pkgver=4.2.0 -pkgrel=3.1 +pkgver=4.2.2 +pkgrel=1 arch=('i686' 'x86_64') url='http://virtualbox.org' license=('GPL') @@ -40,8 +40,7 @@ package_virtualbox-libre-host-modules-lts(){ install=virtualbox-libre-host-modules-lts.install _kernver=$(expac -Q '%v' linux-libre-lts-headers)-LIBRE-LTS - #_extraver=extramodules-${_kernver%.*}-LIBRE-LTS - _extraver=extramodules-3.0-LIBRE-LTS + _extraver=extramodules-${_kernver%.*}-LIBRE-LTS install -dm755 "$pkgdir/usr/lib/modules/$_extraver" cd "dkms/vboxhost/$pkgver/$_kernver/$CARCH/module" @@ -60,8 +59,7 @@ package_virtualbox-libre-guest-modules-lts(){ install=virtualbox-libre-guest-modules-lts.install _kernver=$(expac -Q '%v' linux-libre-lts-headers)-LIBRE-LTS - #_extraver=extramodules-${_kernver%.*}-LIBRE-LTS - _extraver=extramodules-3.0-LIBRE-LTS + _extraver=extramodules-${_kernver%.*}-LIBRE-LTS install -dm755 "$pkgdir/usr/lib/modules/$_extraver" cd "dkms/vboxguest/$pkgver/$_kernver/$CARCH/module" diff --git a/libre/virtualbox-libre-modules/PKGBUILD b/libre/virtualbox-libre-modules/PKGBUILD index 10182a0e9..3fcbd7069 100755 --- a/libre/virtualbox-libre-modules/PKGBUILD +++ b/libre/virtualbox-libre-modules/PKGBUILD @@ -6,8 +6,8 @@ pkgbase=virtualbox-libre-modules pkgname=('virtualbox-libre-host-modules' 'virtualbox-libre-guest-modules') -pkgver=4.2.0 -pkgrel=6.1 +pkgver=4.2.2 +pkgrel=1 arch=('i686' 'x86_64') url='http://virtualbox.org' license=('GPL') diff --git a/libre/virtualbox-libre/vboxdrv-reference.patch b/libre/virtualbox-libre/001-vboxdrv-reference.patch index 51fd6361c..51fd6361c 100644 --- a/libre/virtualbox-libre/vboxdrv-reference.patch +++ b/libre/virtualbox-libre/001-vboxdrv-reference.patch diff --git a/libre/virtualbox-libre/change_default_driver_dir.patch b/libre/virtualbox-libre/002-change_default_driver_dir.patch index d8531499d..d8531499d 100755 --- a/libre/virtualbox-libre/change_default_driver_dir.patch +++ b/libre/virtualbox-libre/002-change_default_driver_dir.patch diff --git a/libre/virtualbox-libre/003-remove_qt_fa_IR.patch b/libre/virtualbox-libre/003-remove_qt_fa_IR.patch new file mode 100644 index 000000000..58e6235d5 --- /dev/null +++ b/libre/virtualbox-libre/003-remove_qt_fa_IR.patch @@ -0,0 +1,23 @@ +# seblu 10/2012 - fucking farci removing patch + +--- a/src/VBox/Frontends/VirtualBox/nls/ApprovedLanguages.kmk 2012-10-18 16:22:52.000000000 +0200 ++++ b/src/VBox/Frontends/VirtualBox/nls/ApprovedLanguages.kmk 2012-10-19 03:03:52.640867388 +0200 +@@ -23,7 +23,6 @@ + de \ + en \ + es \ +- fa_IR \ + hu \ + it \ + ja \ + +--- a/src/VBox/Frontends/VirtualBox/VBoxUI.pro 2012-10-18 16:22:47.000000000 +0200 ++++ b/src/VBox/Frontends/VirtualBox/VBoxUI.pro 2012-10-20 02:48:37.525765901 +0200 +@@ -63,7 +63,6 @@ + nls/VirtualBox_es.ts \ + nls/VirtualBox_eu.ts \ + nls/VirtualBox_fi.ts \ +- nls/VirtualBox_fa_IR.ts \ + nls/VirtualBox_fr.ts \ + nls/VirtualBox_gl_ES.ts \ + nls/VirtualBox_hu.ts \ diff --git a/libre/virtualbox-libre/PKGBUILD b/libre/virtualbox-libre/PKGBUILD index 5ae72a76f..9e1d74cac 100755 --- a/libre/virtualbox-libre/PKGBUILD +++ b/libre/virtualbox-libre/PKGBUILD @@ -12,8 +12,8 @@ pkgname=('virtualbox-libre' 'virtualbox-libre-host-source' 'virtualbox-libre-guest-utils' 'virtualbox-libre-guest-source') -pkgver=4.2.0 -pkgrel=4.1 +pkgver=4.2.2 +pkgrel=1 arch=('i686' 'x86_64') url='http://virtualbox.org' license=('GPL' 'custom') @@ -56,8 +56,9 @@ source=("http://download.virtualbox.org/virtualbox/$pkgver/VirtualBox-$pkgver.ta 'vboxweb.conf' 'vboxweb.rc' 'vboxweb.service' - 'change_default_driver_dir.patch' - 'vboxdrv-reference.patch' + '001-vboxdrv-reference.patch' + '002-change_default_driver_dir.patch' + '003-remove_qt_fa_IR.patch' 'os_blag_64.png' 'os_blag.png' 'os_dragora_64.png' @@ -78,7 +79,7 @@ source=("http://download.virtualbox.org/virtualbox/$pkgver/VirtualBox-$pkgver.ta 'os_venenux.png' 'libre.patch' 'free-distros.patch') -md5sums=('691b4134983ce7d89b9fb683305cb647' +md5sums=('2b65dcd9649e56ac6338670b3fb4a14d' '5f85710e0b8606de967716ded7b2d351' 'ed1341881437455d9735875ddf455fbe' '58d6e5bb4b4c1c6f3f0b3daa6aaeed03' @@ -88,8 +89,9 @@ md5sums=('691b4134983ce7d89b9fb683305cb647' '7e9483b1069a54f181546083ac7e5469' 'c159d683ba1947290fc2ad2c64194150' 'bc9efed88e0469cd7fc460d5a5cd7b4b' - '97e193f050574dd272a38e5ee5ebe62b' '4f1692638d6740df4c4ad9766ba4e179' + '97e193f050574dd272a38e5ee5ebe62b' + '866ce76a94fb22cc7b625e07e571f0ad' '8538dba8686d7449cb481c9bae9d722a' '545c925b46f2ac95e5f8ae407fad101a' 'f6416f509c2e5460e4dc624e0a57f3c1' @@ -108,7 +110,7 @@ md5sums=('691b4134983ce7d89b9fb683305cb647' 'c7951fe6888d939f3a7d0dafe477e82b' '4da8eeb2ece7e475fc7a0d1003da26c6' '5e4187af59726d71c5be48d0cd816c34' - '67cc4c8611890038eb3e4114ae899525' + '85141ccd2621a8e004b8f55c9a1f83eb' 'c7b29fbf4c24a00e8646ca6dd73f38a1') #_extramodules=extramodules-3.5-LIBRE @@ -117,15 +119,21 @@ md5sums=('691b4134983ce7d89b9fb683305cb647' build() { cd "VirtualBox-$pkgver" - patch -Np1 -i "$srcdir/vboxdrv-reference.patch" - patch -Np1 -i "$srcdir/change_default_driver_dir.patch" - patch -Np1 -i "$srcdir/libre.patch" - patch -Np1 -i "$srcdir/free-distros.patch" + # Apply patches + for _p in "$srcdir"/*.patch; do + [[ -e $_p ]] || continue + msg2 "Apply patch ${_p##*/}" + patch -Np1 -i "$_p" + done - ## Removing Nonfree directories + ## Removing Nonfree directories and Nonfree files rm -rv "./include/VBox/ExtPack" rm -rv "./src/VBox/ExtPacks" rm -rv "./src/VBox/Main/src-helper-apps" + rm -rv "./src/VBox/Main/include/ExtPackManagerImpl.h" + rm -rv "./src/VBox/Main/include/ExtPackUtil.h" + rm -rv "./src/VBox/Main/src-all/ExtPackManagerImpl.cpp" + rm -rv "./src/VBox/Main/src-all/ExtPackUtil.cpp" ## Removing Oracle VM VirtualBox Extension Pack icons rm -v "./src/VBox/Resources/darwin/virtualbox-vbox-extpack.icns" @@ -148,7 +156,7 @@ build() { --enable-webservice \ --enable-vde \ --enable-vnc \ - --disable-kmods + --disable-kmods # --with-linux=/usr/src/linux-${_kernver} source ./env.sh kmk all @@ -228,7 +236,7 @@ package_virtualbox-libre() { echo 'INSTALL_DIR=/usr/lib/virtualbox' > "$pkgdir/etc/vbox/vbox.cfg" #udev and licence - install -D -m 0644 "$srcdir/VirtualBox-$pkgver/COPYING" \ + install -D -m 0644 "$srcdir/VirtualBox-${pkgver}/COPYING" \ "$pkgdir/usr/share/licenses/virtualbox/LICENSE" install -D -m 0644 "$srcdir/10-vboxdrv.rules" \ "$pkgdir/usr/lib/udev/rules.d/10-vboxdrv.rules" @@ -333,3 +341,5 @@ package_virtualbox-libre-guest-utils(){ install -D -m644 vboxservice.service \ "$pkgdir/usr/lib/systemd/system/vboxservice.service" } + +# vim:set ts=4 sw=4 et: diff --git a/libre/virtualbox-libre/gsoap.patch b/libre/virtualbox-libre/gsoap.patch deleted file mode 100755 index c49caa720..000000000 --- a/libre/virtualbox-libre/gsoap.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- configure.orig 2012-03-14 08:40:02.447527213 +0000 -+++ configure 2012-03-14 09:05:01.535432453 +0000 -@@ -1959,7 +1959,7 @@ - else - cnf_append "VBOX_GSOAP_CXX_SOURCES" "" - fi -- cnf_append "VBOX_GSOAP_CXX_LIBS" "libgsoap++" -+ cnf_append "VBOX_GSOAP_CXX_LIBS" "libgsoapssl++ libz" - log_success "found" - else - log_failure "stlvector.h not found -- disabling webservice" diff --git a/libre/virtualbox-libre/ipv6_vnc.patch b/libre/virtualbox-libre/ipv6_vnc.patch deleted file mode 100755 index 8f50aba1c..000000000 --- a/libre/virtualbox-libre/ipv6_vnc.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -aur vanilla/VirtualBox-4.1.18/src/VBox/Frontends/VBoxHeadless/FramebufferVNC.cpp changed/VirtualBox-4.1.18/src/VBox/Frontends/VBoxHeadless/FramebufferVNC.cpp ---- vanilla/VirtualBox-4.1.18/src/VBox/Frontends/VBoxHeadless/FramebufferVNC.cpp 2012-06-20 15:15:53.000000000 +0200 -+++ changed/VirtualBox-4.1.18/src/VBox/Frontends/VBoxHeadless/FramebufferVNC.cpp 2012-07-16 16:24:22.448349886 +0200 -@@ -88,8 +88,16 @@ - - vncServer = rfbGetScreen(0, NULL, mWidth, mHeight, 8, 3, 1); - vncServer->screenData = (void*)this; -+#ifdef LIBVNCSERVER_IPv6 -+ if (mVncPort) { -+ vncServer->port = mVncPort; -+ vncServer->ipv6port = mVncPort; -+ } -+#else - if (mVncPort) - vncServer->port = mVncPort; -+#endif -+ - char *pszDesktopName; - rc = RTStrAPrintf(&pszDesktopName, "%s - VirtualBox", pszName); - if (rc >= 0) diff --git a/libre/virtualbox-libre/libre.patch b/libre/virtualbox-libre/libre.patch index 41a34fc84..138bbd612 100755 --- a/libre/virtualbox-libre/libre.patch +++ b/libre/virtualbox-libre/libre.patch @@ -484,4913 +484,6 @@ extern const PDMDEVREG g_DeviceACPI; extern const PDMDEVREG g_DeviceDMA; extern const PDMDEVREG g_DeviceFloppyController; ---- VirtualBox-4.2.0.orig/src/VBox/Main/include/ExtPackManagerImpl.h 2012-03-13 11:51:50.000000000 -0300 -+++ /dev/null 2012-09-18 22:18:48.866734195 -0300 -@@ -1,247 +0,0 @@ --/* $Id: ExtPackManagerImpl.h 39878 2012-01-25 16:30:07Z vboxsync $ */ --/** @file -- * VirtualBox Main - interface for Extension Packs, VBoxSVC & VBoxC. -- */ -- --/* -- * Copyright (C) 2010 Oracle Corporation -- * -- * This file is part of VirtualBox Open Source Edition (OSE), as -- * available from http://www.virtualbox.org. This file is free software; -- * you can redistribute it and/or modify it under the terms of the GNU -- * General Public License (GPL) as published by the Free Software -- * Foundation, in version 2 as it comes in the "COPYING" file of the -- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the -- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -- */ -- --#ifndef ____H_EXTPACKMANAGERIMPL --#define ____H_EXTPACKMANAGERIMPL -- --#include "VirtualBoxBase.h" --#include <VBox/ExtPack/ExtPack.h> --#include <iprt/fs.h> -- --/** -- * An extension pack file. -- */ --class ATL_NO_VTABLE ExtPackFile : -- public VirtualBoxBase, -- VBOX_SCRIPTABLE_IMPL(IExtPackFile) --{ --public: -- /** @name COM and internal init/term/mapping cruft. -- * @{ */ -- VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(ExtPackFile, IExtPackFile) -- DECLARE_NOT_AGGREGATABLE(ExtPackFile) -- DECLARE_PROTECT_FINAL_CONSTRUCT() -- BEGIN_COM_MAP(ExtPackFile) -- VBOX_DEFAULT_INTERFACE_ENTRIES(IExtPackFile) -- COM_INTERFACE_ENTRY(IExtPackBase) -- END_COM_MAP() -- DECLARE_EMPTY_CTOR_DTOR(ExtPackFile) -- -- HRESULT FinalConstruct(); -- void FinalRelease(); -- HRESULT initWithFile(const char *a_pszFile, const char *a_pszDigest, class ExtPackManager *a_pExtPackMgr, VirtualBox *a_pVirtualBox); -- void uninit(); -- RTMEMEF_NEW_AND_DELETE_OPERATORS(); -- /** @} */ -- -- /** @name IExtPackBase interfaces -- * @{ */ -- STDMETHOD(COMGETTER(Name))(BSTR *a_pbstrName); -- STDMETHOD(COMGETTER(Description))(BSTR *a_pbstrDescription); -- STDMETHOD(COMGETTER(Version))(BSTR *a_pbstrVersion); -- STDMETHOD(COMGETTER(Revision))(ULONG *a_puRevision); -- STDMETHOD(COMGETTER(Edition))(BSTR *a_pbstrEdition); -- STDMETHOD(COMGETTER(VRDEModule))(BSTR *a_pbstrVrdeModule); -- STDMETHOD(COMGETTER(PlugIns))(ComSafeArrayOut(IExtPackPlugIn *, a_paPlugIns)); -- STDMETHOD(COMGETTER(Usable))(BOOL *a_pfUsable); -- STDMETHOD(COMGETTER(WhyUnusable))(BSTR *a_pbstrWhy); -- STDMETHOD(COMGETTER(ShowLicense))(BOOL *a_pfShowIt); -- STDMETHOD(COMGETTER(License))(BSTR *a_pbstrHtmlLicense); -- STDMETHOD(QueryLicense)(IN_BSTR a_bstrPreferredLocale, IN_BSTR a_bstrPreferredLanguage, -- IN_BSTR a_bstrFormat, BSTR *a_pbstrLicense); -- /** @} */ -- -- /** @name IExtPackFile interfaces -- * @{ */ -- STDMETHOD(COMGETTER(FilePath))(BSTR *a_pbstrPath); -- STDMETHOD(Install)(BOOL a_fReplace, IN_BSTR a_bstrDisplayInfo, IProgress **a_ppProgress); -- /** @} */ -- --private: -- /** @name Misc init helpers -- * @{ */ -- HRESULT initFailed(const char *a_pszWhyFmt, ...); -- /** @} */ -- --private: -- struct Data; -- /** Pointer to the private instance. */ -- Data *m; -- -- friend class ExtPackManager; --}; -- -- --/** -- * An installed extension pack. -- */ --class ATL_NO_VTABLE ExtPack : -- public VirtualBoxBase, -- VBOX_SCRIPTABLE_IMPL(IExtPack) --{ --public: -- /** @name COM and internal init/term/mapping cruft. -- * @{ */ -- VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(ExtPack, IExtPack) -- DECLARE_NOT_AGGREGATABLE(ExtPack) -- DECLARE_PROTECT_FINAL_CONSTRUCT() -- BEGIN_COM_MAP(ExtPack) -- VBOX_DEFAULT_INTERFACE_ENTRIES(IExtPack) -- COM_INTERFACE_ENTRY(IExtPackBase) -- END_COM_MAP() -- DECLARE_EMPTY_CTOR_DTOR(ExtPack) -- -- HRESULT FinalConstruct(); -- void FinalRelease(); -- HRESULT initWithDir(VBOXEXTPACKCTX a_enmContext, const char *a_pszName, const char *a_pszDir); -- void uninit(); -- RTMEMEF_NEW_AND_DELETE_OPERATORS(); -- /** @} */ -- -- /** @name IExtPackBase interfaces -- * @{ */ -- STDMETHOD(COMGETTER(Name))(BSTR *a_pbstrName); -- STDMETHOD(COMGETTER(Description))(BSTR *a_pbstrDescription); -- STDMETHOD(COMGETTER(Version))(BSTR *a_pbstrVersion); -- STDMETHOD(COMGETTER(Revision))(ULONG *a_puRevision); -- STDMETHOD(COMGETTER(Edition))(BSTR *a_pbstrEdition); -- STDMETHOD(COMGETTER(VRDEModule))(BSTR *a_pbstrVrdeModule); -- STDMETHOD(COMGETTER(PlugIns))(ComSafeArrayOut(IExtPackPlugIn *, a_paPlugIns)); -- STDMETHOD(COMGETTER(Usable))(BOOL *a_pfUsable); -- STDMETHOD(COMGETTER(WhyUnusable))(BSTR *a_pbstrWhy); -- STDMETHOD(COMGETTER(ShowLicense))(BOOL *a_pfShowIt); -- STDMETHOD(COMGETTER(License))(BSTR *a_pbstrHtmlLicense); -- STDMETHOD(QueryLicense)(IN_BSTR a_bstrPreferredLocale, IN_BSTR a_bstrPreferredLanguage, -- IN_BSTR a_bstrFormat, BSTR *a_pbstrLicense); -- /** @} */ -- -- /** @name IExtPack interfaces -- * @{ */ -- STDMETHOD(QueryObject)(IN_BSTR a_bstrObjectId, IUnknown **a_ppUnknown); -- /** @} */ -- -- /** @name Internal interfaces used by ExtPackManager. -- * @{ */ -- bool callInstalledHook(IVirtualBox *a_pVirtualBox, AutoWriteLock *a_pLock, PRTERRINFO pErrInfo); -- HRESULT callUninstallHookAndClose(IVirtualBox *a_pVirtualBox, bool a_fForcedRemoval); -- bool callVirtualBoxReadyHook(IVirtualBox *a_pVirtualBox, AutoWriteLock *a_pLock); -- bool callConsoleReadyHook(IConsole *a_pConsole, AutoWriteLock *a_pLock); -- bool callVmCreatedHook(IVirtualBox *a_pVirtualBox, IMachine *a_pMachine, AutoWriteLock *a_pLock); -- bool callVmConfigureVmmHook(IConsole *a_pConsole, PVM a_pVM, AutoWriteLock *a_pLock, int *a_pvrc); -- bool callVmPowerOnHook(IConsole *a_pConsole, PVM a_pVM, AutoWriteLock *a_pLock, int *a_pvrc); -- bool callVmPowerOffHook(IConsole *a_pConsole, PVM a_pVM, AutoWriteLock *a_pLock); -- HRESULT checkVrde(void); -- HRESULT getVrdpLibraryName(Utf8Str *a_pstrVrdeLibrary); -- bool wantsToBeDefaultVrde(void) const; -- HRESULT refresh(bool *pfCanDelete); -- /** @} */ -- --protected: -- /** @name Internal helper methods. -- * @{ */ -- void probeAndLoad(void); -- bool findModule(const char *a_pszName, const char *a_pszExt, VBOXEXTPACKMODKIND a_enmKind, -- Utf8Str *a_ppStrFound, bool *a_pfNative, PRTFSOBJINFO a_pObjInfo) const; -- static bool objinfoIsEqual(PCRTFSOBJINFO pObjInfo1, PCRTFSOBJINFO pObjInfo2); -- /** @} */ -- -- /** @name Extension Pack Helpers -- * @{ */ -- static DECLCALLBACK(int) hlpFindModule(PCVBOXEXTPACKHLP pHlp, const char *pszName, const char *pszExt, -- VBOXEXTPACKMODKIND enmKind, char *pszFound, size_t cbFound, bool *pfNative); -- static DECLCALLBACK(int) hlpGetFilePath(PCVBOXEXTPACKHLP pHlp, const char *pszFilename, char *pszPath, size_t cbPath); -- static DECLCALLBACK(VBOXEXTPACKCTX) hlpGetContext(PCVBOXEXTPACKHLP pHlp); -- static DECLCALLBACK(int) hlpReservedN(PCVBOXEXTPACKHLP pHlp); -- /** @} */ -- --private: -- struct Data; -- /** Pointer to the private instance. */ -- Data *m; -- -- friend class ExtPackManager; --}; -- -- --/** -- * Extension pack manager. -- */ --class ATL_NO_VTABLE ExtPackManager : -- public VirtualBoxBase, -- VBOX_SCRIPTABLE_IMPL(IExtPackManager) --{ -- /** @name COM and internal init/term/mapping cruft. -- * @{ */ -- VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(ExtPackManager, IExtPackManager) -- DECLARE_NOT_AGGREGATABLE(ExtPackManager) -- DECLARE_PROTECT_FINAL_CONSTRUCT() -- BEGIN_COM_MAP(ExtPackManager) -- VBOX_DEFAULT_INTERFACE_ENTRIES(IExtPackManager) -- END_COM_MAP() -- DECLARE_EMPTY_CTOR_DTOR(ExtPackManager) -- -- HRESULT FinalConstruct(); -- void FinalRelease(); -- HRESULT initExtPackManager(VirtualBox *a_pVirtualBox, VBOXEXTPACKCTX a_enmContext); -- void uninit(); -- RTMEMEF_NEW_AND_DELETE_OPERATORS(); -- /** @} */ -- -- /** @name IExtPack interfaces -- * @{ */ -- STDMETHOD(COMGETTER(InstalledExtPacks))(ComSafeArrayOut(IExtPack *, a_paExtPacks)); -- STDMETHOD(Find)(IN_BSTR a_bstrName, IExtPack **a_pExtPack); -- STDMETHOD(OpenExtPackFile)(IN_BSTR a_bstrTarball, IExtPackFile **a_ppExtPackFile); -- STDMETHOD(Uninstall)(IN_BSTR a_bstrName, BOOL a_fForcedRemoval, IN_BSTR a_bstrDisplayInfo, IProgress **a_ppProgress); -- STDMETHOD(Cleanup)(void); -- STDMETHOD(QueryAllPlugInsForFrontend)(IN_BSTR a_bstrFrontend, ComSafeArrayOut(BSTR, a_pabstrPlugInModules)); -- STDMETHOD(IsExtPackUsable(IN_BSTR a_bstrExtPack, BOOL *aUsable)); -- /** @} */ -- -- /** @name Internal interfaces used by other Main classes. -- * @{ */ -- static DECLCALLBACK(int) doInstallThreadProc(RTTHREAD hThread, void *pvJob); -- HRESULT doInstall(ExtPackFile *a_pExtPackFile, bool a_fReplace, Utf8Str const *a_pstrDisplayInfo); -- static DECLCALLBACK(int) doUninstallThreadProc(RTTHREAD hThread, void *pvJob); -- HRESULT doUninstall(const Utf8Str *a_pstrName, bool a_fForcedRemoval, const Utf8Str *a_pstrDisplayInfo); -- void callAllVirtualBoxReadyHooks(void); -- void callAllConsoleReadyHooks(IConsole *a_pConsole); -- void callAllVmCreatedHooks(IMachine *a_pMachine); -- int callAllVmConfigureVmmHooks(IConsole *a_pConsole, PVM a_pVM); -- int callAllVmPowerOnHooks(IConsole *a_pConsole, PVM a_pVM); -- void callAllVmPowerOffHooks(IConsole *a_pConsole, PVM a_pVM); -- HRESULT checkVrdeExtPack(Utf8Str const *a_pstrExtPack); -- int getVrdeLibraryPathForExtPack(Utf8Str const *a_pstrExtPack, Utf8Str *a_pstrVrdeLibrary); -- HRESULT getDefaultVrdeExtPack(Utf8Str *a_pstrExtPack); -- bool isExtPackUsable(const char *a_pszExtPack); -- void dumpAllToReleaseLog(void); -- /** @} */ -- --private: -- HRESULT runSetUidToRootHelper(Utf8Str const *a_pstrDisplayInfo, const char *a_pszCommand, ...); -- ExtPack *findExtPack(const char *a_pszName); -- void removeExtPack(const char *a_pszName); -- HRESULT refreshExtPack(const char *a_pszName, bool a_fUnsuableIsError, ExtPack **a_ppExtPack); -- --private: -- struct Data; -- /** Pointer to the private instance. */ -- Data *m; --}; -- --#endif --/* vi: set tabstop=4 shiftwidth=4 expandtab: */ ---- VirtualBox-4.2.0.orig/src/VBox/Main/include/ExtPackUtil.h 2012-03-13 11:51:50.000000000 -0300 -+++ /dev/null 2012-09-18 22:18:48.866734195 -0300 -@@ -1,137 +0,0 @@ --/* $Id: ExtPackUtil.h 39878 2012-01-25 16:30:07Z vboxsync $ */ --/** @file -- * VirtualBox Main - Extension Pack Utilities and definitions, VBoxC, VBoxSVC, ++. -- */ -- --/* -- * Copyright (C) 2010 Oracle Corporation -- * -- * This file is part of VirtualBox Open Source Edition (OSE), as -- * available from http://www.virtualbox.org. This file is free software; -- * you can redistribute it and/or modify it under the terms of the GNU -- * General Public License (GPL) as published by the Free Software -- * Foundation, in version 2 as it comes in the "COPYING" file of the -- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the -- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -- */ -- --#ifndef ____H_EXTPACKUTIL --#define ____H_EXTPACKUTIL -- --#include <iprt/cpp/ministring.h> --#include <iprt/fs.h> --#include <iprt/vfs.h> -- -- --/** @name VBOX_EXTPACK_DESCRIPTION_NAME -- * The name of the description file in an extension pack. */ --#define VBOX_EXTPACK_DESCRIPTION_NAME "ExtPack.xml" --/** @name VBOX_EXTPACK_DESCRIPTION_NAME -- * The name of the manifest file in an extension pack. */ --#define VBOX_EXTPACK_MANIFEST_NAME "ExtPack.manifest" --/** @name VBOX_EXTPACK_SIGNATURE_NAME -- * The name of the signature file in an extension pack. */ --#define VBOX_EXTPACK_SIGNATURE_NAME "ExtPack.signature" --/** @name VBOX_EXTPACK_LICENSE_NAME_PREFIX -- * The name prefix of a license file in an extension pack. There can be -- * several license files in a pack, the variations being on locale, language -- * and format (HTML, RTF, plain text). All extension packages shall include -- * a */ --#define VBOX_EXTPACK_LICENSE_NAME_PREFIX "ExtPack-license" --/** @name VBOX_EXTPACK_SUFFIX -- * The suffix of a extension pack tarball. */ --#define VBOX_EXTPACK_SUFFIX ".vbox-extpack" -- --/** The minimum length (strlen) of a extension pack name. */ --#define VBOX_EXTPACK_NAME_MIN_LEN 3 --/** The max length (strlen) of a extension pack name. */ --#define VBOX_EXTPACK_NAME_MAX_LEN 64 -- --/** The architecture-dependent application data subdirectory where the -- * extension packs are installed. Relative to RTPathAppPrivateArch. */ --#define VBOX_EXTPACK_INSTALL_DIR "ExtensionPacks" --/** The architecture-independent application data subdirectory where the -- * certificates are installed. Relative to RTPathAppPrivateNoArch. */ --#define VBOX_EXTPACK_CERT_DIR "ExtPackCertificates" -- --/** The maximum entry name length. -- * Play short and safe. */ --#define VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH 128 -- -- --/** -- * Plug-in descriptor. -- */ --typedef struct VBOXEXTPACKPLUGINDESC --{ -- /** The name. */ -- RTCString strName; -- /** The module name. */ -- RTCString strModule; -- /** The description. */ -- RTCString strDescription; -- /** The frontend or component which it plugs into. */ -- RTCString strFrontend; --} VBOXEXTPACKPLUGINDESC; --/** Pointer to a plug-in descriptor. */ --typedef VBOXEXTPACKPLUGINDESC *PVBOXEXTPACKPLUGINDESC; -- --/** -- * Extension pack descriptor -- * -- * This is the internal representation of the ExtPack.xml. -- */ --typedef struct VBOXEXTPACKDESC --{ -- /** The name. */ -- RTCString strName; -- /** The description. */ -- RTCString strDescription; -- /** The version string. */ -- RTCString strVersion; -- /** The edition string. */ -- RTCString strEdition; -- /** The internal revision number. */ -- uint32_t uRevision; -- /** The name of the main module. */ -- RTCString strMainModule; -- /** The name of the VRDE module, empty if none. */ -- RTCString strVrdeModule; -- /** The number of plug-in descriptors. */ -- uint32_t cPlugIns; -- /** Pointer to an array of plug-in descriptors. */ -- PVBOXEXTPACKPLUGINDESC paPlugIns; -- /** Whether to show the license prior to installation. */ -- bool fShowLicense; --} VBOXEXTPACKDESC; -- --/** Pointer to a extension pack descriptor. */ --typedef VBOXEXTPACKDESC *PVBOXEXTPACKDESC; --/** Pointer to a const extension pack descriptor. */ --typedef VBOXEXTPACKDESC const *PCVBOXEXTPACKDESC; -- -- --void VBoxExtPackInitDesc(PVBOXEXTPACKDESC a_pExtPackDesc); --RTCString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo); --RTCString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo); --RTCString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball); --void VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc); --bool VBoxExtPackIsValidName(const char *pszName); --bool VBoxExtPackIsValidMangledName(const char *pszMangledName, size_t cchMax = RTSTR_MAX); --RTCString *VBoxExtPackMangleName(const char *pszName); --RTCString *VBoxExtPackUnmangleName(const char *pszMangledName, size_t cbMax); --int VBoxExtPackCalcDir(char *pszExtPackDir, size_t cbExtPackDir, const char *pszParentDir, const char *pszName); --bool VBoxExtPackIsValidVersionString(const char *pszVersion); --bool VBoxExtPackIsValidEditionString(const char *pszEdition); --bool VBoxExtPackIsValidModuleString(const char *pszModule); -- --int VBoxExtPackValidateMember(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj, char *pszError, size_t cbError); --int VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss, PRTMANIFEST phFileManifest); --int VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName, -- const char *pszTarball, const char *pszTarballDigest, -- char *pszError, size_t cbError, -- PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile, RTCString *pStrDigest); -- -- --#endif -- ---- VirtualBox-4.2.0.orig/src/VBox/Main/src-all/ExtPackManagerImpl.cpp 2012-04-03 04:56:24.000000000 -0300 -+++ /dev/null 2012-09-18 22:18:48.866734195 -0300 -@@ -1,3126 +0,0 @@ --/* $Id: ExtPackManagerImpl.cpp 40468 2012-03-14 17:07:58Z vboxsync $ */ --/** @file -- * VirtualBox Main - interface for Extension Packs, VBoxSVC & VBoxC. -- */ -- --/* -- * Copyright (C) 2010 Oracle Corporation -- * -- * This file is part of VirtualBox Open Source Edition (OSE), as -- * available from http://www.virtualbox.org. This file is free software; -- * you can redistribute it and/or modify it under the terms of the GNU -- * General Public License (GPL) as published by the Free Software -- * Foundation, in version 2 as it comes in the "COPYING" file of the -- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the -- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -- */ -- -- --/******************************************************************************* --* Header Files * --*******************************************************************************/ --#include "ExtPackManagerImpl.h" --#include "ExtPackUtil.h" -- --#include <iprt/buildconfig.h> --#include <iprt/ctype.h> --#include <iprt/dir.h> --#include <iprt/env.h> --#include <iprt/file.h> --#include <iprt/ldr.h> --#include <iprt/manifest.h> --#include <iprt/param.h> --#include <iprt/path.h> --#include <iprt/pipe.h> --#include <iprt/process.h> --#include <iprt/string.h> -- --#include <VBox/com/array.h> --#include <VBox/com/ErrorInfo.h> --#include <VBox/err.h> --#include <VBox/log.h> --#include <VBox/sup.h> --#include <VBox/version.h> --#include "AutoCaller.h" --#include "Global.h" --#include "ProgressImpl.h" --#include "SystemPropertiesImpl.h" --#include "VirtualBoxImpl.h" -- -- --/******************************************************************************* --* Defined Constants And Macros * --*******************************************************************************/ --/** @name VBOX_EXTPACK_HELPER_NAME -- * The name of the utility application we employ to install and uninstall the -- * extension packs. This is a set-uid-to-root binary on unixy platforms, which -- * is why it has to be a separate application. -- */ --#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) --# define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelperApp.exe" --#else --# define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelperApp" --#endif -- -- --/******************************************************************************* --* Structures and Typedefs * --*******************************************************************************/ --struct ExtPackBaseData --{ --public: -- /** The extension pack descriptor (loaded from the XML, mostly). */ -- VBOXEXTPACKDESC Desc; -- /** The file system object info of the XML file. -- * This is for detecting changes and save time in refresh(). */ -- RTFSOBJINFO ObjInfoDesc; -- /** Whether it's usable or not. */ -- bool fUsable; -- /** Why it is unusable. */ -- Utf8Str strWhyUnusable; --}; -- --/** -- * Private extension pack data. -- */ --struct ExtPackFile::Data : public ExtPackBaseData --{ --public: -- /** The path to the tarball. */ -- Utf8Str strExtPackFile; -- /** The SHA-256 hash of the file (as string). */ -- Utf8Str strDigest; -- /** The file handle of the extension pack file. */ -- RTFILE hExtPackFile; -- /** Our manifest for the tarball. */ -- RTMANIFEST hOurManifest; -- /** Pointer to the extension pack manager. */ -- ComObjPtr<ExtPackManager> ptrExtPackMgr; -- /** Pointer to the VirtualBox object so we can create a progress object. */ -- VirtualBox *pVirtualBox; -- -- RTMEMEF_NEW_AND_DELETE_OPERATORS(); --}; -- --/** -- * Private extension pack data. -- */ --struct ExtPack::Data : public ExtPackBaseData --{ --public: -- /** Where the extension pack is located. */ -- Utf8Str strExtPackPath; -- /** The file system object info of the extension pack directory. -- * This is for detecting changes and save time in refresh(). */ -- RTFSOBJINFO ObjInfoExtPack; -- /** The full path to the main module. */ -- Utf8Str strMainModPath; -- /** The file system object info of the main module. -- * This is used to determin whether to bother try reload it. */ -- RTFSOBJINFO ObjInfoMainMod; -- /** The module handle of the main extension pack module. */ -- RTLDRMOD hMainMod; -- -- /** The helper callbacks for the extension pack. */ -- VBOXEXTPACKHLP Hlp; -- /** Pointer back to the extension pack object (for Hlp methods). */ -- ExtPack *pThis; -- /** The extension pack registration structure. */ -- PCVBOXEXTPACKREG pReg; -- /** The current context. */ -- VBOXEXTPACKCTX enmContext; -- /** Set if we've made the pfnVirtualBoxReady or pfnConsoleReady call. */ -- bool fMadeReadyCall; -- -- RTMEMEF_NEW_AND_DELETE_OPERATORS(); --}; -- --/** List of extension packs. */ --typedef std::list< ComObjPtr<ExtPack> > ExtPackList; -- --/** -- * Private extension pack manager data. -- */ --struct ExtPackManager::Data --{ -- /** The directory where the extension packs are installed. */ -- Utf8Str strBaseDir; -- /** The directory where the certificates this installation recognizes are -- * stored. */ -- Utf8Str strCertificatDirPath; -- /** The list of installed extension packs. */ -- ExtPackList llInstalledExtPacks; -- /** Pointer to the VirtualBox object, our parent. */ -- VirtualBox *pVirtualBox; -- /** The current context. */ -- VBOXEXTPACKCTX enmContext; --#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN) -- /** File handle for the VBoxVMM libary which we slurp because ExtPacks depend on it. */ -- RTLDRMOD hVBoxVMM; --#endif -- -- RTMEMEF_NEW_AND_DELETE_OPERATORS(); --}; -- --/** -- * Extension pack installation job. -- */ --typedef struct EXTPACKINSTALLJOB --{ -- /** Smart pointer to the extension pack file. */ -- ComPtr<ExtPackFile> ptrExtPackFile; -- /** The replace argument. */ -- bool fReplace; -- /** The display info argument. */ -- Utf8Str strDisplayInfo; -- /** Smart pointer to the extension manager. */ -- ComPtr<ExtPackManager> ptrExtPackMgr; -- /** Smart pointer to the progress object for this job. */ -- ComObjPtr<Progress> ptrProgress; --} EXTPACKINSTALLJOB; --/** Pointer to an extension pack installation job. */ --typedef EXTPACKINSTALLJOB *PEXTPACKINSTALLJOB; -- --/** -- * Extension pack uninstallation job. -- */ --typedef struct EXTPACKUNINSTALLJOB --{ -- /** Smart pointer to the extension manager. */ -- ComPtr<ExtPackManager> ptrExtPackMgr; -- /** The name of the extension pack. */ -- Utf8Str strName; -- /** The replace argument. */ -- bool fForcedRemoval; -- /** The display info argument. */ -- Utf8Str strDisplayInfo; -- /** Smart pointer to the progress object for this job. */ -- ComObjPtr<Progress> ptrProgress; --} EXTPACKUNINSTALLJOB; --/** Pointer to an extension pack uninstallation job. */ --typedef EXTPACKUNINSTALLJOB *PEXTPACKUNINSTALLJOB; -- -- --DEFINE_EMPTY_CTOR_DTOR(ExtPackFile) -- --/** -- * Called by ComObjPtr::createObject when creating the object. -- * -- * Just initialize the basic object state, do the rest in initWithDir(). -- * -- * @returns S_OK. -- */ --HRESULT ExtPackFile::FinalConstruct() --{ -- m = NULL; -- return BaseFinalConstruct(); --} -- --/** -- * Initializes the extension pack by reading its file. -- * -- * @returns COM status code. -- * @param a_pszFile The path to the extension pack file. -- * @param a_pszDigest The SHA-256 digest of the file. Or an empty string. -- * @param a_pExtPackMgr Pointer to the extension pack manager. -- * @param a_pVirtualBox Pointer to the VirtualBox object. -- */ --HRESULT ExtPackFile::initWithFile(const char *a_pszFile, const char *a_pszDigest, ExtPackManager *a_pExtPackMgr, VirtualBox *a_pVirtualBox) --{ -- AutoInitSpan autoInitSpan(this); -- AssertReturn(autoInitSpan.isOk(), E_FAIL); -- -- /* -- * Allocate + initialize our private data. -- */ -- m = new ExtPackFile::Data; -- VBoxExtPackInitDesc(&m->Desc); -- RT_ZERO(m->ObjInfoDesc); -- m->fUsable = false; -- m->strWhyUnusable = tr("ExtPack::init failed"); -- m->strExtPackFile = a_pszFile; -- m->strDigest = a_pszDigest; -- m->hExtPackFile = NIL_RTFILE; -- m->hOurManifest = NIL_RTMANIFEST; -- m->ptrExtPackMgr = a_pExtPackMgr; -- m->pVirtualBox = a_pVirtualBox; -- -- RTCString *pstrTarName = VBoxExtPackExtractNameFromTarballPath(a_pszFile); -- if (pstrTarName) -- { -- m->Desc.strName = *pstrTarName; -- delete pstrTarName; -- pstrTarName = NULL; -- } -- -- autoInitSpan.setSucceeded(); -- -- /* -- * Try open the extension pack and check that it is a regular file. -- */ -- int vrc = RTFileOpen(&m->hExtPackFile, a_pszFile, -- RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN); -- if (RT_FAILURE(vrc)) -- { -- if (vrc == VERR_FILE_NOT_FOUND || vrc == VERR_PATH_NOT_FOUND) -- return initFailed(tr("'%s' file not found"), a_pszFile); -- return initFailed(tr("RTFileOpen('%s',,) failed with %Rrc"), a_pszFile, vrc); -- } -- -- RTFSOBJINFO ObjInfo; -- vrc = RTFileQueryInfo(m->hExtPackFile, &ObjInfo, RTFSOBJATTRADD_UNIX); -- if (RT_FAILURE(vrc)) -- return initFailed(tr("RTFileQueryInfo failed with %Rrc on '%s'"), vrc, a_pszFile); -- if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) -- return initFailed(tr("Not a regular file: %s"), a_pszFile); -- -- /* -- * Validate the tarball and extract the XML file. -- */ -- char szError[8192]; -- RTVFSFILE hXmlFile; -- vrc = VBoxExtPackValidateTarball(m->hExtPackFile, NULL /*pszExtPackName*/, a_pszFile, a_pszDigest, -- szError, sizeof(szError), &m->hOurManifest, &hXmlFile, &m->strDigest); -- if (RT_FAILURE(vrc)) -- return initFailed(tr("%s"), szError); -- -- /* -- * Parse the XML. -- */ -- RTCString strSavedName(m->Desc.strName); -- RTCString *pStrLoadErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &m->Desc, &m->ObjInfoDesc); -- RTVfsFileRelease(hXmlFile); -- if (pStrLoadErr != NULL) -- { -- m->strWhyUnusable.printf(tr("Failed to the xml file: %s"), pStrLoadErr->c_str()); -- m->Desc.strName = strSavedName; -- delete pStrLoadErr; -- return S_OK; -- } -- -- /* -- * Match the tarball name with the name from the XML. -- */ -- /** @todo drop this restriction after the old install interface is -- * dropped. */ -- if (!strSavedName.equalsIgnoreCase(m->Desc.strName)) -- return initFailed(tr("Extension pack name mismatch between the downloaded file and the XML inside it (xml='%s' file='%s')"), -- m->Desc.strName.c_str(), strSavedName.c_str()); -- -- m->fUsable = true; -- m->strWhyUnusable.setNull(); -- return S_OK; --} -- --/** -- * Protected helper that formats the strWhyUnusable value. -- * -- * @returns S_OK -- * @param a_pszWhyFmt Why it failed, format string. -- * @param ... The format arguments. -- */ --HRESULT ExtPackFile::initFailed(const char *a_pszWhyFmt, ...) --{ -- va_list va; -- va_start(va, a_pszWhyFmt); -- m->strWhyUnusable.printfV(a_pszWhyFmt, va); -- va_end(va); -- return S_OK; --} -- --/** -- * COM cruft. -- */ --void ExtPackFile::FinalRelease() --{ -- uninit(); -- BaseFinalRelease(); --} -- --/** -- * Do the actual cleanup. -- */ --void ExtPackFile::uninit() --{ -- /* Enclose the state transition Ready->InUninit->NotReady */ -- AutoUninitSpan autoUninitSpan(this); -- if (!autoUninitSpan.uninitDone() && m != NULL) -- { -- VBoxExtPackFreeDesc(&m->Desc); -- RTFileClose(m->hExtPackFile); -- m->hExtPackFile = NIL_RTFILE; -- RTManifestRelease(m->hOurManifest); -- m->hOurManifest = NIL_RTMANIFEST; -- -- delete m; -- m = NULL; -- } --} -- --STDMETHODIMP ExtPackFile::COMGETTER(Name)(BSTR *a_pbstrName) --{ -- CheckComArgOutPointerValid(a_pbstrName); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strName); -- str.cloneTo(a_pbstrName); -- } -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(Description)(BSTR *a_pbstrDescription) --{ -- CheckComArgOutPointerValid(a_pbstrDescription); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strDescription); -- str.cloneTo(a_pbstrDescription); -- } -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(Version)(BSTR *a_pbstrVersion) --{ -- CheckComArgOutPointerValid(a_pbstrVersion); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strVersion); -- str.cloneTo(a_pbstrVersion); -- } -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(Edition)(BSTR *a_pbstrEdition) --{ -- CheckComArgOutPointerValid(a_pbstrEdition); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strEdition); -- str.cloneTo(a_pbstrEdition); -- } -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(Revision)(ULONG *a_puRevision) --{ -- CheckComArgOutPointerValid(a_puRevision); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- *a_puRevision = m->Desc.uRevision; -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(VRDEModule)(BSTR *a_pbstrVrdeModule) --{ -- CheckComArgOutPointerValid(a_pbstrVrdeModule); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strVrdeModule); -- str.cloneTo(a_pbstrVrdeModule); -- } -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(PlugIns)(ComSafeArrayOut(IExtPackPlugIn *, a_paPlugIns)) --{ -- /** @todo implement plug-ins. */ --#ifdef VBOX_WITH_XPCOM -- NOREF(a_paPlugIns); -- NOREF(a_paPlugInsSize); --#endif -- ReturnComNotImplemented(); --} -- --STDMETHODIMP ExtPackFile::COMGETTER(Usable)(BOOL *a_pfUsable) --{ -- CheckComArgOutPointerValid(a_pfUsable); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- *a_pfUsable = m->fUsable; -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(WhyUnusable)(BSTR *a_pbstrWhy) --{ -- CheckComArgOutPointerValid(a_pbstrWhy); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- m->strWhyUnusable.cloneTo(a_pbstrWhy); -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(ShowLicense)(BOOL *a_pfShowIt) --{ -- CheckComArgOutPointerValid(a_pfShowIt); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- *a_pfShowIt = m->Desc.fShowLicense; -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(License)(BSTR *a_pbstrHtmlLicense) --{ -- Bstr bstrHtml("html"); -- return QueryLicense(Bstr::Empty.raw(), Bstr::Empty.raw(), bstrHtml.raw(), a_pbstrHtmlLicense); --} -- --/* Same as ExtPack::QueryLicense, should really explore the subject of base classes here... */ --STDMETHODIMP ExtPackFile::QueryLicense(IN_BSTR a_bstrPreferredLocale, IN_BSTR a_bstrPreferredLanguage, IN_BSTR a_bstrFormat, -- BSTR *a_pbstrLicense) --{ -- /* -- * Validate input. -- */ -- CheckComArgOutPointerValid(a_pbstrLicense); -- CheckComArgNotNull(a_bstrPreferredLocale); -- CheckComArgNotNull(a_bstrPreferredLanguage); -- CheckComArgNotNull(a_bstrFormat); -- -- Utf8Str strPreferredLocale(a_bstrPreferredLocale); -- if (strPreferredLocale.length() != 2 && strPreferredLocale.length() != 0) -- return setError(E_FAIL, tr("The preferred locale is a two character string or empty.")); -- -- Utf8Str strPreferredLanguage(a_bstrPreferredLanguage); -- if (strPreferredLanguage.length() != 2 && strPreferredLanguage.length() != 0) -- return setError(E_FAIL, tr("The preferred lanuage is a two character string or empty.")); -- -- Utf8Str strFormat(a_bstrFormat); -- if ( !strFormat.equals("html") -- && !strFormat.equals("rtf") -- && !strFormat.equals("txt")) -- return setError(E_FAIL, tr("The license format can only have the values 'html', 'rtf' and 'txt'.")); -- -- /* -- * Combine the options to form a file name before locking down anything. -- */ -- char szName[sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX "-de_DE.html") + 2]; -- if (strPreferredLocale.isNotEmpty() && strPreferredLanguage.isNotEmpty()) -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s_%s.%s", -- strPreferredLocale.c_str(), strPreferredLanguage.c_str(), strFormat.c_str()); -- else if (strPreferredLocale.isNotEmpty()) -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s.%s", strPreferredLocale.c_str(), strFormat.c_str()); -- else if (strPreferredLanguage.isNotEmpty()) -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-_%s.%s", strPreferredLocale.c_str(), strFormat.c_str()); -- else -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX ".%s", strFormat.c_str()); -- -- /* -- * Lock the extension pack. We need a write lock here as there must not be -- * concurrent accesses to the tar file handle. -- */ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- /* -- * Do not permit this query on a pack that isn't considered usable (could -- * be marked so because of bad license files). -- */ -- if (!m->fUsable) -- hrc = setError(E_FAIL, tr("%s"), m->strWhyUnusable.c_str()); -- else -- { -- /* -- * Look it up in the manifest before scanning the tarball for it -- */ -- if (RTManifestEntryExists(m->hOurManifest, szName)) -- { -- RTVFSFSSTREAM hTarFss; -- char szError[8192]; -- int vrc = VBoxExtPackOpenTarFss(m->hExtPackFile, szError, sizeof(szError), &hTarFss, NULL); -- if (RT_SUCCESS(vrc)) -- { -- for (;;) -- { -- /* Get the first/next. */ -- char *pszName; -- RTVFSOBJ hVfsObj; -- RTVFSOBJTYPE enmType; -- vrc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj); -- if (RT_FAILURE(vrc)) -- { -- if (vrc != VERR_EOF) -- hrc = setError(VBOX_E_IPRT_ERROR, tr("RTVfsFsStrmNext failed: %Rrc"), vrc); -- else -- hrc = setError(E_UNEXPECTED, tr("'%s' was found in the manifest but not in the tarball"), szName); -- break; -- } -- -- /* Is this it? */ -- const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName; -- if ( !strcmp(pszAdjName, szName) -- && ( enmType == RTVFSOBJTYPE_IO_STREAM -- || enmType == RTVFSOBJTYPE_FILE)) -- { -- RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); -- RTVfsObjRelease(hVfsObj); -- RTStrFree(pszName); -- -- /* Load the file into memory. */ -- RTFSOBJINFO ObjInfo; -- vrc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_NOTHING); -- if (RT_SUCCESS(vrc)) -- { -- size_t cbFile = (size_t)ObjInfo.cbObject; -- void *pvFile = RTMemAllocZ(cbFile + 1); -- if (pvFile) -- { -- vrc = RTVfsIoStrmRead(hVfsIos, pvFile, cbFile, true /*fBlocking*/, NULL); -- if (RT_SUCCESS(vrc)) -- { -- /* try translate it into a string we can return. */ -- Bstr bstrLicense((const char *)pvFile, cbFile); -- if (bstrLicense.isNotEmpty()) -- { -- bstrLicense.detachTo(a_pbstrLicense); -- hrc = S_OK; -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, -- tr("The license file '%s' is empty or contains invalid UTF-8 encoding"), -- szName); -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to read '%s': %Rrc"), szName, vrc); -- RTMemFree(pvFile); -- } -- else -- hrc = setError(E_OUTOFMEMORY, tr("Failed to allocate %zu bytes for '%s'"), cbFile, szName); -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, tr("RTVfsIoStrmQueryInfo on '%s': %Rrc"), szName, vrc); -- RTVfsIoStrmRelease(hVfsIos); -- break; -- } -- -- /* Release current. */ -- RTVfsObjRelease(hVfsObj); -- RTStrFree(pszName); -- } -- RTVfsFsStrmRelease(hTarFss); -- } -- else -- hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("%s"), szError); -- } -- else -- hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The license file '%s' was not found in '%s'"), -- szName, m->strExtPackFile.c_str()); -- } -- } -- return hrc; --} -- --STDMETHODIMP ExtPackFile::COMGETTER(FilePath)(BSTR *a_pbstrPath) --{ -- CheckComArgOutPointerValid(a_pbstrPath); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- m->strExtPackFile.cloneTo(a_pbstrPath); -- return hrc; --} -- --STDMETHODIMP ExtPackFile::Install(BOOL a_fReplace, IN_BSTR a_bstrDisplayInfo, IProgress **a_ppProgress) --{ -- if (a_ppProgress) -- *a_ppProgress = NULL; -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- if (m->fUsable) -- { -- PEXTPACKINSTALLJOB pJob = NULL; -- try -- { -- pJob = new EXTPACKINSTALLJOB; -- pJob->ptrExtPackFile = this; -- pJob->fReplace = a_fReplace != FALSE; -- pJob->strDisplayInfo = a_bstrDisplayInfo; -- pJob->ptrExtPackMgr = m->ptrExtPackMgr; -- hrc = pJob->ptrProgress.createObject(); -- if (SUCCEEDED(hrc)) -- { -- Bstr bstrDescription = tr("Installing extension pack"); -- hrc = pJob->ptrProgress->init( --#ifndef VBOX_COM_INPROC -- m->pVirtualBox, --#endif -- static_cast<IExtPackFile *>(this), -- bstrDescription.raw(), -- FALSE /*aCancelable*/, -- NULL /*aId*/); -- } -- if (SUCCEEDED(hrc)) -- { -- ComPtr<Progress> ptrProgress = pJob->ptrProgress; -- int vrc = RTThreadCreate(NULL /*phThread*/, ExtPackManager::doInstallThreadProc, pJob, 0, -- RTTHREADTYPE_DEFAULT, 0 /*fFlags*/, "ExtPackInst"); -- if (RT_SUCCESS(vrc)) -- { -- pJob = NULL; /* the thread deletes it */ -- ptrProgress.queryInterfaceTo(a_ppProgress); -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, tr("RTThreadCreate failed with %Rrc"), vrc); -- } -- } -- catch (std::bad_alloc) -- { -- hrc = E_OUTOFMEMORY; -- } -- if (pJob) -- delete pJob; -- } -- else -- hrc = setError(E_FAIL, "%s", m->strWhyUnusable.c_str()); -- } -- return hrc; --} -- -- -- -- -- --DEFINE_EMPTY_CTOR_DTOR(ExtPack) -- --/** -- * Called by ComObjPtr::createObject when creating the object. -- * -- * Just initialize the basic object state, do the rest in initWithDir(). -- * -- * @returns S_OK. -- */ --HRESULT ExtPack::FinalConstruct() --{ -- m = NULL; -- return S_OK; --} -- --/** -- * Initializes the extension pack by reading its file. -- * -- * @returns COM status code. -- * @param a_enmContext The context we're in. -- * @param a_pszName The name of the extension pack. This is also the -- * name of the subdirector under @a a_pszParentDir -- * where the extension pack is installed. -- * @param a_pszDir The extension pack directory name. -- */ --HRESULT ExtPack::initWithDir(VBOXEXTPACKCTX a_enmContext, const char *a_pszName, const char *a_pszDir) --{ -- AutoInitSpan autoInitSpan(this); -- AssertReturn(autoInitSpan.isOk(), E_FAIL); -- -- static const VBOXEXTPACKHLP s_HlpTmpl = -- { -- /* u32Version = */ VBOXEXTPACKHLP_VERSION, -- /* uVBoxFullVersion = */ VBOX_FULL_VERSION, -- /* uVBoxVersionRevision = */ 0, -- /* u32Padding = */ 0, -- /* pszVBoxVersion = */ "", -- /* pfnFindModule = */ ExtPack::hlpFindModule, -- /* pfnGetFilePath = */ ExtPack::hlpGetFilePath, -- /* pfnGetContext = */ ExtPack::hlpGetContext, -- /* pfnReserved1 = */ ExtPack::hlpReservedN, -- /* pfnReserved2 = */ ExtPack::hlpReservedN, -- /* pfnReserved3 = */ ExtPack::hlpReservedN, -- /* pfnReserved4 = */ ExtPack::hlpReservedN, -- /* pfnReserved5 = */ ExtPack::hlpReservedN, -- /* pfnReserved6 = */ ExtPack::hlpReservedN, -- /* pfnReserved7 = */ ExtPack::hlpReservedN, -- /* pfnReserved8 = */ ExtPack::hlpReservedN, -- /* pfnReserved9 = */ ExtPack::hlpReservedN, -- /* u32EndMarker = */ VBOXEXTPACKHLP_VERSION -- }; -- -- /* -- * Allocate + initialize our private data. -- */ -- m = new Data; -- VBoxExtPackInitDesc(&m->Desc); -- m->Desc.strName = a_pszName; -- RT_ZERO(m->ObjInfoDesc); -- m->fUsable = false; -- m->strWhyUnusable = tr("ExtPack::init failed"); -- m->strExtPackPath = a_pszDir; -- RT_ZERO(m->ObjInfoExtPack); -- m->strMainModPath.setNull(); -- RT_ZERO(m->ObjInfoMainMod); -- m->hMainMod = NIL_RTLDRMOD; -- m->Hlp = s_HlpTmpl; -- m->Hlp.pszVBoxVersion = RTBldCfgVersion(); -- m->Hlp.uVBoxInternalRevision = RTBldCfgRevision(); -- m->pThis = this; -- m->pReg = NULL; -- m->enmContext = a_enmContext; -- m->fMadeReadyCall = false; -- -- /* -- * Probe the extension pack (this code is shared with refresh()). -- */ -- probeAndLoad(); -- -- autoInitSpan.setSucceeded(); -- return S_OK; --} -- --/** -- * COM cruft. -- */ --void ExtPack::FinalRelease() --{ -- uninit(); --} -- --/** -- * Do the actual cleanup. -- */ --void ExtPack::uninit() --{ -- /* Enclose the state transition Ready->InUninit->NotReady */ -- AutoUninitSpan autoUninitSpan(this); -- if (!autoUninitSpan.uninitDone() && m != NULL) -- { -- if (m->hMainMod != NIL_RTLDRMOD) -- { -- AssertPtr(m->pReg); -- if (m->pReg->pfnUnload != NULL) -- m->pReg->pfnUnload(m->pReg); -- -- RTLdrClose(m->hMainMod); -- m->hMainMod = NIL_RTLDRMOD; -- m->pReg = NULL; -- } -- -- VBoxExtPackFreeDesc(&m->Desc); -- -- delete m; -- m = NULL; -- } --} -- -- --/** -- * Calls the installed hook. -- * -- * @returns true if we left the lock, false if we didn't. -- * @param a_pVirtualBox The VirtualBox interface. -- * @param a_pLock The write lock held by the caller. -- * @param pErrInfo Where to return error information. -- */ --bool ExtPack::callInstalledHook(IVirtualBox *a_pVirtualBox, AutoWriteLock *a_pLock, PRTERRINFO pErrInfo) --{ -- if ( m != NULL -- && m->hMainMod != NIL_RTLDRMOD) -- { -- if (m->pReg->pfnInstalled) -- { -- ComPtr<ExtPack> ptrSelfRef = this; -- a_pLock->release(); -- pErrInfo->rc = m->pReg->pfnInstalled(m->pReg, a_pVirtualBox, pErrInfo); -- a_pLock->acquire(); -- return true; -- } -- } -- pErrInfo->rc = VINF_SUCCESS; -- return false; --} -- --/** -- * Calls the uninstall hook and closes the module. -- * -- * @returns S_OK or COM error status with error information. -- * @param a_pVirtualBox The VirtualBox interface. -- * @param a_fForcedRemoval When set, we'll ignore complaints from the -- * uninstall hook. -- * @remarks The caller holds the manager's write lock, not released. -- */ --HRESULT ExtPack::callUninstallHookAndClose(IVirtualBox *a_pVirtualBox, bool a_fForcedRemoval) --{ -- HRESULT hrc = S_OK; -- -- if ( m != NULL -- && m->hMainMod != NIL_RTLDRMOD) -- { -- if (m->pReg->pfnUninstall && !a_fForcedRemoval) -- { -- int vrc = m->pReg->pfnUninstall(m->pReg, a_pVirtualBox); -- if (RT_FAILURE(vrc)) -- { -- LogRel(("ExtPack pfnUninstall returned %Rrc for %s\n", vrc, m->Desc.strName.c_str())); -- if (!a_fForcedRemoval) -- hrc = setError(E_FAIL, tr("pfnUninstall returned %Rrc"), vrc); -- } -- } -- if (SUCCEEDED(hrc)) -- { -- RTLdrClose(m->hMainMod); -- m->hMainMod = NIL_RTLDRMOD; -- m->pReg = NULL; -- } -- } -- -- return hrc; --} -- --/** -- * Calls the pfnVirtualBoxReady hook. -- * -- * @returns true if we left the lock, false if we didn't. -- * @param a_pVirtualBox The VirtualBox interface. -- * @param a_pLock The write lock held by the caller. -- */ --bool ExtPack::callVirtualBoxReadyHook(IVirtualBox *a_pVirtualBox, AutoWriteLock *a_pLock) --{ -- if ( m != NULL -- && m->fUsable -- && !m->fMadeReadyCall) -- { -- m->fMadeReadyCall = true; -- if (m->pReg->pfnVirtualBoxReady) -- { -- ComPtr<ExtPack> ptrSelfRef = this; -- a_pLock->release(); -- m->pReg->pfnVirtualBoxReady(m->pReg, a_pVirtualBox); -- a_pLock->acquire(); -- return true; -- } -- } -- return false; --} -- --/** -- * Calls the pfnConsoleReady hook. -- * -- * @returns true if we left the lock, false if we didn't. -- * @param a_pConsole The Console interface. -- * @param a_pLock The write lock held by the caller. -- */ --bool ExtPack::callConsoleReadyHook(IConsole *a_pConsole, AutoWriteLock *a_pLock) --{ -- if ( m != NULL -- && m->fUsable -- && !m->fMadeReadyCall) -- { -- m->fMadeReadyCall = true; -- if (m->pReg->pfnConsoleReady) -- { -- ComPtr<ExtPack> ptrSelfRef = this; -- a_pLock->release(); -- m->pReg->pfnConsoleReady(m->pReg, a_pConsole); -- a_pLock->acquire(); -- return true; -- } -- } -- return false; --} -- --/** -- * Calls the pfnVMCreate hook. -- * -- * @returns true if we left the lock, false if we didn't. -- * @param a_pVirtualBox The VirtualBox interface. -- * @param a_pMachine The machine interface of the new VM. -- * @param a_pLock The write lock held by the caller. -- */ --bool ExtPack::callVmCreatedHook(IVirtualBox *a_pVirtualBox, IMachine *a_pMachine, AutoWriteLock *a_pLock) --{ -- if ( m != NULL -- && m->fUsable) -- { -- if (m->pReg->pfnVMCreated) -- { -- ComPtr<ExtPack> ptrSelfRef = this; -- a_pLock->release(); -- m->pReg->pfnVMCreated(m->pReg, a_pVirtualBox, a_pMachine); -- a_pLock->acquire(); -- return true; -- } -- } -- return false; --} -- --/** -- * Calls the pfnVMConfigureVMM hook. -- * -- * @returns true if we left the lock, false if we didn't. -- * @param a_pConsole The console interface. -- * @param a_pVM The VM handle. -- * @param a_pLock The write lock held by the caller. -- * @param a_pvrc Where to return the status code of the -- * callback. This is always set. LogRel is -- * called on if a failure status is returned. -- */ --bool ExtPack::callVmConfigureVmmHook(IConsole *a_pConsole, PVM a_pVM, AutoWriteLock *a_pLock, int *a_pvrc) --{ -- *a_pvrc = VINF_SUCCESS; -- if ( m != NULL -- && m->fUsable) -- { -- if (m->pReg->pfnVMConfigureVMM) -- { -- ComPtr<ExtPack> ptrSelfRef = this; -- a_pLock->release(); -- int vrc = m->pReg->pfnVMConfigureVMM(m->pReg, a_pConsole, a_pVM); -- *a_pvrc = vrc; -- a_pLock->acquire(); -- if (RT_FAILURE(vrc)) -- LogRel(("ExtPack pfnVMConfigureVMM returned %Rrc for %s\n", vrc, m->Desc.strName.c_str())); -- return true; -- } -- } -- return false; --} -- --/** -- * Calls the pfnVMPowerOn hook. -- * -- * @returns true if we left the lock, false if we didn't. -- * @param a_pConsole The console interface. -- * @param a_pVM The VM handle. -- * @param a_pLock The write lock held by the caller. -- * @param a_pvrc Where to return the status code of the -- * callback. This is always set. LogRel is -- * called on if a failure status is returned. -- */ --bool ExtPack::callVmPowerOnHook(IConsole *a_pConsole, PVM a_pVM, AutoWriteLock *a_pLock, int *a_pvrc) --{ -- *a_pvrc = VINF_SUCCESS; -- if ( m != NULL -- && m->fUsable) -- { -- if (m->pReg->pfnVMPowerOn) -- { -- ComPtr<ExtPack> ptrSelfRef = this; -- a_pLock->release(); -- int vrc = m->pReg->pfnVMPowerOn(m->pReg, a_pConsole, a_pVM); -- *a_pvrc = vrc; -- a_pLock->acquire(); -- if (RT_FAILURE(vrc)) -- LogRel(("ExtPack pfnVMPowerOn returned %Rrc for %s\n", vrc, m->Desc.strName.c_str())); -- return true; -- } -- } -- return false; --} -- --/** -- * Calls the pfnVMPowerOff hook. -- * -- * @returns true if we left the lock, false if we didn't. -- * @param a_pConsole The console interface. -- * @param a_pVM The VM handle. -- * @param a_pLock The write lock held by the caller. -- */ --bool ExtPack::callVmPowerOffHook(IConsole *a_pConsole, PVM a_pVM, AutoWriteLock *a_pLock) --{ -- if ( m != NULL -- && m->fUsable) -- { -- if (m->pReg->pfnVMPowerOff) -- { -- ComPtr<ExtPack> ptrSelfRef = this; -- a_pLock->release(); -- m->pReg->pfnVMPowerOff(m->pReg, a_pConsole, a_pVM); -- a_pLock->acquire(); -- return true; -- } -- } -- return false; --} -- --/** -- * Check if the extension pack is usable and has an VRDE module. -- * -- * @returns S_OK or COM error status with error information. -- * -- * @remarks Caller holds the extension manager lock for reading, no locking -- * necessary. -- */ --HRESULT ExtPack::checkVrde(void) --{ -- HRESULT hrc; -- if ( m != NULL -- && m->fUsable) -- { -- if (m->Desc.strVrdeModule.isNotEmpty()) -- hrc = S_OK; -- else -- hrc = setError(E_FAIL, tr("The extension pack '%s' does not include a VRDE module"), m->Desc.strName.c_str()); -- } -- else -- hrc = setError(E_FAIL, tr("%s"), m->strWhyUnusable.c_str()); -- return hrc; --} -- --/** -- * Same as checkVrde(), except that it also resolves the path to the module. -- * -- * @returns S_OK or COM error status with error information. -- * @param a_pstrVrdeLibrary Where to return the path on success. -- * -- * @remarks Caller holds the extension manager lock for reading, no locking -- * necessary. -- */ --HRESULT ExtPack::getVrdpLibraryName(Utf8Str *a_pstrVrdeLibrary) --{ -- HRESULT hrc = checkVrde(); -- if (SUCCEEDED(hrc)) -- { -- if (findModule(m->Desc.strVrdeModule.c_str(), NULL, VBOXEXTPACKMODKIND_R3, -- a_pstrVrdeLibrary, NULL /*a_pfNative*/, NULL /*a_pObjInfo*/)) -- hrc = S_OK; -- else -- hrc = setError(E_FAIL, tr("Failed to locate the VRDE module '%s' in extension pack '%s'"), -- m->Desc.strVrdeModule.c_str(), m->Desc.strName.c_str()); -- } -- return hrc; --} -- --/** -- * Check if this extension pack wishes to be the default VRDE provider. -- * -- * @returns @c true if it wants to and it is in a usable state, otherwise -- * @c false. -- * -- * @remarks Caller holds the extension manager lock for reading, no locking -- * necessary. -- */ --bool ExtPack::wantsToBeDefaultVrde(void) const --{ -- return m->fUsable -- && m->Desc.strVrdeModule.isNotEmpty(); --} -- --/** -- * Refreshes the extension pack state. -- * -- * This is called by the manager so that the on disk changes are picked up. -- * -- * @returns S_OK or COM error status with error information. -- * -- * @param a_pfCanDelete Optional can-delete-this-object output indicator. -- * -- * @remarks Caller holds the extension manager lock for writing. -- * @remarks Only called in VBoxSVC. -- */ --HRESULT ExtPack::refresh(bool *a_pfCanDelete) --{ -- if (a_pfCanDelete) -- *a_pfCanDelete = false; -- -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); /* for the COMGETTERs */ -- -- /* -- * Has the module been deleted? -- */ -- RTFSOBJINFO ObjInfoExtPack; -- int vrc = RTPathQueryInfoEx(m->strExtPackPath.c_str(), &ObjInfoExtPack, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); -- if ( RT_FAILURE(vrc) -- || !RTFS_IS_DIRECTORY(ObjInfoExtPack.Attr.fMode)) -- { -- if (a_pfCanDelete) -- *a_pfCanDelete = true; -- return S_OK; -- } -- -- /* -- * We've got a directory, so try query file system object info for the -- * files we are interested in as well. -- */ -- RTFSOBJINFO ObjInfoDesc; -- char szDescFilePath[RTPATH_MAX]; -- vrc = RTPathJoin(szDescFilePath, sizeof(szDescFilePath), m->strExtPackPath.c_str(), VBOX_EXTPACK_DESCRIPTION_NAME); -- if (RT_SUCCESS(vrc)) -- vrc = RTPathQueryInfoEx(szDescFilePath, &ObjInfoDesc, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); -- if (RT_FAILURE(vrc)) -- RT_ZERO(ObjInfoDesc); -- -- RTFSOBJINFO ObjInfoMainMod; -- if (m->strMainModPath.isNotEmpty()) -- vrc = RTPathQueryInfoEx(m->strMainModPath.c_str(), &ObjInfoMainMod, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); -- if (m->strMainModPath.isEmpty() || RT_FAILURE(vrc)) -- RT_ZERO(ObjInfoMainMod); -- -- /* -- * If we have a usable module already, just verify that things haven't -- * changed since we loaded it. -- */ -- if (m->fUsable) -- { -- if (m->hMainMod == NIL_RTLDRMOD) -- probeAndLoad(); -- else if ( !objinfoIsEqual(&ObjInfoDesc, &m->ObjInfoDesc) -- || !objinfoIsEqual(&ObjInfoMainMod, &m->ObjInfoMainMod) -- || !objinfoIsEqual(&ObjInfoExtPack, &m->ObjInfoExtPack) ) -- { -- /** @todo not important, so it can wait. */ -- } -- } -- /* -- * Ok, it is currently not usable. If anything has changed since last time -- * reprobe the extension pack. -- */ -- else if ( !objinfoIsEqual(&ObjInfoDesc, &m->ObjInfoDesc) -- || !objinfoIsEqual(&ObjInfoMainMod, &m->ObjInfoMainMod) -- || !objinfoIsEqual(&ObjInfoExtPack, &m->ObjInfoExtPack) ) -- probeAndLoad(); -- -- return S_OK; --} -- --/** -- * Probes the extension pack, loading the main dll and calling its registration -- * entry point. -- * -- * This updates the state accordingly, the strWhyUnusable and fUnusable members -- * being the most important ones. -- */ --void ExtPack::probeAndLoad(void) --{ -- m->fUsable = false; -- m->fMadeReadyCall = false; -- -- /* -- * Query the file system info for the extension pack directory. This and -- * all other file system info we save is for the benefit of refresh(). -- */ -- int vrc = RTPathQueryInfoEx(m->strExtPackPath.c_str(), &m->ObjInfoExtPack, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); -- if (RT_FAILURE(vrc)) -- { -- m->strWhyUnusable.printf(tr("RTPathQueryInfoEx on '%s' failed: %Rrc"), m->strExtPackPath.c_str(), vrc); -- return; -- } -- if (!RTFS_IS_DIRECTORY(m->ObjInfoExtPack.Attr.fMode)) -- { -- if (RTFS_IS_SYMLINK(m->ObjInfoExtPack.Attr.fMode)) -- m->strWhyUnusable.printf(tr("'%s' is a symbolic link, this is not allowed"), m->strExtPackPath.c_str(), vrc); -- else if (RTFS_IS_FILE(m->ObjInfoExtPack.Attr.fMode)) -- m->strWhyUnusable.printf(tr("'%s' is a symbolic file, not a directory"), m->strExtPackPath.c_str(), vrc); -- else -- m->strWhyUnusable.printf(tr("'%s' is not a directory (fMode=%#x)"), m->strExtPackPath.c_str(), m->ObjInfoExtPack.Attr.fMode); -- return; -- } -- -- RTERRINFOSTATIC ErrInfo; -- RTErrInfoInitStatic(&ErrInfo); -- vrc = SUPR3HardenedVerifyDir(m->strExtPackPath.c_str(), true /*fRecursive*/, true /*fCheckFiles*/, &ErrInfo.Core); -- if (RT_FAILURE(vrc)) -- { -- m->strWhyUnusable.printf(tr("%s (rc=%Rrc)"), ErrInfo.Core.pszMsg, vrc); -- return; -- } -- -- /* -- * Read the description file. -- */ -- RTCString strSavedName(m->Desc.strName); -- RTCString *pStrLoadErr = VBoxExtPackLoadDesc(m->strExtPackPath.c_str(), &m->Desc, &m->ObjInfoDesc); -- if (pStrLoadErr != NULL) -- { -- m->strWhyUnusable.printf(tr("Failed to load '%s/%s': %s"), -- m->strExtPackPath.c_str(), VBOX_EXTPACK_DESCRIPTION_NAME, pStrLoadErr->c_str()); -- m->Desc.strName = strSavedName; -- delete pStrLoadErr; -- return; -- } -- -- /* -- * Make sure the XML name and directory matches. -- */ -- if (!m->Desc.strName.equalsIgnoreCase(strSavedName)) -- { -- m->strWhyUnusable.printf(tr("The description name ('%s') and directory name ('%s') does not match"), -- m->Desc.strName.c_str(), strSavedName.c_str()); -- m->Desc.strName = strSavedName; -- return; -- } -- -- /* -- * Load the main DLL and call the predefined entry point. -- */ -- bool fIsNative; -- if (!findModule(m->Desc.strMainModule.c_str(), NULL /* default extension */, VBOXEXTPACKMODKIND_R3, -- &m->strMainModPath, &fIsNative, &m->ObjInfoMainMod)) -- { -- m->strWhyUnusable.printf(tr("Failed to locate the main module ('%s')"), m->Desc.strMainModule.c_str()); -- return; -- } -- -- vrc = SUPR3HardenedVerifyPlugIn(m->strMainModPath.c_str(), &ErrInfo.Core); -- if (RT_FAILURE(vrc)) -- { -- m->strWhyUnusable.printf(tr("%s"), ErrInfo.Core.pszMsg); -- return; -- } -- -- if (fIsNative) -- { -- vrc = SUPR3HardenedLdrLoadPlugIn(m->strMainModPath.c_str(), &m->hMainMod, &ErrInfo.Core); -- if (RT_FAILURE(vrc)) -- { -- m->hMainMod = NIL_RTLDRMOD; -- m->strWhyUnusable.printf(tr("Failed to load the main module ('%s'): %Rrc - %s"), -- m->strMainModPath.c_str(), vrc, ErrInfo.Core.pszMsg); -- return; -- } -- } -- else -- { -- m->strWhyUnusable.printf(tr("Only native main modules are currently supported")); -- return; -- } -- -- /* -- * Resolve the predefined entry point. -- */ -- PFNVBOXEXTPACKREGISTER pfnRegistration; -- vrc = RTLdrGetSymbol(m->hMainMod, VBOX_EXTPACK_MAIN_MOD_ENTRY_POINT, (void **)&pfnRegistration); -- if (RT_SUCCESS(vrc)) -- { -- RTErrInfoClear(&ErrInfo.Core); -- vrc = pfnRegistration(&m->Hlp, &m->pReg, &ErrInfo.Core); -- if ( RT_SUCCESS(vrc) -- && !RTErrInfoIsSet(&ErrInfo.Core) -- && VALID_PTR(m->pReg)) -- { -- if ( VBOXEXTPACK_IS_MAJOR_VER_EQUAL(m->pReg->u32Version, VBOXEXTPACKREG_VERSION) -- && m->pReg->u32EndMarker == m->pReg->u32Version) -- { -- if ( (!m->pReg->pfnInstalled || RT_VALID_PTR(m->pReg->pfnInstalled)) -- && (!m->pReg->pfnUninstall || RT_VALID_PTR(m->pReg->pfnUninstall)) -- && (!m->pReg->pfnVirtualBoxReady || RT_VALID_PTR(m->pReg->pfnVirtualBoxReady)) -- && (!m->pReg->pfnConsoleReady || RT_VALID_PTR(m->pReg->pfnConsoleReady)) -- && (!m->pReg->pfnUnload || RT_VALID_PTR(m->pReg->pfnUnload)) -- && (!m->pReg->pfnVMCreated || RT_VALID_PTR(m->pReg->pfnVMCreated)) -- && (!m->pReg->pfnVMConfigureVMM || RT_VALID_PTR(m->pReg->pfnVMConfigureVMM)) -- && (!m->pReg->pfnVMPowerOn || RT_VALID_PTR(m->pReg->pfnVMPowerOn)) -- && (!m->pReg->pfnVMPowerOff || RT_VALID_PTR(m->pReg->pfnVMPowerOff)) -- && (!m->pReg->pfnQueryObject || RT_VALID_PTR(m->pReg->pfnQueryObject)) -- ) -- { -- /* -- * We're good! -- */ -- m->fUsable = true; -- m->strWhyUnusable.setNull(); -- return; -- } -- -- m->strWhyUnusable = tr("The registration structure contains on or more invalid function pointers"); -- } -- else -- m->strWhyUnusable.printf(tr("Unsupported registration structure version %u.%u"), -- RT_HIWORD(m->pReg->u32Version), RT_LOWORD(m->pReg->u32Version)); -- } -- else -- m->strWhyUnusable.printf(tr("%s returned %Rrc, pReg=%p ErrInfo='%s'"), -- VBOX_EXTPACK_MAIN_MOD_ENTRY_POINT, vrc, m->pReg, ErrInfo.Core.pszMsg); -- m->pReg = NULL; -- } -- else -- m->strWhyUnusable.printf(tr("Failed to resolve exported symbol '%s' in the main module: %Rrc"), -- VBOX_EXTPACK_MAIN_MOD_ENTRY_POINT, vrc); -- -- RTLdrClose(m->hMainMod); -- m->hMainMod = NIL_RTLDRMOD; --} -- --/** -- * Finds a module. -- * -- * @returns true if found, false if not. -- * @param a_pszName The module base name (no extension). -- * @param a_pszExt The extension. If NULL we use default -- * extensions. -- * @param a_enmKind The kind of module to locate. -- * @param a_pStrFound Where to return the path to the module we've -- * found. -- * @param a_pfNative Where to return whether this is a native module -- * or an agnostic one. Optional. -- * @param a_pObjInfo Where to return the file system object info for -- * the module. Optional. -- */ --bool ExtPack::findModule(const char *a_pszName, const char *a_pszExt, VBOXEXTPACKMODKIND a_enmKind, -- Utf8Str *a_pStrFound, bool *a_pfNative, PRTFSOBJINFO a_pObjInfo) const --{ -- /* -- * Try the native path first. -- */ -- char szPath[RTPATH_MAX]; -- int vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), RTBldCfgTargetDotArch()); -- AssertLogRelRCReturn(vrc, false); -- vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName); -- AssertLogRelRCReturn(vrc, false); -- if (!a_pszExt) -- { -- const char *pszDefExt; -- switch (a_enmKind) -- { -- case VBOXEXTPACKMODKIND_RC: pszDefExt = ".rc"; break; -- case VBOXEXTPACKMODKIND_R0: pszDefExt = ".r0"; break; -- case VBOXEXTPACKMODKIND_R3: pszDefExt = RTLdrGetSuff(); break; -- default: -- AssertFailedReturn(false); -- } -- vrc = RTStrCat(szPath, sizeof(szPath), pszDefExt); -- AssertLogRelRCReturn(vrc, false); -- } -- -- RTFSOBJINFO ObjInfo; -- if (!a_pObjInfo) -- a_pObjInfo = &ObjInfo; -- vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX); -- if (RT_SUCCESS(vrc) && RTFS_IS_FILE(a_pObjInfo->Attr.fMode)) -- { -- if (a_pfNative) -- *a_pfNative = true; -- *a_pStrFound = szPath; -- return true; -- } -- -- /* -- * Try the platform agnostic modules. -- */ -- /* gcc.x86/module.rel */ -- char szSubDir[32]; -- RTStrPrintf(szSubDir, sizeof(szSubDir), "%s.%s", RTBldCfgCompiler(), RTBldCfgTargetArch()); -- vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), szSubDir); -- AssertLogRelRCReturn(vrc, false); -- vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName); -- AssertLogRelRCReturn(vrc, false); -- if (!a_pszExt) -- { -- vrc = RTStrCat(szPath, sizeof(szPath), ".rel"); -- AssertLogRelRCReturn(vrc, false); -- } -- vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX); -- if (RT_SUCCESS(vrc) && RTFS_IS_FILE(a_pObjInfo->Attr.fMode)) -- { -- if (a_pfNative) -- *a_pfNative = false; -- *a_pStrFound = szPath; -- return true; -- } -- -- /* x86/module.rel */ -- vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), RTBldCfgTargetArch()); -- AssertLogRelRCReturn(vrc, false); -- vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName); -- AssertLogRelRCReturn(vrc, false); -- if (!a_pszExt) -- { -- vrc = RTStrCat(szPath, sizeof(szPath), ".rel"); -- AssertLogRelRCReturn(vrc, false); -- } -- vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX); -- if (RT_SUCCESS(vrc) && RTFS_IS_FILE(a_pObjInfo->Attr.fMode)) -- { -- if (a_pfNative) -- *a_pfNative = false; -- *a_pStrFound = szPath; -- return true; -- } -- -- return false; --} -- --/** -- * Compares two file system object info structures. -- * -- * @returns true if equal, false if not. -- * @param pObjInfo1 The first. -- * @param pObjInfo2 The second. -- * @todo IPRT should do this, really. -- */ --/* static */ bool ExtPack::objinfoIsEqual(PCRTFSOBJINFO pObjInfo1, PCRTFSOBJINFO pObjInfo2) --{ -- if (!RTTimeSpecIsEqual(&pObjInfo1->ModificationTime, &pObjInfo2->ModificationTime)) -- return false; -- if (!RTTimeSpecIsEqual(&pObjInfo1->ChangeTime, &pObjInfo2->ChangeTime)) -- return false; -- if (!RTTimeSpecIsEqual(&pObjInfo1->BirthTime, &pObjInfo2->BirthTime)) -- return false; -- if (pObjInfo1->cbObject != pObjInfo2->cbObject) -- return false; -- if (pObjInfo1->Attr.fMode != pObjInfo2->Attr.fMode) -- return false; -- if (pObjInfo1->Attr.enmAdditional == pObjInfo2->Attr.enmAdditional) -- { -- switch (pObjInfo1->Attr.enmAdditional) -- { -- case RTFSOBJATTRADD_UNIX: -- if (pObjInfo1->Attr.u.Unix.uid != pObjInfo2->Attr.u.Unix.uid) -- return false; -- if (pObjInfo1->Attr.u.Unix.gid != pObjInfo2->Attr.u.Unix.gid) -- return false; -- if (pObjInfo1->Attr.u.Unix.INodeIdDevice != pObjInfo2->Attr.u.Unix.INodeIdDevice) -- return false; -- if (pObjInfo1->Attr.u.Unix.INodeId != pObjInfo2->Attr.u.Unix.INodeId) -- return false; -- if (pObjInfo1->Attr.u.Unix.GenerationId != pObjInfo2->Attr.u.Unix.GenerationId) -- return false; -- break; -- default: -- break; -- } -- } -- return true; --} -- -- --/** -- * @interface_method_impl{VBOXEXTPACKHLP,pfnFindModule} -- */ --/*static*/ DECLCALLBACK(int) --ExtPack::hlpFindModule(PCVBOXEXTPACKHLP pHlp, const char *pszName, const char *pszExt, VBOXEXTPACKMODKIND enmKind, -- char *pszFound, size_t cbFound, bool *pfNative) --{ -- /* -- * Validate the input and get our bearings. -- */ -- AssertPtrReturn(pszName, VERR_INVALID_POINTER); -- AssertPtrNullReturn(pszExt, VERR_INVALID_POINTER); -- AssertPtrReturn(pszFound, VERR_INVALID_POINTER); -- AssertPtrNullReturn(pfNative, VERR_INVALID_POINTER); -- AssertReturn(enmKind > VBOXEXTPACKMODKIND_INVALID && enmKind < VBOXEXTPACKMODKIND_END, VERR_INVALID_PARAMETER); -- -- AssertPtrReturn(pHlp, VERR_INVALID_POINTER); -- AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER); -- ExtPack::Data *m = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp); -- AssertPtrReturn(m, VERR_INVALID_POINTER); -- ExtPack *pThis = m->pThis; -- AssertPtrReturn(pThis, VERR_INVALID_POINTER); -- -- /* -- * This is just a wrapper around findModule. -- */ -- Utf8Str strFound; -- if (pThis->findModule(pszName, pszExt, enmKind, &strFound, pfNative, NULL)) -- return RTStrCopy(pszFound, cbFound, strFound.c_str()); -- return VERR_FILE_NOT_FOUND; --} -- --/*static*/ DECLCALLBACK(int) --ExtPack::hlpGetFilePath(PCVBOXEXTPACKHLP pHlp, const char *pszFilename, char *pszPath, size_t cbPath) --{ -- /* -- * Validate the input and get our bearings. -- */ -- AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); -- AssertPtrReturn(pszPath, VERR_INVALID_POINTER); -- AssertReturn(cbPath > 0, VERR_BUFFER_OVERFLOW); -- -- AssertPtrReturn(pHlp, VERR_INVALID_POINTER); -- AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER); -- ExtPack::Data *m = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp); -- AssertPtrReturn(m, VERR_INVALID_POINTER); -- ExtPack *pThis = m->pThis; -- AssertPtrReturn(pThis, VERR_INVALID_POINTER); -- -- /* -- * This is a simple RTPathJoin, no checking if things exists or anything. -- */ -- int vrc = RTPathJoin(pszPath, cbPath, pThis->m->strExtPackPath.c_str(), pszFilename); -- if (RT_FAILURE(vrc)) -- RT_BZERO(pszPath, cbPath); -- return vrc; --} -- --/*static*/ DECLCALLBACK(VBOXEXTPACKCTX) --ExtPack::hlpGetContext(PCVBOXEXTPACKHLP pHlp) --{ -- /* -- * Validate the input and get our bearings. -- */ -- AssertPtrReturn(pHlp, VBOXEXTPACKCTX_INVALID); -- AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VBOXEXTPACKCTX_INVALID); -- ExtPack::Data *m = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp); -- AssertPtrReturn(m, VBOXEXTPACKCTX_INVALID); -- ExtPack *pThis = m->pThis; -- AssertPtrReturn(pThis, VBOXEXTPACKCTX_INVALID); -- -- return pThis->m->enmContext; --} -- --/*static*/ DECLCALLBACK(int) --ExtPack::hlpReservedN(PCVBOXEXTPACKHLP pHlp) --{ -- /* -- * Validate the input and get our bearings. -- */ -- AssertPtrReturn(pHlp, VERR_INVALID_POINTER); -- AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER); -- ExtPack::Data *m = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp); -- AssertPtrReturn(m, VERR_INVALID_POINTER); -- ExtPack *pThis = m->pThis; -- AssertPtrReturn(pThis, VERR_INVALID_POINTER); -- -- return VERR_NOT_IMPLEMENTED; --} -- -- -- -- -- --STDMETHODIMP ExtPack::COMGETTER(Name)(BSTR *a_pbstrName) --{ -- CheckComArgOutPointerValid(a_pbstrName); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strName); -- str.cloneTo(a_pbstrName); -- } -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(Description)(BSTR *a_pbstrDescription) --{ -- CheckComArgOutPointerValid(a_pbstrDescription); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strDescription); -- str.cloneTo(a_pbstrDescription); -- } -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(Version)(BSTR *a_pbstrVersion) --{ -- CheckComArgOutPointerValid(a_pbstrVersion); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strVersion); -- str.cloneTo(a_pbstrVersion); -- } -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(Revision)(ULONG *a_puRevision) --{ -- CheckComArgOutPointerValid(a_puRevision); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- *a_puRevision = m->Desc.uRevision; -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(Edition)(BSTR *a_pbstrEdition) --{ -- CheckComArgOutPointerValid(a_pbstrEdition); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strEdition); -- str.cloneTo(a_pbstrEdition); -- } -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(VRDEModule)(BSTR *a_pbstrVrdeModule) --{ -- CheckComArgOutPointerValid(a_pbstrVrdeModule); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- Bstr str(m->Desc.strVrdeModule); -- str.cloneTo(a_pbstrVrdeModule); -- } -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(PlugIns)(ComSafeArrayOut(IExtPackPlugIn *, a_paPlugIns)) --{ -- /** @todo implement plug-ins. */ --#ifdef VBOX_WITH_XPCOM -- NOREF(a_paPlugIns); -- NOREF(a_paPlugInsSize); --#endif -- ReturnComNotImplemented(); --} -- --STDMETHODIMP ExtPack::COMGETTER(Usable)(BOOL *a_pfUsable) --{ -- CheckComArgOutPointerValid(a_pfUsable); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- *a_pfUsable = m->fUsable; -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(WhyUnusable)(BSTR *a_pbstrWhy) --{ -- CheckComArgOutPointerValid(a_pbstrWhy); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- m->strWhyUnusable.cloneTo(a_pbstrWhy); -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(ShowLicense)(BOOL *a_pfShowIt) --{ -- CheckComArgOutPointerValid(a_pfShowIt); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- *a_pfShowIt = m->Desc.fShowLicense; -- return hrc; --} -- --STDMETHODIMP ExtPack::COMGETTER(License)(BSTR *a_pbstrHtmlLicense) --{ -- Bstr bstrHtml("html"); -- return QueryLicense(Bstr::Empty.raw(), Bstr::Empty.raw(), bstrHtml.raw(), a_pbstrHtmlLicense); --} -- --STDMETHODIMP ExtPack::QueryLicense(IN_BSTR a_bstrPreferredLocale, IN_BSTR a_bstrPreferredLanguage, IN_BSTR a_bstrFormat, -- BSTR *a_pbstrLicense) --{ -- /* -- * Validate input. -- */ -- CheckComArgOutPointerValid(a_pbstrLicense); -- CheckComArgNotNull(a_bstrPreferredLocale); -- CheckComArgNotNull(a_bstrPreferredLanguage); -- CheckComArgNotNull(a_bstrFormat); -- -- Utf8Str strPreferredLocale(a_bstrPreferredLocale); -- if (strPreferredLocale.length() != 2 && strPreferredLocale.length() != 0) -- return setError(E_FAIL, tr("The preferred locale is a two character string or empty.")); -- -- Utf8Str strPreferredLanguage(a_bstrPreferredLanguage); -- if (strPreferredLanguage.length() != 2 && strPreferredLanguage.length() != 0) -- return setError(E_FAIL, tr("The preferred lanuage is a two character string or empty.")); -- -- Utf8Str strFormat(a_bstrFormat); -- if ( !strFormat.equals("html") -- && !strFormat.equals("rtf") -- && !strFormat.equals("txt")) -- return setError(E_FAIL, tr("The license format can only have the values 'html', 'rtf' and 'txt'.")); -- -- /* -- * Combine the options to form a file name before locking down anything. -- */ -- char szName[sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX "-de_DE.html") + 2]; -- if (strPreferredLocale.isNotEmpty() && strPreferredLanguage.isNotEmpty()) -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s_%s.%s", -- strPreferredLocale.c_str(), strPreferredLanguage.c_str(), strFormat.c_str()); -- else if (strPreferredLocale.isNotEmpty()) -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s.%s", strPreferredLocale.c_str(), strFormat.c_str()); -- else if (strPreferredLanguage.isNotEmpty()) -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-_%s.%s", strPreferredLocale.c_str(), strFormat.c_str()); -- else -- RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX ".%s", strFormat.c_str()); -- -- /* -- * Effectuate the query. -- */ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); /* paranoia */ -- -- if (!m->fUsable) -- hrc = setError(E_FAIL, tr("%s"), m->strWhyUnusable.c_str()); -- else -- { -- char szPath[RTPATH_MAX]; -- int vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), szName); -- if (RT_SUCCESS(vrc)) -- { -- void *pvFile; -- size_t cbFile; -- vrc = RTFileReadAllEx(szPath, 0, RTFOFF_MAX, RTFILE_RDALL_O_DENY_READ, &pvFile, &cbFile); -- if (RT_SUCCESS(vrc)) -- { -- Bstr bstrLicense((const char *)pvFile, cbFile); -- if (bstrLicense.isNotEmpty()) -- { -- bstrLicense.detachTo(a_pbstrLicense); -- hrc = S_OK; -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, tr("The license file '%s' is empty or contains invalid UTF-8 encoding"), -- szPath); -- RTFileReadAllFree(pvFile, cbFile); -- } -- else if (vrc == VERR_FILE_NOT_FOUND || vrc == VERR_PATH_NOT_FOUND) -- hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The license file '%s' was not found in extension pack '%s'"), -- szName, m->Desc.strName.c_str()); -- else -- hrc = setError(VBOX_E_FILE_ERROR, tr("Failed to open the license file '%s': %Rrc"), szPath, vrc); -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, tr("RTPathJoin failed: %Rrc"), vrc); -- } -- } -- return hrc; --} -- -- --STDMETHODIMP ExtPack::QueryObject(IN_BSTR a_bstrObjectId, IUnknown **a_ppUnknown) --{ -- com::Guid ObjectId; -- CheckComArgGuid(a_bstrObjectId, ObjectId); -- CheckComArgOutPointerValid(a_ppUnknown); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- if ( m->pReg -- && m->pReg->pfnQueryObject) -- { -- void *pvUnknown = m->pReg->pfnQueryObject(m->pReg, ObjectId.raw()); -- if (pvUnknown) -- *a_ppUnknown = (IUnknown *)pvUnknown; -- else -- hrc = E_NOINTERFACE; -- } -- else -- hrc = E_NOINTERFACE; -- } -- return hrc; --} -- -- -- -- --DEFINE_EMPTY_CTOR_DTOR(ExtPackManager) -- --/** -- * Called by ComObjPtr::createObject when creating the object. -- * -- * Just initialize the basic object state, do the rest in init(). -- * -- * @returns S_OK. -- */ --HRESULT ExtPackManager::FinalConstruct() --{ -- m = NULL; -- return S_OK; --} -- --/** -- * Initializes the extension pack manager. -- * -- * @returns COM status code. -- * @param a_pVirtualBox Pointer to the VirtualBox object. -- * @param a_enmContext The context we're in. -- */ --HRESULT ExtPackManager::initExtPackManager(VirtualBox *a_pVirtualBox, VBOXEXTPACKCTX a_enmContext) --{ -- AutoInitSpan autoInitSpan(this); -- AssertReturn(autoInitSpan.isOk(), E_FAIL); -- -- /* -- * Figure some stuff out before creating the instance data. -- */ -- char szBaseDir[RTPATH_MAX]; -- int rc = RTPathAppPrivateArchTop(szBaseDir, sizeof(szBaseDir)); -- AssertLogRelRCReturn(rc, E_FAIL); -- rc = RTPathAppend(szBaseDir, sizeof(szBaseDir), VBOX_EXTPACK_INSTALL_DIR); -- AssertLogRelRCReturn(rc, E_FAIL); -- -- char szCertificatDir[RTPATH_MAX]; -- rc = RTPathAppPrivateNoArch(szCertificatDir, sizeof(szCertificatDir)); -- AssertLogRelRCReturn(rc, E_FAIL); -- rc = RTPathAppend(szCertificatDir, sizeof(szCertificatDir), VBOX_EXTPACK_CERT_DIR); -- AssertLogRelRCReturn(rc, E_FAIL); -- -- /* -- * Allocate and initialize the instance data. -- */ -- m = new Data; -- m->strBaseDir = szBaseDir; -- m->strCertificatDirPath = szCertificatDir; -- m->pVirtualBox = a_pVirtualBox; -- m->enmContext = a_enmContext; -- -- /* -- * Slurp in VBoxVMM which is used by VBoxPuelMain. -- */ --#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN) -- if (a_enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON) -- { -- int vrc = SUPR3HardenedLdrLoadAppPriv("VBoxVMM", &m->hVBoxVMM, RTLDRLOAD_FLAGS_GLOBAL, NULL); -- if (RT_FAILURE(vrc)) -- m->hVBoxVMM = NIL_RTLDRMOD; -- /* cleanup in ::uninit()? */ -- } --#endif -- -- /* -- * Go looking for extensions. The RTDirOpen may fail if nothing has been -- * installed yet, or if root is paranoid and has revoked our access to them. -- * -- * We ASSUME that there are no files, directories or stuff in the directory -- * that exceed the max name length in RTDIRENTRYEX. -- */ -- HRESULT hrc = S_OK; -- PRTDIR pDir; -- int vrc = RTDirOpen(&pDir, szBaseDir); -- if (RT_SUCCESS(vrc)) -- { -- for (;;) -- { -- RTDIRENTRYEX Entry; -- vrc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); -- if (RT_FAILURE(vrc)) -- { -- AssertLogRelMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc)); -- break; -- } -- if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode) -- && strcmp(Entry.szName, ".") != 0 -- && strcmp(Entry.szName, "..") != 0 -- && VBoxExtPackIsValidMangledName(Entry.szName) ) -- { -- /* -- * All directories are extensions, the shall be nothing but -- * extensions in this subdirectory. -- */ -- char szExtPackDir[RTPATH_MAX]; -- vrc = RTPathJoin(szExtPackDir, sizeof(szExtPackDir), m->strBaseDir.c_str(), Entry.szName); -- AssertLogRelRC(vrc); -- if (RT_SUCCESS(vrc)) -- { -- RTCString *pstrName = VBoxExtPackUnmangleName(Entry.szName, RTSTR_MAX); -- AssertLogRel(pstrName); -- if (pstrName) -- { -- ComObjPtr<ExtPack> NewExtPack; -- HRESULT hrc2 = NewExtPack.createObject(); -- if (SUCCEEDED(hrc2)) -- hrc2 = NewExtPack->initWithDir(a_enmContext, pstrName->c_str(), szExtPackDir); -- delete pstrName; -- if (SUCCEEDED(hrc2)) -- m->llInstalledExtPacks.push_back(NewExtPack); -- else if (SUCCEEDED(rc)) -- hrc = hrc2; -- } -- else -- hrc = E_UNEXPECTED; -- } -- else -- hrc = E_UNEXPECTED; -- } -- } -- RTDirClose(pDir); -- } -- /* else: ignore, the directory probably does not exist or something. */ -- -- if (SUCCEEDED(hrc)) -- autoInitSpan.setSucceeded(); -- return hrc; --} -- --/** -- * COM cruft. -- */ --void ExtPackManager::FinalRelease() --{ -- uninit(); --} -- --/** -- * Do the actual cleanup. -- */ --void ExtPackManager::uninit() --{ -- /* Enclose the state transition Ready->InUninit->NotReady */ -- AutoUninitSpan autoUninitSpan(this); -- if (!autoUninitSpan.uninitDone() && m != NULL) -- { -- delete m; -- m = NULL; -- } --} -- -- --STDMETHODIMP ExtPackManager::COMGETTER(InstalledExtPacks)(ComSafeArrayOut(IExtPack *, a_paExtPacks)) --{ -- CheckComArgOutSafeArrayPointerValid(a_paExtPacks); -- Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- SafeIfaceArray<IExtPack> SaExtPacks(m->llInstalledExtPacks); -- SaExtPacks.detachTo(ComSafeArrayOutArg(a_paExtPacks)); -- } -- -- return hrc; --} -- --STDMETHODIMP ExtPackManager::Find(IN_BSTR a_bstrName, IExtPack **a_pExtPack) --{ -- CheckComArgNotNull(a_bstrName); -- CheckComArgOutPointerValid(a_pExtPack); -- Utf8Str strName(a_bstrName); -- Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- ComPtr<ExtPack> ptrExtPack = findExtPack(strName.c_str()); -- if (!ptrExtPack.isNull()) -- ptrExtPack.queryInterfaceTo(a_pExtPack); -- else -- hrc = VBOX_E_OBJECT_NOT_FOUND; -- } -- -- return hrc; --} -- --STDMETHODIMP ExtPackManager::OpenExtPackFile(IN_BSTR a_bstrTarballAndDigest, IExtPackFile **a_ppExtPackFile) --{ -- CheckComArgNotNull(a_bstrTarballAndDigest); -- CheckComArgOutPointerValid(a_ppExtPackFile); -- AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED); -- -- /* The API can optionally take a ::SHA-256=<hex-digest> attribute at the -- end of the file name. This is just a temporary measure for -- backporting, in 4.2 we'll add another parameter to the method. */ -- Utf8Str strTarball; -- Utf8Str strDigest; -- Utf8Str strTarballAndDigest(a_bstrTarballAndDigest); -- size_t offSha256 = strTarballAndDigest.find("::SHA-256="); -- if (offSha256 == Utf8Str::npos) -- strTarball = strTarballAndDigest; -- else -- { -- strTarball = strTarballAndDigest.substr(0, offSha256); -- strDigest = strTarballAndDigest.substr(offSha256 + sizeof("::SHA-256=") - 1); -- } -- -- ComObjPtr<ExtPackFile> NewExtPackFile; -- HRESULT hrc = NewExtPackFile.createObject(); -- if (SUCCEEDED(hrc)) -- hrc = NewExtPackFile->initWithFile(strTarball.c_str(), strDigest.c_str(), this, m->pVirtualBox); -- if (SUCCEEDED(hrc)) -- NewExtPackFile.queryInterfaceTo(a_ppExtPackFile); -- -- return hrc; --} -- --STDMETHODIMP ExtPackManager::Uninstall(IN_BSTR a_bstrName, BOOL a_fForcedRemoval, IN_BSTR a_bstrDisplayInfo, -- IProgress **a_ppProgress) --{ -- CheckComArgNotNull(a_bstrName); -- if (a_ppProgress) -- *a_ppProgress = NULL; -- Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- PEXTPACKUNINSTALLJOB pJob = NULL; -- try -- { -- pJob = new EXTPACKUNINSTALLJOB; -- pJob->ptrExtPackMgr = this; -- pJob->strName = a_bstrName; -- pJob->fForcedRemoval = a_fForcedRemoval != FALSE; -- pJob->strDisplayInfo = a_bstrDisplayInfo; -- hrc = pJob->ptrProgress.createObject(); -- if (SUCCEEDED(hrc)) -- { -- Bstr bstrDescription = tr("Uninstalling extension pack"); -- hrc = pJob->ptrProgress->init( --#ifndef VBOX_COM_INPROC -- m->pVirtualBox, --#endif -- static_cast<IExtPackManager *>(this), -- bstrDescription.raw(), -- FALSE /*aCancelable*/, -- NULL /*aId*/); -- } -- if (SUCCEEDED(hrc)) -- { -- ComPtr<Progress> ptrProgress = pJob->ptrProgress; -- int vrc = RTThreadCreate(NULL /*phThread*/, ExtPackManager::doUninstallThreadProc, pJob, 0, -- RTTHREADTYPE_DEFAULT, 0 /*fFlags*/, "ExtPackUninst"); -- if (RT_SUCCESS(vrc)) -- { -- pJob = NULL; /* the thread deletes it */ -- ptrProgress.queryInterfaceTo(a_ppProgress); -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, tr("RTThreadCreate failed with %Rrc"), vrc); -- } -- } -- catch (std::bad_alloc) -- { -- hrc = E_OUTOFMEMORY; -- } -- if (pJob) -- delete pJob; -- } -- -- return hrc; --} -- --STDMETHODIMP ExtPackManager::Cleanup(void) --{ -- Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- /* -- * Run the set-uid-to-root binary that performs the cleanup. -- * -- * Take the write lock to prevent conflicts with other calls to this -- * VBoxSVC instance. -- */ -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- hrc = runSetUidToRootHelper(NULL, -- "cleanup", -- "--base-dir", m->strBaseDir.c_str(), -- (const char *)NULL); -- } -- -- return hrc; --} -- --STDMETHODIMP ExtPackManager::QueryAllPlugInsForFrontend(IN_BSTR a_bstrFrontend, ComSafeArrayOut(BSTR, a_pabstrPlugInModules)) --{ -- CheckComArgNotNull(a_bstrFrontend); -- Utf8Str strName(a_bstrFrontend); -- CheckComArgOutSafeArrayPointerValid(a_pabstrPlugInModules); -- Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- com::SafeArray<BSTR> saPaths((size_t)0); -- /** @todo implement plug-ins */ -- saPaths.detachTo(ComSafeArrayOutArg(a_pabstrPlugInModules)); -- } -- return hrc; --} -- --STDMETHODIMP ExtPackManager::IsExtPackUsable(IN_BSTR a_bstrExtPack, BOOL *aUsable) --{ -- CheckComArgNotNull(a_bstrExtPack); -- Utf8Str strExtPack(a_bstrExtPack); -- *aUsable = isExtPackUsable(strExtPack.c_str()); -- return S_OK; --} -- --/** -- * Finds the success indicator string in the stderr output ofr hte helper app. -- * -- * @returns Pointer to the indicator. -- * @param psz The stderr output string. Can be NULL. -- * @param cch The size of the string. -- */ --static char *findSuccessIndicator(char *psz, size_t cch) --{ -- static const char s_szSuccessInd[] = "rcExit=RTEXITCODE_SUCCESS"; -- Assert(!cch || strlen(psz) == cch); -- if (cch < sizeof(s_szSuccessInd) - 1) -- return NULL; -- char *pszInd = &psz[cch - sizeof(s_szSuccessInd) + 1]; -- if (strcmp(s_szSuccessInd, pszInd)) -- return NULL; -- return pszInd; --} -- --/** -- * Runs the helper application that does the privileged operations. -- * -- * @returns S_OK or a failure status with error information set. -- * @param a_pstrDisplayInfo Platform specific display info hacks. -- * @param a_pszCommand The command to execute. -- * @param ... The argument strings that goes along with the -- * command. Maximum is about 16. Terminated by a -- * NULL. -- */ --HRESULT ExtPackManager::runSetUidToRootHelper(Utf8Str const *a_pstrDisplayInfo, const char *a_pszCommand, ...) --{ -- /* -- * Calculate the path to the helper application. -- */ -- char szExecName[RTPATH_MAX]; -- int vrc = RTPathAppPrivateArch(szExecName, sizeof(szExecName)); -- AssertLogRelRCReturn(vrc, E_UNEXPECTED); -- -- vrc = RTPathAppend(szExecName, sizeof(szExecName), VBOX_EXTPACK_HELPER_NAME); -- AssertLogRelRCReturn(vrc, E_UNEXPECTED); -- -- /* -- * Convert the variable argument list to a RTProcCreate argument vector. -- */ -- const char *apszArgs[20]; -- unsigned cArgs = 0; -- -- LogRel(("ExtPack: Executing '%s'", szExecName)); -- apszArgs[cArgs++] = &szExecName[0]; -- -- if ( a_pstrDisplayInfo -- && a_pstrDisplayInfo->isNotEmpty()) -- { -- LogRel((" '--display-info-hack' '%s'", a_pstrDisplayInfo->c_str())); -- apszArgs[cArgs++] = "--display-info-hack"; -- apszArgs[cArgs++] = a_pstrDisplayInfo->c_str(); -- } -- -- LogRel(("'%s'", a_pszCommand)); -- apszArgs[cArgs++] = a_pszCommand; -- -- va_list va; -- va_start(va, a_pszCommand); -- const char *pszLastArg; -- for (;;) -- { -- AssertReturn(cArgs < RT_ELEMENTS(apszArgs) - 1, E_UNEXPECTED); -- pszLastArg = va_arg(va, const char *); -- if (!pszLastArg) -- break; -- LogRel((" '%s'", pszLastArg)); -- apszArgs[cArgs++] = pszLastArg; -- }; -- va_end(va); -- -- LogRel(("\n")); -- apszArgs[cArgs] = NULL; -- -- /* -- * Create a PIPE which we attach to stderr so that we can read the error -- * message on failure and report it back to the caller. -- */ -- RTPIPE hPipeR; -- RTHANDLE hStdErrPipe; -- hStdErrPipe.enmType = RTHANDLETYPE_PIPE; -- vrc = RTPipeCreate(&hPipeR, &hStdErrPipe.u.hPipe, RTPIPE_C_INHERIT_WRITE); -- AssertLogRelRCReturn(vrc, E_UNEXPECTED); -- -- /* -- * Spawn the process. -- */ -- HRESULT hrc; -- RTPROCESS hProcess; -- vrc = RTProcCreateEx(szExecName, -- apszArgs, -- RTENV_DEFAULT, -- 0 /*fFlags*/, -- NULL /*phStdIn*/, -- NULL /*phStdOut*/, -- &hStdErrPipe, -- NULL /*pszAsUser*/, -- NULL /*pszPassword*/, -- &hProcess); -- if (RT_SUCCESS(vrc)) -- { -- vrc = RTPipeClose(hStdErrPipe.u.hPipe); -- hStdErrPipe.u.hPipe = NIL_RTPIPE; -- -- /* -- * Read the pipe output until the process completes. -- */ -- RTPROCSTATUS ProcStatus = { -42, RTPROCEXITREASON_ABEND }; -- size_t cbStdErrBuf = 0; -- size_t offStdErrBuf = 0; -- char *pszStdErrBuf = NULL; -- do -- { -- /* -- * Service the pipe. Block waiting for output or the pipe breaking -- * when the process terminates. -- */ -- if (hPipeR != NIL_RTPIPE) -- { -- char achBuf[1024]; -- size_t cbRead; -- vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead); -- if (RT_SUCCESS(vrc)) -- { -- /* grow the buffer? */ -- size_t cbBufReq = offStdErrBuf + cbRead + 1; -- if ( cbBufReq > cbStdErrBuf -- && cbBufReq < _256K) -- { -- size_t cbNew = RT_ALIGN_Z(cbBufReq, 16); // 1024 -- void *pvNew = RTMemRealloc(pszStdErrBuf, cbNew); -- if (pvNew) -- { -- pszStdErrBuf = (char *)pvNew; -- cbStdErrBuf = cbNew; -- } -- } -- -- /* append if we've got room. */ -- if (cbBufReq <= cbStdErrBuf) -- { -- memcpy(&pszStdErrBuf[offStdErrBuf], achBuf, cbRead); -- offStdErrBuf = offStdErrBuf + cbRead; -- pszStdErrBuf[offStdErrBuf] = '\0'; -- } -- } -- else -- { -- AssertLogRelMsg(vrc == VERR_BROKEN_PIPE, ("%Rrc\n", vrc)); -- RTPipeClose(hPipeR); -- hPipeR = NIL_RTPIPE; -- } -- } -- -- /* -- * Service the process. Block if we have no pipe. -- */ -- if (hProcess != NIL_RTPROCESS) -- { -- vrc = RTProcWait(hProcess, -- hPipeR == NIL_RTPIPE ? RTPROCWAIT_FLAGS_BLOCK : RTPROCWAIT_FLAGS_NOBLOCK, -- &ProcStatus); -- if (RT_SUCCESS(vrc)) -- hProcess = NIL_RTPROCESS; -- else -- AssertLogRelMsgStmt(vrc == VERR_PROCESS_RUNNING, ("%Rrc\n", vrc), hProcess = NIL_RTPROCESS); -- } -- } while ( hPipeR != NIL_RTPIPE -- || hProcess != NIL_RTPROCESS); -- -- LogRel(("ExtPack: enmReason=%d iStatus=%d stderr='%s'\n", -- ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "")); -- -- /* -- * Look for rcExit=RTEXITCODE_SUCCESS at the end of the error output, -- * cut it as it is only there to attest the success. -- */ -- if (offStdErrBuf > 0) -- { -- RTStrStripR(pszStdErrBuf); -- offStdErrBuf = strlen(pszStdErrBuf); -- } -- -- char *pszSuccessInd = findSuccessIndicator(pszStdErrBuf, offStdErrBuf); -- if (pszSuccessInd) -- { -- *pszSuccessInd = '\0'; -- offStdErrBuf = pszSuccessInd - pszStdErrBuf; -- } -- else if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL -- && ProcStatus.iStatus == 0) -- ProcStatus.iStatus = offStdErrBuf ? 667 : 666; -- -- /* -- * Compose the status code and, on failure, error message. -- */ -- if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL -- && ProcStatus.iStatus == 0) -- hrc = S_OK; -- else if (ProcStatus.enmReason == RTPROCEXITREASON_NORMAL) -- { -- AssertMsg(ProcStatus.iStatus != 0, ("%s\n", pszStdErrBuf)); -- hrc = setError(E_FAIL, tr("The installer failed with exit code %d: %s"), -- ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""); -- } -- else if (ProcStatus.enmReason == RTPROCEXITREASON_SIGNAL) -- hrc = setError(E_UNEXPECTED, tr("The installer was killed by signal #d (stderr: %s)"), -- ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""); -- else if (ProcStatus.enmReason == RTPROCEXITREASON_ABEND) -- hrc = setError(E_UNEXPECTED, tr("The installer aborted abnormally (stderr: %s)"), -- offStdErrBuf ? pszStdErrBuf : ""); -- else -- hrc = setError(E_UNEXPECTED, tr("internal error: enmReason=%d iStatus=%d stderr='%s'"), -- ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""); -- -- RTMemFree(pszStdErrBuf); -- } -- else -- hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to launch the helper application '%s' (%Rrc)"), szExecName, vrc); -- -- RTPipeClose(hPipeR); -- RTPipeClose(hStdErrPipe.u.hPipe); -- -- return hrc; --} -- --/** -- * Finds an installed extension pack. -- * -- * @returns Pointer to the extension pack if found, NULL if not. (No reference -- * counting problem here since the caller must be holding the lock.) -- * @param a_pszName The name of the extension pack. -- */ --ExtPack *ExtPackManager::findExtPack(const char *a_pszName) --{ -- size_t cchName = strlen(a_pszName); -- -- for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); -- it != m->llInstalledExtPacks.end(); -- it++) -- { -- ExtPack::Data *pExtPackData = (*it)->m; -- if ( pExtPackData -- && pExtPackData->Desc.strName.length() == cchName -- && pExtPackData->Desc.strName.equalsIgnoreCase(a_pszName)) -- return (*it); -- } -- return NULL; --} -- --/** -- * Removes an installed extension pack from the internal list. -- * -- * The package is expected to exist! -- * -- * @param a_pszName The name of the extension pack. -- */ --void ExtPackManager::removeExtPack(const char *a_pszName) --{ -- size_t cchName = strlen(a_pszName); -- -- for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); -- it != m->llInstalledExtPacks.end(); -- it++) -- { -- ExtPack::Data *pExtPackData = (*it)->m; -- if ( pExtPackData -- && pExtPackData->Desc.strName.length() == cchName -- && pExtPackData->Desc.strName.equalsIgnoreCase(a_pszName)) -- { -- m->llInstalledExtPacks.erase(it); -- return; -- } -- } -- AssertMsgFailed(("%s\n", a_pszName)); --} -- --/** -- * Refreshes the specified extension pack. -- * -- * This may remove the extension pack from the list, so any non-smart pointers -- * to the extension pack object may become invalid. -- * -- * @returns S_OK and *a_ppExtPack on success, COM status code and error -- * message on failure. Note that *a_ppExtPack can be NULL. -- * -- * @param a_pszName The extension to update.. -- * @param a_fUnusableIsError If @c true, report an unusable extension pack -- * as an error. -- * @param a_ppExtPack Where to store the pointer to the extension -- * pack of it is still around after the refresh. -- * This is optional. -- * -- * @remarks Caller holds the extension manager lock. -- * @remarks Only called in VBoxSVC. -- */ --HRESULT ExtPackManager::refreshExtPack(const char *a_pszName, bool a_fUnusableIsError, ExtPack **a_ppExtPack) --{ -- Assert(m->pVirtualBox != NULL); /* Only called from VBoxSVC. */ -- -- HRESULT hrc; -- ExtPack *pExtPack = findExtPack(a_pszName); -- if (pExtPack) -- { -- /* -- * Refresh existing object. -- */ -- bool fCanDelete; -- hrc = pExtPack->refresh(&fCanDelete); -- if (SUCCEEDED(hrc)) -- { -- if (fCanDelete) -- { -- removeExtPack(a_pszName); -- pExtPack = NULL; -- } -- } -- } -- else -- { -- /* -- * Do this check here, otherwise VBoxExtPackCalcDir() will fail with a strange -- * error. -- */ -- bool fValid = VBoxExtPackIsValidName(a_pszName); -- if (!fValid) -- return setError(E_FAIL, "Invalid extension pack name specified"); -- -- /* -- * Does the dir exist? Make some special effort to deal with case -- * sensitivie file systems (a_pszName is case insensitive and mangled). -- */ -- char szDir[RTPATH_MAX]; -- int vrc = VBoxExtPackCalcDir(szDir, sizeof(szDir), m->strBaseDir.c_str(), a_pszName); -- AssertLogRelRCReturn(vrc, E_FAIL); -- -- RTDIRENTRYEX Entry; -- RTFSOBJINFO ObjInfo; -- vrc = RTPathQueryInfoEx(szDir, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); -- bool fExists = RT_SUCCESS(vrc) && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode); -- if (!fExists) -- { -- PRTDIR pDir; -- vrc = RTDirOpen(&pDir, m->strBaseDir.c_str()); -- if (RT_SUCCESS(vrc)) -- { -- const char *pszMangledName = RTPathFilename(szDir); -- for (;;) -- { -- vrc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK); -- if (RT_FAILURE(vrc)) -- { -- AssertLogRelMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc)); -- break; -- } -- if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode) -- && !RTStrICmp(Entry.szName, pszMangledName)) -- { -- /* -- * The installed extension pack has a uses different case. -- * Update the name and directory variables. -- */ -- vrc = RTPathJoin(szDir, sizeof(szDir), m->strBaseDir.c_str(), Entry.szName); /* not really necessary */ -- AssertLogRelRCReturnStmt(vrc, RTDirClose(pDir), E_UNEXPECTED); -- a_pszName = Entry.szName; -- fExists = true; -- break; -- } -- } -- RTDirClose(pDir); -- } -- } -- if (fExists) -- { -- /* -- * We've got something, create a new extension pack object for it. -- */ -- ComObjPtr<ExtPack> ptrNewExtPack; -- hrc = ptrNewExtPack.createObject(); -- if (SUCCEEDED(hrc)) -- hrc = ptrNewExtPack->initWithDir(m->enmContext, a_pszName, szDir); -- if (SUCCEEDED(hrc)) -- { -- m->llInstalledExtPacks.push_back(ptrNewExtPack); -- if (ptrNewExtPack->m->fUsable) -- LogRel(("ExtPackManager: Found extension pack '%s'.\n", a_pszName)); -- else -- LogRel(("ExtPackManager: Found bad extension pack '%s': %s\n", -- a_pszName, ptrNewExtPack->m->strWhyUnusable.c_str() )); -- pExtPack = ptrNewExtPack; -- } -- } -- else -- hrc = S_OK; -- } -- -- /* -- * Report error if not usable, if that is desired. -- */ -- if ( SUCCEEDED(hrc) -- && pExtPack -- && a_fUnusableIsError -- && !pExtPack->m->fUsable) -- hrc = setError(E_FAIL, "%s", pExtPack->m->strWhyUnusable.c_str()); -- -- if (a_ppExtPack) -- *a_ppExtPack = pExtPack; -- return hrc; --} -- --/** -- * Thread wrapper around doInstall. -- * -- * @returns VINF_SUCCESS (ignored) -- * @param hThread The thread handle (ignored). -- * @param pvJob The job structure. -- */ --/*static*/ DECLCALLBACK(int) ExtPackManager::doInstallThreadProc(RTTHREAD hThread, void *pvJob) --{ -- PEXTPACKINSTALLJOB pJob = (PEXTPACKINSTALLJOB)pvJob; -- HRESULT hrc = pJob->ptrExtPackMgr->doInstall(pJob->ptrExtPackFile, pJob->fReplace, &pJob->strDisplayInfo); -- pJob->ptrProgress->notifyComplete(hrc); -- delete pJob; -- -- NOREF(hThread); -- return VINF_SUCCESS; --} -- --/** -- * Worker for IExtPackFile::Install. -- * -- * Called on a worker thread via doInstallThreadProc. -- * -- * @returns COM status code. -- * @param a_pExtPackFile The extension pack file, caller checks that -- * it's usable. -- * @param a_fReplace Whether to replace any existing extpack or just -- * fail. -- * @param a_pstrDisplayInfo Host specific display information hacks. -- * @param a_ppProgress Where to return a progress object some day. Can -- * be NULL. -- */ --HRESULT ExtPackManager::doInstall(ExtPackFile *a_pExtPackFile, bool a_fReplace, Utf8Str const *a_pstrDisplayInfo) --{ -- AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED); -- RTCString const * const pStrName = &a_pExtPackFile->m->Desc.strName; -- RTCString const * const pStrTarball = &a_pExtPackFile->m->strExtPackFile; -- RTCString const * const pStrTarballDigest = &a_pExtPackFile->m->strDigest; -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- /* -- * Refresh the data we have on the extension pack as it -- * may be made stale by direct meddling or some other user. -- */ -- ExtPack *pExtPack; -- hrc = refreshExtPack(pStrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack); -- if (SUCCEEDED(hrc)) -- { -- if (pExtPack && a_fReplace) -- hrc = pExtPack->callUninstallHookAndClose(m->pVirtualBox, false /*a_ForcedRemoval*/); -- else if (pExtPack) -- hrc = setError(E_FAIL, -- tr("Extension pack '%s' is already installed." -- " In case of a reinstallation, please uninstall it first"), -- pStrName->c_str()); -- } -- if (SUCCEEDED(hrc)) -- { -- /* -- * Run the privileged helper binary that performs the actual -- * installation. Then create an object for the packet (we do this -- * even on failure, to be on the safe side). -- */ -- hrc = runSetUidToRootHelper(a_pstrDisplayInfo, -- "install", -- "--base-dir", m->strBaseDir.c_str(), -- "--cert-dir", m->strCertificatDirPath.c_str(), -- "--name", pStrName->c_str(), -- "--tarball", pStrTarball->c_str(), -- "--sha-256", pStrTarballDigest->c_str(), -- pExtPack ? "--replace" : (const char *)NULL, -- (const char *)NULL); -- if (SUCCEEDED(hrc)) -- { -- hrc = refreshExtPack(pStrName->c_str(), true /*a_fUnusableIsError*/, &pExtPack); -- if (SUCCEEDED(hrc) && pExtPack) -- { -- RTERRINFOSTATIC ErrInfo; -- RTErrInfoInitStatic(&ErrInfo); -- pExtPack->callInstalledHook(m->pVirtualBox, &autoLock, &ErrInfo.Core); -- if (RT_SUCCESS(ErrInfo.Core.rc)) -- LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pStrName->c_str())); -- else -- { -- LogRel(("ExtPackManager: Installated hook for '%s' failed: %Rrc - %s\n", -- pStrName->c_str(), ErrInfo.Core.rc, ErrInfo.Core.pszMsg)); -- -- /* -- * Uninstall the extpack if the error indicates that. -- */ -- if (ErrInfo.Core.rc == VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL) -- runSetUidToRootHelper(a_pstrDisplayInfo, -- "uninstall", -- "--base-dir", m->strBaseDir.c_str(), -- "--name", pStrName->c_str(), -- "--forced", -- (const char *)NULL); -- hrc = setError(E_FAIL, tr("The installation hook failed: %Rrc - %s"), -- ErrInfo.Core.rc, ErrInfo.Core.pszMsg); -- } -- } -- else if (SUCCEEDED(hrc)) -- hrc = setError(E_FAIL, tr("Installing extension pack '%s' failed under mysterious circumstances"), -- pStrName->c_str()); -- } -- else -- { -- ErrorInfoKeeper Eik; -- refreshExtPack(pStrName->c_str(), false /*a_fUnusableIsError*/, NULL); -- } -- } -- -- /* -- * Do VirtualBoxReady callbacks now for any freshly installed -- * extension pack (old ones will not be called). -- */ -- if (m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON) -- { -- autoLock.release(); -- callAllVirtualBoxReadyHooks(); -- } -- } -- -- return hrc; --} -- --/** -- * Thread wrapper around doUninstall. -- * -- * @returns VINF_SUCCESS (ignored) -- * @param hThread The thread handle (ignored). -- * @param pvJob The job structure. -- */ --/*static*/ DECLCALLBACK(int) ExtPackManager::doUninstallThreadProc(RTTHREAD hThread, void *pvJob) --{ -- PEXTPACKUNINSTALLJOB pJob = (PEXTPACKUNINSTALLJOB)pvJob; -- HRESULT hrc = pJob->ptrExtPackMgr->doUninstall(&pJob->strName, pJob->fForcedRemoval, &pJob->strDisplayInfo); -- pJob->ptrProgress->notifyComplete(hrc); -- delete pJob; -- -- NOREF(hThread); -- return VINF_SUCCESS; --} -- --/** -- * Worker for IExtPackManager::Uninstall. -- * -- * Called on a worker thread via doUninstallThreadProc. -- * -- * @returns COM status code. -- * @param a_pstrName The name of the extension pack to uninstall. -- * @param a_fForcedRemoval Whether to be skip and ignore certain bits of -- * the extpack feedback. To deal with misbehaving -- * extension pack hooks. -- * @param a_pstrDisplayInfo Host specific display information hacks. -- */ --HRESULT ExtPackManager::doUninstall(Utf8Str const *a_pstrName, bool a_fForcedRemoval, Utf8Str const *a_pstrDisplayInfo) --{ -- Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- /* -- * Refresh the data we have on the extension pack as it may be made -- * stale by direct meddling or some other user. -- */ -- ExtPack *pExtPack; -- hrc = refreshExtPack(a_pstrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack); -- if (SUCCEEDED(hrc)) -- { -- if (!pExtPack) -- { -- LogRel(("ExtPackManager: Extension pack '%s' is not installed, so nothing to uninstall.\n", a_pstrName->c_str())); -- hrc = S_OK; /* nothing to uninstall */ -- } -- else -- { -- /* -- * Call the uninstall hook and unload the main dll. -- */ -- hrc = pExtPack->callUninstallHookAndClose(m->pVirtualBox, a_fForcedRemoval); -- if (SUCCEEDED(hrc)) -- { -- /* -- * Run the set-uid-to-root binary that performs the -- * uninstallation. Then refresh the object. -- * -- * This refresh is theorically subject to races, but it's of -- * the don't-do-that variety. -- */ -- const char *pszForcedOpt = a_fForcedRemoval ? "--forced" : NULL; -- hrc = runSetUidToRootHelper(a_pstrDisplayInfo, -- "uninstall", -- "--base-dir", m->strBaseDir.c_str(), -- "--name", a_pstrName->c_str(), -- pszForcedOpt, /* Last as it may be NULL. */ -- (const char *)NULL); -- if (SUCCEEDED(hrc)) -- { -- hrc = refreshExtPack(a_pstrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack); -- if (SUCCEEDED(hrc)) -- { -- if (!pExtPack) -- LogRel(("ExtPackManager: Successfully uninstalled extension pack '%s'.\n", a_pstrName->c_str())); -- else -- hrc = setError(E_FAIL, -- tr("Uninstall extension pack '%s' failed under mysterious circumstances"), -- a_pstrName->c_str()); -- } -- } -- else -- { -- ErrorInfoKeeper Eik; -- refreshExtPack(a_pstrName->c_str(), false /*a_fUnusableIsError*/, NULL); -- } -- } -- } -- } -- -- /* -- * Do VirtualBoxReady callbacks now for any freshly installed -- * extension pack (old ones will not be called). -- */ -- if (m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON) -- { -- autoLock.release(); -- callAllVirtualBoxReadyHooks(); -- } -- } -- -- return hrc; --} -- -- --/** -- * Calls the pfnVirtualBoxReady hook for all working extension packs. -- * -- * @remarks The caller must not hold any locks. -- */ --void ExtPackManager::callAllVirtualBoxReadyHooks(void) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return; -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- ComPtr<ExtPackManager> ptrSelfRef = this; -- -- for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); -- it != m->llInstalledExtPacks.end(); -- /* advancing below */) -- { -- if ((*it)->callVirtualBoxReadyHook(m->pVirtualBox, &autoLock)) -- it = m->llInstalledExtPacks.begin(); -- else -- it++; -- } --} -- --/** -- * Calls the pfnConsoleReady hook for all working extension packs. -- * -- * @param a_pConsole The console interface. -- * @remarks The caller must not hold any locks. -- */ --void ExtPackManager::callAllConsoleReadyHooks(IConsole *a_pConsole) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return; -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- ComPtr<ExtPackManager> ptrSelfRef = this; -- -- for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); -- it != m->llInstalledExtPacks.end(); -- /* advancing below */) -- { -- if ((*it)->callConsoleReadyHook(a_pConsole, &autoLock)) -- it = m->llInstalledExtPacks.begin(); -- else -- it++; -- } --} -- --/** -- * Calls the pfnVMCreated hook for all working extension packs. -- * -- * @param a_pMachine The machine interface of the new VM. -- */ --void ExtPackManager::callAllVmCreatedHooks(IMachine *a_pMachine) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return; -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */ -- ExtPackList llExtPacks = m->llInstalledExtPacks; -- -- for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); it++) -- (*it)->callVmCreatedHook(m->pVirtualBox, a_pMachine, &autoLock); --} -- --/** -- * Calls the pfnVMConfigureVMM hook for all working extension packs. -- * -- * @returns VBox status code. Stops on the first failure, expecting the caller -- * to signal this to the caller of the CFGM constructor. -- * @param a_pConsole The console interface for the VM. -- * @param a_pVM The VM handle. -- */ --int ExtPackManager::callAllVmConfigureVmmHooks(IConsole *a_pConsole, PVM a_pVM) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return Global::vboxStatusCodeFromCOM(hrc); -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */ -- ExtPackList llExtPacks = m->llInstalledExtPacks; -- -- for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); it++) -- { -- int vrc; -- (*it)->callVmConfigureVmmHook(a_pConsole, a_pVM, &autoLock, &vrc); -- if (RT_FAILURE(vrc)) -- return vrc; -- } -- -- return VINF_SUCCESS; --} -- --/** -- * Calls the pfnVMPowerOn hook for all working extension packs. -- * -- * @returns VBox status code. Stops on the first failure, expecting the caller -- * to not power on the VM. -- * @param a_pConsole The console interface for the VM. -- * @param a_pVM The VM handle. -- */ --int ExtPackManager::callAllVmPowerOnHooks(IConsole *a_pConsole, PVM a_pVM) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return Global::vboxStatusCodeFromCOM(hrc); -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */ -- ExtPackList llExtPacks = m->llInstalledExtPacks; -- -- for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); it++) -- { -- int vrc; -- (*it)->callVmPowerOnHook(a_pConsole, a_pVM, &autoLock, &vrc); -- if (RT_FAILURE(vrc)) -- return vrc; -- } -- -- return VINF_SUCCESS; --} -- --/** -- * Calls the pfnVMPowerOff hook for all working extension packs. -- * -- * @param a_pConsole The console interface for the VM. -- * @param a_pVM The VM handle. Can be NULL. -- */ --void ExtPackManager::callAllVmPowerOffHooks(IConsole *a_pConsole, PVM a_pVM) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return; -- AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */ -- ExtPackList llExtPacks = m->llInstalledExtPacks; -- -- for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); it++) -- (*it)->callVmPowerOffHook(a_pConsole, a_pVM, &autoLock); --} -- -- --/** -- * Checks that the specified extension pack contains a VRDE module and that it -- * is shipshape. -- * -- * @returns S_OK if ok, appropriate failure status code with details. -- * @param a_pstrExtPack The name of the extension pack. -- */ --HRESULT ExtPackManager::checkVrdeExtPack(Utf8Str const *a_pstrExtPack) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- ExtPack *pExtPack = findExtPack(a_pstrExtPack->c_str()); -- if (pExtPack) -- hrc = pExtPack->checkVrde(); -- else -- hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"), a_pstrExtPack->c_str()); -- } -- -- return hrc; --} -- --/** -- * Gets the full path to the VRDE library of the specified extension pack. -- * -- * This will do extacly the same as checkVrdeExtPack and then resolve the -- * library path. -- * -- * @returns S_OK if a path is returned, COM error status and message return if -- * not. -- * @param a_pstrExtPack The extension pack. -- * @param a_pstrVrdeLibrary Where to return the path. -- */ --int ExtPackManager::getVrdeLibraryPathForExtPack(Utf8Str const *a_pstrExtPack, Utf8Str *a_pstrVrdeLibrary) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- ExtPack *pExtPack = findExtPack(a_pstrExtPack->c_str()); -- if (pExtPack) -- hrc = pExtPack->getVrdpLibraryName(a_pstrVrdeLibrary); -- else -- hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"), a_pstrExtPack->c_str()); -- } -- -- return hrc; --} -- --/** -- * Gets the name of the default VRDE extension pack. -- * -- * @returns S_OK or some COM error status on red tape failure. -- * @param a_pstrExtPack Where to return the extension pack name. Returns -- * empty if no extension pack wishes to be the default -- * VRDP provider. -- */ --HRESULT ExtPackManager::getDefaultVrdeExtPack(Utf8Str *a_pstrExtPack) --{ -- a_pstrExtPack->setNull(); -- -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (SUCCEEDED(hrc)) -- { -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); -- it != m->llInstalledExtPacks.end(); -- it++) -- { -- if ((*it)->wantsToBeDefaultVrde()) -- { -- *a_pstrExtPack = (*it)->m->Desc.strName; -- break; -- } -- } -- } -- return hrc; --} -- --/** -- * Checks if an extension pack is (present and) usable. -- * -- * @returns @c true if it is, otherwise @c false. -- * @param a_pszExtPack The name of the extension pack. -- */ --bool ExtPackManager::isExtPackUsable(const char *a_pszExtPack) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return false; -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- ExtPack *pExtPack = findExtPack(a_pszExtPack); -- return pExtPack != NULL -- && pExtPack->m->fUsable; --} -- --/** -- * Dumps all extension packs to the release log. -- */ --void ExtPackManager::dumpAllToReleaseLog(void) --{ -- AutoCaller autoCaller(this); -- HRESULT hrc = autoCaller.rc(); -- if (FAILED(hrc)) -- return; -- AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); -- -- LogRel(("Installed Extension Packs:\n")); -- for (ExtPackList::iterator it = m->llInstalledExtPacks.begin(); -- it != m->llInstalledExtPacks.end(); -- it++) -- { -- ExtPack::Data *pExtPackData = (*it)->m; -- if (pExtPackData) -- { -- if (pExtPackData->fUsable) -- LogRel((" %s (Version: %s r%u%s%s; VRDE Module: %s)\n", -- pExtPackData->Desc.strName.c_str(), -- pExtPackData->Desc.strVersion.c_str(), -- pExtPackData->Desc.uRevision, -- pExtPackData->Desc.strEdition.isEmpty() ? "" : " ", -- pExtPackData->Desc.strEdition.c_str(), -- pExtPackData->Desc.strVrdeModule.c_str() )); -- else -- LogRel((" %s (Version: %s r%u%s%s; VRDE Module: %s unusable because of '%s')\n", -- pExtPackData->Desc.strName.c_str(), -- pExtPackData->Desc.strVersion.c_str(), -- pExtPackData->Desc.uRevision, -- pExtPackData->Desc.strEdition.isEmpty() ? "" : " ", -- pExtPackData->Desc.strEdition.c_str(), -- pExtPackData->Desc.strVrdeModule.c_str(), -- pExtPackData->strWhyUnusable.c_str() )); -- } -- else -- LogRel((" pExtPackData is NULL\n")); -- } -- -- if (!m->llInstalledExtPacks.size()) -- LogRel((" None installed!\n")); --} -- --/* vi: set tabstop=4 shiftwidth=4 expandtab: */ ---- VirtualBox-4.2.0.orig/src/VBox/Main/src-all/ExtPackUtil.cpp 2012-07-18 05:57:58.000000000 -0300 -+++ /dev/null 2012-09-18 22:18:48.866734195 -0300 -@@ -1,1385 +0,0 @@ --/* $Id: ExtPackUtil.cpp 41783 2012-06-16 19:24:15Z vboxsync $ */ --/** @file -- * VirtualBox Main - Extension Pack Utilities and definitions, VBoxC, VBoxSVC, ++. -- */ -- --/* -- * Copyright (C) 2010-2012 Oracle Corporation -- * -- * This file is part of VirtualBox Open Source Edition (OSE), as -- * available from http://www.virtualbox.org. This file is free software; -- * you can redistribute it and/or modify it under the terms of the GNU -- * General Public License (GPL) as published by the Free Software -- * Foundation, in version 2 as it comes in the "COPYING" file of the -- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the -- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. -- */ -- -- --/******************************************************************************* --* Header Files * --*******************************************************************************/ --#include "../include/ExtPackUtil.h" -- --#include <iprt/ctype.h> --#include <iprt/dir.h> --#include <iprt/file.h> --#include <iprt/manifest.h> --#include <iprt/param.h> --#include <iprt/path.h> --#include <iprt/sha.h> --#include <iprt/string.h> --#include <iprt/vfs.h> --#include <iprt/tar.h> --#include <iprt/zip.h> --#include <iprt/cpp/xml.h> -- --#include <VBox/log.h> -- -- --/** -- * Worker for VBoxExtPackLoadDesc that loads the plug-in descriptors. -- * -- * @returns Same as VBoxExtPackLoadDesc. -- * @param pVBoxExtPackElm -- * @param pcPlugIns Where to return the number of plug-ins in the -- * array. -- * @param paPlugIns Where to return the plug-in descriptor array. -- * (RTMemFree it even on failure) -- */ --static RTCString * --vboxExtPackLoadPlugInDescs(const xml::ElementNode *pVBoxExtPackElm, -- uint32_t *pcPlugIns, PVBOXEXTPACKPLUGINDESC *paPlugIns) --{ -- *pcPlugIns = 0; -- *paPlugIns = NULL; -- -- /** @todo plug-ins */ -- NOREF(pVBoxExtPackElm); -- -- return NULL; --} -- --/** -- * Clears the extension pack descriptor. -- * -- * @param a_pExtPackDesc The descriptor to clear. -- */ --static void vboxExtPackClearDesc(PVBOXEXTPACKDESC a_pExtPackDesc) --{ -- a_pExtPackDesc->strName.setNull(); -- a_pExtPackDesc->strDescription.setNull(); -- a_pExtPackDesc->strVersion.setNull(); -- a_pExtPackDesc->strEdition.setNull(); -- a_pExtPackDesc->uRevision = 0; -- a_pExtPackDesc->strMainModule.setNull(); -- a_pExtPackDesc->strVrdeModule.setNull(); -- a_pExtPackDesc->cPlugIns = 0; -- a_pExtPackDesc->paPlugIns = NULL; -- a_pExtPackDesc->fShowLicense = false; --} -- --/** -- * Initializes an extension pack descriptor so that it's safe to call free on -- * it whatever happens later on. -- * -- * @param a_pExtPackDesc The descirptor to initialize. -- */ --void VBoxExtPackInitDesc(PVBOXEXTPACKDESC a_pExtPackDesc) --{ -- vboxExtPackClearDesc(a_pExtPackDesc); --} -- -- --/** -- * Load the extension pack descriptor from an XML document. -- * -- * @returns NULL on success, pointer to an error message on failure (caller -- * deletes it). -- * @param a_pDoc Pointer to the XML document. -- * @param a_pExtPackDesc Where to store the extension pack descriptor. -- */ --static RTCString *vboxExtPackLoadDescFromDoc(xml::Document *a_pDoc, PVBOXEXTPACKDESC a_pExtPackDesc) --{ -- /* -- * Get the main element and check its version. -- */ -- const xml::ElementNode *pVBoxExtPackElm = a_pDoc->getRootElement(); -- if ( !pVBoxExtPackElm -- || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0) -- return new RTCString("No VirtualBoxExtensionPack element"); -- -- RTCString strFormatVersion; -- if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion)) -- return new RTCString("Missing format version"); -- if (!strFormatVersion.equals("1.0")) -- return &(new RTCString("Unsupported format version: "))->append(strFormatVersion); -- -- /* -- * Read and validate mandatory bits. -- */ -- const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name"); -- if (!pNameElm) -- return new RTCString("The 'Name' element is missing"); -- const char *pszName = pNameElm->getValue(); -- if (!VBoxExtPackIsValidName(pszName)) -- return &(new RTCString("Invalid name: "))->append(pszName); -- -- const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description"); -- if (!pDescElm) -- return new RTCString("The 'Description' element is missing"); -- const char *pszDesc = pDescElm->getValue(); -- if (!pszDesc || *pszDesc == '\0') -- return new RTCString("The 'Description' element is empty"); -- if (strpbrk(pszDesc, "\n\r\t\v\b") != NULL) -- return new RTCString("The 'Description' must not contain control characters"); -- -- const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version"); -- if (!pVersionElm) -- return new RTCString("The 'Version' element is missing"); -- const char *pszVersion = pVersionElm->getValue(); -- if (!pszVersion || *pszVersion == '\0') -- return new RTCString("The 'Version' element is empty"); -- if (!VBoxExtPackIsValidVersionString(pszVersion)) -- return &(new RTCString("Invalid version string: "))->append(pszVersion); -- -- uint32_t uRevision; -- if (!pVersionElm->getAttributeValue("revision", uRevision)) -- uRevision = 0; -- -- const char *pszEdition; -- if (!pVersionElm->getAttributeValue("edition", pszEdition)) -- pszEdition = ""; -- if (!VBoxExtPackIsValidEditionString(pszEdition)) -- return &(new RTCString("Invalid edition string: "))->append(pszEdition); -- -- const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule"); -- if (!pMainModuleElm) -- return new RTCString("The 'MainModule' element is missing"); -- const char *pszMainModule = pMainModuleElm->getValue(); -- if (!pszMainModule || *pszMainModule == '\0') -- return new RTCString("The 'MainModule' element is empty"); -- if (!VBoxExtPackIsValidModuleString(pszMainModule)) -- return &(new RTCString("Invalid main module string: "))->append(pszMainModule); -- -- /* -- * The VRDE module, optional. -- * Accept both none and empty as tokens of no VRDE module. -- */ -- const char *pszVrdeModule = NULL; -- const xml::ElementNode *pVrdeModuleElm = pVBoxExtPackElm->findChildElement("VRDEModule"); -- if (pVrdeModuleElm) -- { -- pszVrdeModule = pVrdeModuleElm->getValue(); -- if (!pszVrdeModule || *pszVrdeModule == '\0') -- pszVrdeModule = NULL; -- else if (!VBoxExtPackIsValidModuleString(pszVrdeModule)) -- return &(new RTCString("Invalid VRDE module string: "))->append(pszVrdeModule); -- } -- -- /* -- * Whether to show the license, optional. (presense is enough here) -- */ -- const xml::ElementNode *pShowLicenseElm = pVBoxExtPackElm->findChildElement("ShowLicense"); -- bool fShowLicense = pShowLicenseElm != NULL; -- -- /* -- * Parse plug-in descriptions (last because of the manual memory management). -- */ -- uint32_t cPlugIns = 0; -- PVBOXEXTPACKPLUGINDESC paPlugIns = NULL; -- RTCString *pstrRet = vboxExtPackLoadPlugInDescs(pVBoxExtPackElm, &cPlugIns, &paPlugIns); -- if (pstrRet) -- { -- RTMemFree(paPlugIns); -- return pstrRet; -- } -- -- /* -- * Everything seems fine, fill in the return values and return successfully. -- */ -- a_pExtPackDesc->strName = pszName; -- a_pExtPackDesc->strDescription = pszDesc; -- a_pExtPackDesc->strVersion = pszVersion; -- a_pExtPackDesc->strEdition = pszEdition; -- a_pExtPackDesc->uRevision = uRevision; -- a_pExtPackDesc->strMainModule = pszMainModule; -- a_pExtPackDesc->strVrdeModule = pszVrdeModule; -- a_pExtPackDesc->cPlugIns = cPlugIns; -- a_pExtPackDesc->paPlugIns = paPlugIns; -- a_pExtPackDesc->fShowLicense = fShowLicense; -- -- return NULL; --} -- --/** -- * Reads the extension pack descriptor. -- * -- * @returns NULL on success, pointer to an error message on failure (caller -- * deletes it). -- * @param a_pszDir The directory containing the description file. -- * @param a_pExtPackDesc Where to store the extension pack descriptor. -- * @param a_pObjInfo Where to store the object info for the file (unix -- * attribs). Optional. -- */ --RTCString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo) --{ -- vboxExtPackClearDesc(a_pExtPackDesc); -- -- /* -- * Validate, open and parse the XML file. -- */ -- char szFilePath[RTPATH_MAX]; -- int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME); -- if (RT_FAILURE(vrc)) -- return new RTCString("RTPathJoin failed with %Rrc", vrc); -- -- RTFSOBJINFO ObjInfo; -- vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); -- if (RT_FAILURE(vrc)) -- return &(new RTCString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc); -- if (a_pObjInfo) -- *a_pObjInfo = ObjInfo; -- if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) -- { -- if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) -- return new RTCString("The XML file is symlinked, that is not allowed"); -- return &(new RTCString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode); -- } -- -- xml::Document Doc; -- { -- xml::XmlFileParser Parser; -- try -- { -- Parser.read(szFilePath, Doc); -- } -- catch (xml::XmlError Err) -- { -- return new RTCString(Err.what()); -- } -- } -- -- /* -- * Hand the xml doc over to the common code. -- */ -- return vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc); --} -- --/** -- * Reads the extension pack descriptor. -- * -- * @returns NULL on success, pointer to an error message on failure (caller -- * deletes it). -- * @param a_pszDir The directory containing the description file. -- * @param a_pExtPackDesc Where to store the extension pack descriptor. -- * @param a_pObjInfo Where to store the object info for the file (unix -- * attribs). Optional. -- */ --RTCString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo) --{ -- vboxExtPackClearDesc(a_pExtPackDesc); -- -- /* -- * Query the object info. -- */ -- RTFSOBJINFO ObjInfo; -- int rc = RTVfsFileQueryInfo(hVfsFile, &ObjInfo, RTFSOBJATTRADD_UNIX); -- if (RT_FAILURE(rc)) -- return &(new RTCString)->printf("RTVfsFileQueryInfo failed: %Rrc", rc); -- if (a_pObjInfo) -- *a_pObjInfo = ObjInfo; -- -- /* -- * The simple approach, read the whole thing into memory and pass this to -- * the XML parser. -- */ -- -- /* Check the file size. */ -- if (ObjInfo.cbObject > _1M || ObjInfo.cbObject < 0) -- return &(new RTCString)->printf("The XML file is too large (%'RU64 bytes)", ObjInfo.cbObject); -- size_t const cbFile = (size_t)ObjInfo.cbObject; -- -- /* Rewind to the start of the file. */ -- rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL); -- if (RT_FAILURE(rc)) -- return &(new RTCString)->printf("RTVfsFileSeek(,0,BEGIN) failed: %Rrc", rc); -- -- /* Allocate memory and read the file content into it. */ -- void *pvFile = RTMemTmpAlloc(cbFile); -- if (!pvFile) -- return &(new RTCString)->printf("RTMemTmpAlloc(%zu) failed", cbFile); -- -- RTCString *pstrErr = NULL; -- rc = RTVfsFileRead(hVfsFile, pvFile, cbFile, NULL); -- if (RT_FAILURE(rc)) -- pstrErr = &(new RTCString)->printf("RTVfsFileRead failed: %Rrc", rc); -- -- /* -- * Parse the file. -- */ -- xml::Document Doc; -- if (RT_SUCCESS(rc)) -- { -- xml::XmlMemParser Parser; -- RTCString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME; -- try -- { -- Parser.read(pvFile, cbFile, strFileName, Doc); -- } -- catch (xml::XmlError Err) -- { -- pstrErr = new RTCString(Err.what()); -- rc = VERR_PARSE_ERROR; -- } -- } -- RTMemTmpFree(pvFile); -- -- /* -- * Hand the xml doc over to the common code. -- */ -- if (RT_SUCCESS(rc)) -- pstrErr = vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc); -- -- return pstrErr; --} -- --/** -- * Frees all resources associated with a extension pack descriptor. -- * -- * @param a_pExtPackDesc The extension pack descriptor which members -- * should be freed. -- */ --void VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc) --{ -- if (!a_pExtPackDesc) -- return; -- -- a_pExtPackDesc->strName.setNull(); -- a_pExtPackDesc->strDescription.setNull(); -- a_pExtPackDesc->strVersion.setNull(); -- a_pExtPackDesc->strEdition.setNull(); -- a_pExtPackDesc->uRevision = 0; -- a_pExtPackDesc->strMainModule.setNull(); -- a_pExtPackDesc->strVrdeModule.setNull(); -- a_pExtPackDesc->cPlugIns = 0; -- RTMemFree(a_pExtPackDesc->paPlugIns); -- a_pExtPackDesc->paPlugIns = NULL; -- a_pExtPackDesc->fShowLicense = false; --} -- --/** -- * Extract the extension pack name from the tarball path. -- * -- * @returns String containing the name on success, the caller must delete it. -- * NULL if no valid name was found or if we ran out of memory. -- * @param pszTarball The path to the tarball. -- */ --RTCString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball) --{ -- /* -- * Skip ahead to the filename part and count the number of characters -- * that matches the criteria for a mangled extension pack name. -- */ -- const char *pszSrc = RTPathFilename(pszTarball); -- if (!pszSrc) -- return NULL; -- -- size_t off = 0; -- while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == '_') -- off++; -- -- /* -- * Check min and max name limits. -- */ -- if ( off > VBOX_EXTPACK_NAME_MAX_LEN -- || off < VBOX_EXTPACK_NAME_MIN_LEN) -- return NULL; -- -- /* -- * Return the unmangled name. -- */ -- return VBoxExtPackUnmangleName(pszSrc, off); --} -- --/** -- * Validates the extension pack name. -- * -- * @returns true if valid, false if not. -- * @param pszName The name to validate. -- * @sa VBoxExtPackExtractNameFromTarballPath -- */ --bool VBoxExtPackIsValidName(const char *pszName) --{ -- if (!pszName) -- return false; -- -- /* -- * Check the characters making up the name, only english alphabet -- * characters, decimal digits and spaces are allowed. -- */ -- size_t off = 0; -- while (pszName[off]) -- { -- if (!RT_C_IS_ALNUM(pszName[off]) && pszName[off] != ' ') -- return false; -- off++; -- } -- -- /* -- * Check min and max name limits. -- */ -- if ( off > VBOX_EXTPACK_NAME_MAX_LEN -- || off < VBOX_EXTPACK_NAME_MIN_LEN) -- return false; -- -- return true; --} -- --/** -- * Checks if an alledged manged extension pack name. -- * -- * @returns true if valid, false if not. -- * @param pszMangledName The mangled name to validate. -- * @param cchMax The max number of chars to test. -- * @sa VBoxExtPackMangleName -- */ --bool VBoxExtPackIsValidMangledName(const char *pszMangledName, size_t cchMax /*= RTSTR_MAX*/) --{ -- if (!pszMangledName) -- return false; -- -- /* -- * Check the characters making up the name, only english alphabet -- * characters, decimal digits and underscores (=space) are allowed. -- */ -- size_t off = 0; -- while (off < cchMax && pszMangledName[off]) -- { -- if (!RT_C_IS_ALNUM(pszMangledName[off]) && pszMangledName[off] != '_') -- return false; -- off++; -- } -- -- /* -- * Check min and max name limits. -- */ -- if ( off > VBOX_EXTPACK_NAME_MAX_LEN -- || off < VBOX_EXTPACK_NAME_MIN_LEN) -- return false; -- -- return true; --} -- --/** -- * Mangle an extension pack name so it can be used by a directory or file name. -- * -- * @returns String containing the mangled name on success, the caller must -- * delete it. NULL on failure. -- * @param pszName The unmangled name. -- * @sa VBoxExtPackUnmangleName, VBoxExtPackIsValidMangledName -- */ --RTCString *VBoxExtPackMangleName(const char *pszName) --{ -- AssertReturn(VBoxExtPackIsValidName(pszName), NULL); -- -- char szTmp[VBOX_EXTPACK_NAME_MAX_LEN + 1]; -- size_t off = 0; -- char ch; -- while ((ch = pszName[off]) != '\0') -- { -- if (ch == ' ') -- ch = '_'; -- szTmp[off++] = ch; -- } -- szTmp[off] = '\0'; -- Assert(VBoxExtPackIsValidMangledName(szTmp)); -- -- return new RTCString(szTmp, off); --} -- --/** -- * Unmangle an extension pack name (reverses VBoxExtPackMangleName). -- * -- * @returns String containing the mangled name on success, the caller must -- * delete it. NULL on failure. -- * @param pszMangledName The mangled name. -- * @param cchMax The max name length. RTSTR_MAX is fine. -- * @sa VBoxExtPackMangleName, VBoxExtPackIsValidMangledName -- */ --RTCString *VBoxExtPackUnmangleName(const char *pszMangledName, size_t cchMax) --{ -- AssertReturn(VBoxExtPackIsValidMangledName(pszMangledName, cchMax), NULL); -- -- char szTmp[VBOX_EXTPACK_NAME_MAX_LEN + 1]; -- size_t off = 0; -- char ch; -- while ( off < cchMax -- && (ch = pszMangledName[off]) != '\0') -- { -- if (ch == '_') -- ch = ' '; -- else -- AssertReturn(RT_C_IS_ALNUM(ch) || ch == ' ', NULL); -- szTmp[off++] = ch; -- } -- szTmp[off] = '\0'; -- AssertReturn(VBoxExtPackIsValidName(szTmp), NULL); -- -- return new RTCString(szTmp, off); --} -- --/** -- * Constructs the extension pack directory path. -- * -- * A combination of RTPathJoin and VBoxExtPackMangleName. -- * -- * @returns IPRT status code like RTPathJoin. -- * @param pszExtPackDir Where to return the directory path. -- * @param cbExtPackDir The size of the return buffer. -- * @param pszParentDir The parent directory (".../Extensions"). -- * @param pszName The extension pack name, unmangled. -- */ --int VBoxExtPackCalcDir(char *pszExtPackDir, size_t cbExtPackDir, const char *pszParentDir, const char *pszName) --{ -- AssertReturn(VBoxExtPackIsValidName(pszName), VERR_INTERNAL_ERROR_5); -- -- RTCString *pstrMangledName = VBoxExtPackMangleName(pszName); -- if (!pstrMangledName) -- return VERR_INTERNAL_ERROR_4; -- -- int vrc = RTPathJoin(pszExtPackDir, cbExtPackDir, pszParentDir, pstrMangledName->c_str()); -- delete pstrMangledName; -- -- return vrc; --} -- -- --/** -- * Validates the extension pack version string. -- * -- * @returns true if valid, false if not. -- * @param pszVersion The version string to validate. -- */ --bool VBoxExtPackIsValidVersionString(const char *pszVersion) --{ -- if (!pszVersion || *pszVersion == '\0') -- return false; -- -- /* 1.x.y.z... */ -- for (;;) -- { -- if (!RT_C_IS_DIGIT(*pszVersion)) -- return false; -- do -- pszVersion++; -- while (RT_C_IS_DIGIT(*pszVersion)); -- if (*pszVersion != '.') -- break; -- pszVersion++; -- } -- -- /* upper case string + numbers indicating the build type */ -- if (*pszVersion == '-' || *pszVersion == '_') -- { -- /** @todo Should probably restrict this to known build types (alpha, -- * beta, rc, ++). */ -- do -- pszVersion++; -- while ( RT_C_IS_DIGIT(*pszVersion) -- || RT_C_IS_UPPER(*pszVersion) -- || *pszVersion == '-' -- || *pszVersion == '_'); -- } -- -- return *pszVersion == '\0'; --} -- --/** -- * Validates the extension pack edition string. -- * -- * @returns true if valid, false if not. -- * @param pszEdition The edition string to validate. -- */ --bool VBoxExtPackIsValidEditionString(const char *pszEdition) --{ -- if (*pszEdition) -- { -- if (!RT_C_IS_UPPER(*pszEdition)) -- return false; -- -- do -- pszEdition++; -- while ( RT_C_IS_UPPER(*pszEdition) -- || RT_C_IS_DIGIT(*pszEdition) -- || *pszEdition == '-' -- || *pszEdition == '_'); -- } -- return *pszEdition == '\0'; --} -- --/** -- * Validates an extension pack module string. -- * -- * @returns true if valid, false if not. -- * @param pszModule The module string to validate. -- */ --bool VBoxExtPackIsValidModuleString(const char *pszModule) --{ -- if (!pszModule || *pszModule == '\0') -- return false; -- -- /* Restricted charset, no extensions (dots). */ -- while ( RT_C_IS_ALNUM(*pszModule) -- || *pszModule == '-' -- || *pszModule == '_') -- pszModule++; -- -- return *pszModule == '\0'; --} -- --/** -- * RTStrPrintfv wrapper. -- * -- * @returns @a rc -- * @param rc The status code to return. -- * @param pszError The error buffer. -- * @param cbError The size of the buffer. -- * @param pszFormat The error message format string. -- * @param ... Format arguments. -- */ --static int vboxExtPackReturnError(int rc, char *pszError, size_t cbError, const char *pszFormat, ...) --{ -- va_list va; -- va_start(va, pszFormat); -- RTStrPrintfV(pszError, cbError, pszFormat, va); -- va_end(va); -- return rc; --} -- --/** -- * RTStrPrintfv wrapper. -- * -- * @param pszError The error buffer. -- * @param cbError The size of the buffer. -- * @param pszFormat The error message format string. -- * @param ... Format arguments. -- */ --static void vboxExtPackSetError(char *pszError, size_t cbError, const char *pszFormat, ...) --{ -- va_list va; -- va_start(va, pszFormat); -- RTStrPrintfV(pszError, cbError, pszFormat, va); -- va_end(va); --} -- --/** -- * Verifies the manifest and its signature. -- * -- * @returns VBox status code, failures with message. -- * @param hManifestFile The xml from the extension pack. -- * @param pszExtPackName The expected extension pack name. This can be -- * NULL, in which we don't have any expectations. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- */ --static int vboxExtPackVerifyXml(RTVFSFILE hXmlFile, const char *pszExtPackName, char *pszError, size_t cbError) --{ -- /* -- * Load the XML. -- */ -- VBOXEXTPACKDESC ExtPackDesc; -- RTCString *pstrErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &ExtPackDesc, NULL); -- if (pstrErr) -- { -- RTStrCopy(pszError, cbError, pstrErr->c_str()); -- delete pstrErr; -- return VERR_PARSE_ERROR; -- } -- -- /* -- * Check the name. -- */ -- /** @todo drop this restriction after the old install interface is -- * dropped. */ -- int rc = VINF_SUCCESS; -- if ( pszExtPackName -- && !ExtPackDesc.strName.equalsIgnoreCase(pszExtPackName)) -- rc = vboxExtPackReturnError(VERR_NOT_EQUAL, pszError, cbError, -- "The name of the downloaded file and the name stored inside the extension pack does not match" -- " (xml='%s' file='%s')", ExtPackDesc.strName.c_str(), pszExtPackName); -- return rc; --} -- --/** -- * Verifies the manifest and its signature. -- * -- * @returns VBox status code, failures with message. -- * @param hOurManifest The manifest we compiled. -- * @param hManifestFile The manifest file in the extension pack. -- * @param hSignatureFile The manifest signature file. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- */ --static int vboxExtPackVerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile, -- char *pszError, size_t cbError) --{ -- /* -- * Read the manifest from the extension pack. -- */ -- int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL); -- if (RT_FAILURE(rc)) -- return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsFileSeek failed: %Rrc", rc); -- -- RTMANIFEST hTheirManifest; -- rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest); -- if (RT_FAILURE(rc)) -- return vboxExtPackReturnError(rc, pszError, cbError, "RTManifestCreate failed: %Rrc", rc); -- -- RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile); -- rc = RTManifestReadStandard(hTheirManifest, hVfsIos); -- RTVfsIoStrmRelease(hVfsIos); -- if (RT_SUCCESS(rc)) -- { -- /* -- * Compare the manifests. -- */ -- static const char *s_apszIgnoreEntries[] = -- { -- VBOX_EXTPACK_MANIFEST_NAME, -- VBOX_EXTPACK_SIGNATURE_NAME, -- "./" VBOX_EXTPACK_MANIFEST_NAME, -- "./" VBOX_EXTPACK_SIGNATURE_NAME, -- NULL -- }; -- char szError[RTPATH_MAX]; -- rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL, -- RTMANIFEST_EQUALS_IGN_MISSING_ATTRS /*fFlags*/, -- szError, sizeof(szError)); -- if (RT_SUCCESS(rc)) -- { -- /* -- * Validate the manifest file signature. -- */ -- /** @todo implement signature stuff */ -- NOREF(hSignatureFile); -- -- } -- else if (rc == VERR_NOT_EQUAL && szError[0]) -- vboxExtPackSetError(pszError, cbError, "Manifest mismatch: %s", szError); -- else -- vboxExtPackSetError(pszError, cbError, "RTManifestEqualsEx failed: %Rrc", rc); --#if 0 -- RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM; -- RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut); -- RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL); -- RTManifestWriteStandard(hOurManifest, hVfsIosStdOut); -- RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL); -- RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut); --#endif -- } -- else -- vboxExtPackSetError(pszError, cbError, "Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc); -- -- RTManifestRelease(hTheirManifest); -- return rc; --} -- -- --/** -- * Verifies the file digest (if specified) and returns the SHA-256 of the file. -- * -- * @returns -- * @param hFileManifest Manifest containing a SHA-256 digest of the file -- * that was calculated as the file was processed. -- * @param pszFileDigest SHA-256 digest of the file. -- * @param pStrDigest Where to return the SHA-256 digest. Optional. -- * @param pszError Where to write an error message on failure. -- * @param cbError The size of the @a pszError buffer. -- */ --static int vboxExtPackVerifyFileDigest(RTMANIFEST hFileManifest, const char *pszFileDigest, -- RTCString *pStrDigest, char *pszError, size_t cbError) --{ -- /* -- * Extract the SHA-256 entry for the extpack file. -- */ -- char szCalculatedDigest[RTSHA256_DIGEST_LEN + 1]; -- int rc = RTManifestEntryQueryAttr(hFileManifest, "extpack", NULL /*no name*/, RTMANIFEST_ATTR_SHA256, -- szCalculatedDigest, sizeof(szCalculatedDigest), NULL); -- if (RT_SUCCESS(rc)) -- { -- /* -- * Convert the two strings to binary form before comparing. -- * We convert the calculated hash even if we don't have anything to -- * compare with, just to validate it. -- */ -- uint8_t abCalculatedHash[RTSHA256_HASH_SIZE]; -- rc = RTSha256FromString(szCalculatedDigest, abCalculatedHash); -- if (RT_SUCCESS(rc)) -- { -- if ( pszFileDigest -- && *pszFileDigest != '\0') -- { -- uint8_t abFileHash[RTSHA256_HASH_SIZE]; -- rc = RTSha256FromString(pszFileDigest, abFileHash); -- if (RT_SUCCESS(rc)) -- { -- if (memcmp(abFileHash, abCalculatedHash, sizeof(abFileHash))) -- { -- vboxExtPackSetError(pszError, cbError, "The extension pack file has changed (SHA-256 mismatch)"); -- rc = VERR_NOT_EQUAL; -- } -- } -- else -- vboxExtPackSetError(pszError, cbError, "Bad SHA-256 '%s': %Rrc", szCalculatedDigest, rc); -- } -- -- /* -- * Set the output hash on success. -- */ -- if (pStrDigest && RT_SUCCESS(rc)) -- { -- try -- { -- *pStrDigest = szCalculatedDigest; -- } -- catch (std::bad_alloc) -- { -- rc = VERR_NO_MEMORY; -- } -- } -- } -- else -- vboxExtPackSetError(pszError, cbError, "Bad SHA-256 '%s': %Rrc", szCalculatedDigest, rc); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTManifestEntryGetAttr: %Rrc", rc); -- return rc; --} -- -- -- --/** -- * Validates a standard file. -- * -- * Generally all files are -- * -- * @returns VBox status code, failure message in @a pszError. -- * @param pszAdjName The adjusted member name. -- * @param enmType The VFS object type. -- * @param phVfsObj The pointer to the VFS object handle variable. -- * This is both input and output. -- * @param phVfsFile Where to store the handle to the memorized -- * file. This is NULL for license files. -- * @param pszError Where to write an error message on failure. -- * @param cbError The size of the @a pszError buffer. -- */ --static int VBoxExtPackValidateStandardFile(const char *pszAdjName, RTVFSOBJTYPE enmType, -- PRTVFSOBJ phVfsObj, PRTVFSFILE phVfsFile, char *pszError, size_t cbError) --{ -- int rc; -- -- /* -- * Make sure it's a file and that it isn't too large. -- */ -- if (phVfsFile && *phVfsFile != NIL_RTVFSFILE) -- rc = vboxExtPackReturnError(VERR_DUPLICATE, pszError, cbError, -- "There can only be one '%s'", pszAdjName); -- else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE) -- rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError, -- "Standard member '%s' is not a file", pszAdjName); -- else -- { -- RTFSOBJINFO ObjInfo; -- rc = RTVfsObjQueryInfo(*phVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); -- if (RT_SUCCESS(rc)) -- { -- if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) -- rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError, -- "Standard member '%s' is not a file", pszAdjName); -- else if (ObjInfo.cbObject >= _1M) -- rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError, -- "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)", -- pszAdjName, (uint64_t)ObjInfo.cbObject); -- else -- { -- /* -- * Make an in memory copy of the stream and check that the file -- * is UTF-8 clean. -- */ -- RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(*phVfsObj); -- RTVFSFILE hVfsFile; -- rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, &hVfsFile); -- if (RT_SUCCESS(rc)) -- { -- rc = RTVfsIoStrmValidateUtf8Encoding(hVfsIos, -- RTVFS_VALIDATE_UTF8_BY_RTC_3629 | RTVFS_VALIDATE_UTF8_NO_NULL, -- NULL); -- if (RT_SUCCESS(rc)) -- { -- /* -- * Replace *phVfsObj with the memorized file. -- */ -- rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL); -- if (RT_SUCCESS(rc)) -- { -- RTVfsObjRelease(*phVfsObj); -- *phVfsObj = RTVfsObjFromFile(hVfsFile); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTVfsFileSeek failed on '%s': %Rrc", pszAdjName, rc); -- } -- -- if (phVfsFile && RT_SUCCESS(rc)) -- *phVfsFile = hVfsFile; -- else -- RTVfsFileRelease(hVfsFile); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszAdjName, rc); -- RTVfsIoStrmRelease(hVfsIos); -- } -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszAdjName, rc); -- } -- return rc; --} -- -- --/** -- * Validates a name in an extension pack. -- * -- * We restrict the charset to try make sure the extension pack can be unpacked -- * on all file systems. -- * -- * @returns VBox status code, failures with message. -- * @param pszName The name to validate. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- */ --static int vboxExtPackValidateMemberName(const char *pszName, char *pszError, size_t cbError) --{ -- if (RTPathStartsWithRoot(pszName)) -- return vboxExtPackReturnError(VERR_PATH_IS_NOT_RELATIVE, pszError, cbError, "'%s': starts with root spec", pszName); -- -- const char *pszErr = NULL; -- const char *psz = pszName; -- int ch; -- while ((ch = *psz) != '\0') -- { -- /* Character set restrictions. */ -- if (ch < 0 || ch >= 128) -- { -- pszErr = "Only 7-bit ASCII allowed"; -- break; -- } -- if (ch <= 31 || ch == 127) -- { -- pszErr = "No control characters are not allowed"; -- break; -- } -- if (ch == '\\') -- { -- pszErr = "Only backward slashes are not allowed"; -- break; -- } -- if (strchr("'\":;*?|[]<>(){}", ch)) -- { -- pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed"; -- break; -- } -- -- /* Take the simple way out and ban all ".." sequences. */ -- if ( ch == '.' -- && psz[1] == '.') -- { -- pszErr = "Double dot sequence are not allowed"; -- break; -- } -- -- /* Keep the tree shallow or the hardening checks will fail. */ -- if (psz - pszName > VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH) -- { -- pszErr = "Too long"; -- break; -- } -- -- /* advance */ -- psz++; -- } -- -- if (pszErr) -- return vboxExtPackReturnError(VERR_INVALID_NAME, pszError, cbError, -- "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr); -- return RTEXITCODE_SUCCESS; --} -- -- --/** -- * Validates a file in an extension pack. -- * -- * @returns VBox status code, failures with message. -- * @param pszName The name of the file. -- * @param hVfsObj The VFS object. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- */ --static int vboxExtPackValidateMemberFile(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError) --{ -- int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError); -- if (RT_SUCCESS(rc)) -- { -- RTFSOBJINFO ObjInfo; -- rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); -- if (RT_SUCCESS(rc)) -- { -- if (ObjInfo.cbObject >= 9*_1G64) -- rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError, -- "'%s': too large (%'RU64 bytes)", -- pszName, (uint64_t)ObjInfo.cbObject); -- if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) -- rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError, -- "The alleged file '%s' has a mode mask stating otherwise (%RTfmode)", -- pszName, ObjInfo.Attr.fMode); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); -- } -- return rc; --} -- -- --/** -- * Validates a directory in an extension pack. -- * -- * @returns VBox status code, failures with message. -- * @param pszName The name of the directory. -- * @param hVfsObj The VFS object. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- */ --static int vboxExtPackValidateMemberDir(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError) --{ -- int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError); -- if (RT_SUCCESS(rc)) -- { -- RTFSOBJINFO ObjInfo; -- rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); -- if (RT_SUCCESS(rc)) -- { -- if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode)) -- rc = vboxExtPackReturnError(VERR_NOT_A_DIRECTORY, pszError, cbError, -- "The alleged directory '%s' has a mode mask saying differently (%RTfmode)", -- pszName, ObjInfo.Attr.fMode); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); -- } -- return rc; --} -- --/** -- * Validates a member of an extension pack. -- * -- * @returns VBox status code, failures with message. -- * @param pszName The name of the directory. -- * @param enmType The object type. -- * @param hVfsObj The VFS object. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- */ --int VBoxExtPackValidateMember(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj, char *pszError, size_t cbError) --{ -- Assert(cbError > 0); -- *pszError = '\0'; -- -- int rc; -- if ( enmType == RTVFSOBJTYPE_FILE -- || enmType == RTVFSOBJTYPE_IO_STREAM) -- rc = vboxExtPackValidateMemberFile(pszName, hVfsObj, pszError, cbError); -- else if ( enmType == RTVFSOBJTYPE_DIR -- || enmType == RTVFSOBJTYPE_BASE) -- rc = vboxExtPackValidateMemberDir(pszName, hVfsObj, pszError, cbError); -- else -- rc = vboxExtPackReturnError(VERR_UNEXPECTED_FS_OBJ_TYPE, pszError, cbError, -- "'%s' is not a file or directory (enmType=%d)", pszName, enmType); -- return rc; --} -- -- --/** -- * Rewinds the tarball file handle and creates a gunzip | tar chain that -- * results in a filesystem stream. -- * -- * @returns VBox status code, failures with message. -- * @param hTarballFile The handle to the tarball file. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- * @param phTarFss Where to return the filesystem stream handle. -- * @param phFileManifest Where to return a manifest where the tarball is -- * gettting hashed. The entry will be called -- * "extpack" and be ready when the file system -- * stream is at an end. Optional. -- */ --int VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss, PRTMANIFEST phFileManifest) --{ -- Assert(cbError > 0); -- *pszError = '\0'; -- *phTarFss = NIL_RTVFSFSSTREAM; -- -- /* -- * Rewind the file and set up a VFS chain for it. -- */ -- int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL); -- if (RT_FAILURE(rc)) -- return vboxExtPackReturnError(rc, pszError, cbError, "Failed seeking to the start of the tarball: %Rrc", rc); -- -- RTVFSIOSTREAM hTarballIos; -- rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/, -- &hTarballIos); -- if (RT_FAILURE(rc)) -- return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsIoStrmFromRTFile failed: %Rrc", rc); -- -- RTMANIFEST hFileManifest = NIL_RTMANIFEST; -- rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest); -- if (RT_SUCCESS(rc)) -- { -- RTVFSIOSTREAM hPtIos; -- rc = RTManifestEntryAddPassthruIoStream(hFileManifest, hTarballIos, "extpack", RTMANIFEST_ATTR_SHA256, true /*read*/, &hPtIos); -- if (RT_SUCCESS(rc)) -- { -- RTVFSIOSTREAM hGunzipIos; -- rc = RTZipGzipDecompressIoStream(hPtIos, 0 /*fFlags*/, &hGunzipIos); -- if (RT_SUCCESS(rc)) -- { -- RTVFSFSSTREAM hTarFss; -- rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss); -- if (RT_SUCCESS(rc)) -- { -- RTVfsIoStrmRelease(hPtIos); -- RTVfsIoStrmRelease(hGunzipIos); -- RTVfsIoStrmRelease(hTarballIos); -- *phTarFss = hTarFss; -- if (phFileManifest) -- *phFileManifest = hFileManifest; -- else -- RTManifestRelease(hFileManifest); -- return VINF_SUCCESS; -- } -- -- vboxExtPackSetError(pszError, cbError, "RTZipTarFsStreamFromIoStream failed: %Rrc", rc); -- RTVfsIoStrmRelease(hGunzipIos); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTZipGzipDecompressIoStream failed: %Rrc", rc); -- RTVfsIoStrmRelease(hPtIos); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddPassthruIoStream failed: %Rrc", rc); -- RTManifestRelease(hFileManifest); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc); -- -- RTVfsIoStrmRelease(hTarballIos); -- return rc; --} -- -- --/** -- * Validates the extension pack tarball prior to unpacking. -- * -- * Operations performed: -- * - Mandatory files. -- * - Manifest check. -- * - Manifest seal check. -- * - XML check, match name. -- * -- * @returns VBox status code, failures with message. -- * @param hTarballFile The handle to open the @a pszTarball file. -- * @param pszExtPackName The name of the extension pack name. NULL if -- * the name is not fixed. -- * @param pszTarball The name of the tarball in case we have to -- * complain about something. -- * @param pszTarballDigest The SHA-256 digest of the tarball. Empty string -- * if no digest available. -- * @param pszError Where to store an error message on failure. -- * @param cbError The size of the buffer @a pszError points to. -- * @param phValidManifest Where to optionally return the handle to fully -- * validated the manifest for the extension pack. -- * This includes all files. -- * @param phXmlFile Where to optionally return the memorized XML -- * file. -- * @param pStrDigest Where to return the digest of the file. -- * Optional. -- */ --int VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName, -- const char *pszTarball, const char *pszTarballDigest, -- char *pszError, size_t cbError, -- PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile, RTCString *pStrDigest) --{ -- /* -- * Clear return values. -- */ -- if (phValidManifest) -- *phValidManifest = NIL_RTMANIFEST; -- if (phXmlFile) -- *phXmlFile = NIL_RTVFSFILE; -- Assert(cbError > 1); -- *pszError = '\0'; -- NOREF(pszTarball); -- -- /* -- * Open the tar.gz filesystem stream and set up an manifest in-memory file. -- */ -- RTMANIFEST hFileManifest; -- RTVFSFSSTREAM hTarFss; -- int rc = VBoxExtPackOpenTarFss(hTarballFile, pszError, cbError, &hTarFss, &hFileManifest); -- if (RT_FAILURE(rc)) -- return rc; -- -- RTMANIFEST hOurManifest; -- rc = RTManifestCreate(0 /*fFlags*/, &hOurManifest); -- if (RT_SUCCESS(rc)) -- { -- /* -- * Process the tarball (would be nice to move this to a function). -- */ -- RTVFSFILE hXmlFile = NIL_RTVFSFILE; -- RTVFSFILE hManifestFile = NIL_RTVFSFILE; -- RTVFSFILE hSignatureFile = NIL_RTVFSFILE; -- for (;;) -- { -- /* -- * Get the next stream object. -- */ -- char *pszName; -- RTVFSOBJ hVfsObj; -- RTVFSOBJTYPE enmType; -- rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj); -- if (RT_FAILURE(rc)) -- { -- if (rc != VERR_EOF) -- vboxExtPackSetError(pszError, cbError, "RTVfsFsStrmNext failed: %Rrc", rc); -- else -- rc = VINF_SUCCESS; -- break; -- } -- const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName; -- -- /* -- * Check the type & name validity, performing special tests on -- * standard extension pack member files. -- * -- * N.B. We will always reach the end of the loop before breaking on -- * failure - cleanup reasons. -- */ -- rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, pszError, cbError); -- if (RT_SUCCESS(rc)) -- { -- PRTVFSFILE phVfsFile = NULL; -- if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME)) -- phVfsFile = &hXmlFile; -- else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME)) -- phVfsFile = &hManifestFile; -- else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME)) -- phVfsFile = &hSignatureFile; -- else if (!strncmp(pszAdjName, VBOX_EXTPACK_LICENSE_NAME_PREFIX, sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX) - 1)) -- rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, NULL, pszError, cbError); -- if (phVfsFile) -- rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, phVfsFile, pszError, cbError); -- } -- -- /* -- * Add any I/O stream to the manifest -- */ -- if ( RT_SUCCESS(rc) -- && ( enmType == RTVFSOBJTYPE_FILE -- || enmType == RTVFSOBJTYPE_IO_STREAM)) -- { -- RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); -- rc = RTManifestEntryAddIoStream(hOurManifest, hVfsIos, pszAdjName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256); -- if (RT_FAILURE(rc)) -- vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszAdjName, rc); -- RTVfsIoStrmRelease(hVfsIos); -- } -- -- /* -- * Clean up and break out on failure. -- */ -- RTVfsObjRelease(hVfsObj); -- RTStrFree(pszName); -- if (RT_FAILURE(rc)) -- break; -- } -- -- /* -- * Check the integrity of the tarball file. -- */ -- if (RT_SUCCESS(rc)) -- { -- RTVfsFsStrmRelease(hTarFss); -- hTarFss = NIL_RTVFSFSSTREAM; -- rc = vboxExtPackVerifyFileDigest(hFileManifest, pszTarballDigest, pStrDigest, pszError, cbError); -- } -- -- /* -- * If we've successfully processed the tarball, verify that the -- * mandatory files are present. -- */ -- if (RT_SUCCESS(rc)) -- { -- if (hXmlFile == NIL_RTVFSFILE) -- rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME); -- if (hManifestFile == NIL_RTVFSFILE) -- rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME); -- if (hSignatureFile == NIL_RTVFSFILE) -- rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME); -- } -- -- /* -- * Check the manifest and it's signature. -- */ -- if (RT_SUCCESS(rc)) -- rc = vboxExtPackVerifyManifestAndSignature(hOurManifest, hManifestFile, hSignatureFile, pszError, cbError); -- -- /* -- * Check the XML. -- */ -- if (RT_SUCCESS(rc)) -- rc = vboxExtPackVerifyXml(hXmlFile, pszExtPackName, pszError, cbError); -- -- /* -- * Returns objects. -- */ -- if (RT_SUCCESS(rc)) -- { -- if (phValidManifest) -- { -- RTManifestRetain(hOurManifest); -- *phValidManifest = hOurManifest; -- } -- if (phXmlFile) -- { -- RTVfsFileRetain(hXmlFile); -- *phXmlFile = hXmlFile; -- } -- } -- -- /* -- * Release our object references. -- */ -- RTManifestRelease(hOurManifest); -- RTVfsFileRelease(hXmlFile); -- RTVfsFileRelease(hManifestFile); -- RTVfsFileRelease(hSignatureFile); -- } -- else -- vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc); -- RTVfsFsStrmRelease(hTarFss); -- RTManifestRelease(hFileManifest); -- -- return rc; --} -- --- VirtualBox-4.1.18.orig/include/Makefile.kmk 2012-06-20 10:07:49.000000000 -0300 +++ VirtualBox-4.1.18/include/Makefile.kmk 2012-07-24 21:11:57.007068865 -0300 @@ -51,7 +51,6 @@ diff --git a/libre/virtualbox-libre/vboxbuild b/libre/virtualbox-libre/vboxbuild deleted file mode 100755 index 27519950f..000000000 --- a/libre/virtualbox-libre/vboxbuild +++ /dev/null @@ -1,95 +0,0 @@ -#!/bin/bash - -. /etc/vbox/vbox.cfg - -MODLIST=() -LOG="/var/log/vbox-install.log" ->| "$LOG" - -stat_busy() { - printf '==> %s ... ' "$1" -} - -stat_done() { - echo 'done' -} - -stat_fail() { - echo 'failed' -} - -if [[ $INSTALL_DIR ]]; then - VBOXMANAGE=$INSTALL_DIR/VBoxManage - BUILDVBOXDRV=$INSTALL_DIR/src/vboxdrv/build_in_tmp - BUILDVBOXNETFLT=$INSTALL_DIR/src/vboxnetflt/build_in_tmp - BUILDVBOXNETADP=$INSTALL_DIR/src/vboxnetadp/build_in_tmp - BUILDVBOXPCI=$INSTALL_DIR/src/vboxpci/build_in_tmp -else - echo "error: missing vbox.cfg" - exit 1 -fi - -if [[ -f /proc/modules ]]; then - IFS=$'\n' read -r -d '' -a MODLIST < \ - <(grep -oE '^vbox(pci|netflt|netadp|drv)' /proc/modules) -fi - -if (( ${#MODLIST[*]} )); then - stat_busy "Unloading VirtualBox kernel libre modules" - modprobe -ar "${MODLIST[@]}" && stat_done || stat_fail -fi - -for kdir in /usr/lib/modules/[2-3]*; do - if [[ ! -d $kdir/kernel ]]; then - # found a stale kernel - mods=("$kdir/extramodules"{drv,netadp,netflt,pci}.ko*) - if (( ${#mods[@]} )); then - stat_busy "Removing all old VirtualBox kernel libre modules" - if rm -f "${mods[@]}" && - rmdir -p --ignore-fail-on-non-empty "$kdir/extramodules" 2>/dev/null; then - stat_done - else - stat_fail - fi - fi - fi -done - -# default to the currently running kernel -if (( ! $# )); then - set -- $(uname -r) -fi - -for kernver; do - export KERN_DIR=/usr/lib/modules/$kernver/build - export MODULE_DIR=/usr/lib/modules/$kernver/extramodules - if [[ ! -d $KERN_DIR ]]; then - printf "error: \`%s' does not appear to be a valid kernel libre build directory.\n" \ - "$KERN_DIR" - continue - fi - - stat_busy "Recompiling VirtualBox kernel libre modules ($kernver)" - if ! $BUILDVBOXDRV \ - --save-module-symvers /tmp/vboxdrv-Module.symvers \ - --no-print-directory install >> $LOG 2>&1; then - echo "Look at $LOG to find out what went wrong" - stat_fail - fi - for build in BUILDVBOX{NETFLT,NETADP,PCI}; do - if ! ${!build} \ - --use-module-symvers /tmp/vboxdrv-Module.symvers \ - --no-print-directory install >> $LOG 2>&1; then - echo "Look at $LOG to find out what went wrong" - stat_fail - fi - done - gzip -f9 "$MODULE_DIR"/*.ko - depmod "$kernver" - stat_done -done - -if (( ${#MODLIST[*]} )); then - stat_busy "Reloading VirtualBox kernel libre modules" - modprobe -a "${MODLIST[@]}" && stat_done || stat_fail -fi diff --git a/libre/xulrunner-libre/Bug-756390-Make-the-Reset-Firefox-feature-more-gener.patch b/libre/xulrunner-libre/Bug-756390-Make-the-Reset-Firefox-feature-more-gener.patch index 240c3d4e8..a5fe02165 100755 --- a/libre/xulrunner-libre/Bug-756390-Make-the-Reset-Firefox-feature-more-gener.patch +++ b/libre/xulrunner-libre/Bug-756390-Make-the-Reset-Firefox-feature-more-gener.patch @@ -139,7 +139,7 @@ index 21cf405..f3c1a6b 100644 <!ENTITY noMigrationSources.label "No programs that contain bookmarks, history or password data could be found.">
diff --git a/browser/locales/en-US/chrome/browser/migration/migration.properties b/browser/locales/en-US/chrome/browser/migration/migration.properties
-index ab82d85..915f6b8 100644
+index 260bc29..52b32cc 100644
--- a/browser/locales/en-US/chrome/browser/migration/migration.properties
+++ b/browser/locales/en-US/chrome/browser/migration/migration.properties
@@ -8,7 +8,6 @@ profileName_format=%S %S
@@ -150,7 +150,7 @@ index ab82d85..915f6b8 100644 importedBookmarksFolder=From %S
-@@ -22,22 +21,22 @@ importedSafariReadingList=Reading List (From Safari)
+@@ -24,22 +23,22 @@ importedSafariReadingList=Reading List (From Safari)
2_ie=Cookies
2_safari=Cookies
2_chrome=Cookies
@@ -177,25 +177,25 @@ index ab82d85..915f6b8 100644 32_ie=Favorites
32_safari=Bookmarks
-@@ -46,4 +45,4 @@ importedSafariReadingList=Reading List (From Safari)
+@@ -48,4 +47,4 @@ importedSafariReadingList=Reading List (From Safari)
64_ie=Other Data
64_safari=Other Data
64_chrome=Other Data
-64_firefox=Bookmarks Backups
+64_self=Bookmarks Backups
diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
-index 697b217..b6e1709 100644
+index 339ffda..6999b26 100644
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -38,7 +38,7 @@ toolkit.jar:
+ content/global/mozilla.xhtml (mozilla.xhtml)
- *+ content/global/nsDragAndDrop.js (nsDragAndDrop.js)
+ content/global/nsDragAndDrop.js (nsDragAndDrop.js)
content/global/resetProfile.css (resetProfile.css)
-* content/global/resetProfile.js (resetProfile.js)
+ content/global/resetProfile.js (resetProfile.js)
- * content/global/resetProfile.xul (resetProfile.xul)
- * content/global/resetProfileProgress.xul (resetProfileProgress.xul)
- * content/global/treeUtils.js (treeUtils.js)
+ content/global/resetProfile.xul (resetProfile.xul)
+ content/global/resetProfileProgress.xul (resetProfileProgress.xul)
+ content/global/treeUtils.js (treeUtils.js)
diff --git a/toolkit/content/resetProfile.js b/toolkit/content/resetProfile.js
index dcb4065..09c1146 100644
--- a/toolkit/content/resetProfile.js
@@ -267,10 +267,10 @@ index f35c227..7062886 100644 %{C++
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
-index e5d3042..6de3390 100644
+index 60348b5..c240c4f 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
-@@ -3650,7 +3650,7 @@ XREMain::XRE_mainRun()
+@@ -3651,7 +3651,7 @@ XREMain::XRE_mainRun()
if (gDoProfileReset) {
// Automatically migrate from the current application if we just
// reset the profile.
diff --git a/libre/xulrunner-libre/PKGBUILD b/libre/xulrunner-libre/PKGBUILD index 4c93e1c48..0d5f817e6 100755 --- a/libre/xulrunner-libre/PKGBUILD +++ b/libre/xulrunner-libre/PKGBUILD @@ -6,7 +6,7 @@ # We're getting this from Debian Experimental _debname=iceweasel -_debver=15.0.1 +_debver=16.0.1 _debrel=1 _debrepo=http://ftp.debian.org/debian/pool/main/ debfile() { echo $@|sed -r 's@(.).*@\1/&/&@'; } @@ -30,11 +30,11 @@ options=('!emptydirs') conflicts=('xulrunner') provides=("xulrunner=${_debver}") replaces=('xulrunner-oss' 'xulrunner') -md5sums=('0936242388cd4c75930c1d2487e15216' - 'ce37c76476b8edf40780d00cf79d0d62' +md5sums=('33e50f7ddfa7274e5a3bd393c37fb3b3' + 'ddfcf225ea0e3d7b4b377f4a63d5e8c4' 'f2f4f4a573f549e8b494e33b3ad226bc' '27271ce647a83906ef7a24605e840d61' - 'c52fac65c1e06290a5108b75c31ace79') + '0a31239f1008038df5057982fe745dec') build() { export QUILT_PATCHES=debian/patches |