[darwinbuild-changes] [732] trunk
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 3 13:37:30 PST 2010
Revision: 732
http://trac.macosforge.org/projects/darwinbuild/changeset/732
Author: wsiegrist at apple.com
Date: 2010-03-03 13:37:30 -0800 (Wed, 03 Mar 2010)
Log Message:
-----------
Merge PR-7489777, PR-7598640, and PR-7638434
Modified Paths:
--------------
trunk/CHANGES
trunk/darwinbuild.xcodeproj/project.pbxproj
trunk/darwintrace/darwintrace.c
trunk/darwinup/Archive.cpp
trunk/darwinup/Archive.h
trunk/darwinup/Depot.cpp
trunk/darwinup/Depot.h
trunk/darwinup/Digest.cpp
trunk/darwinup/Digest.h
trunk/darwinup/File.cpp
trunk/darwinup/File.h
trunk/darwinup/SerialSet.cpp
trunk/darwinup/SerialSet.h
trunk/darwinup/Utils.cpp
trunk/darwinup/Utils.h
trunk/darwinup/main.cpp
trunk/darwinup/redo_prebinding.h
trunk/testing/darwinup/run-tests.sh
Added Paths:
-----------
trunk/darwinup/Column.cpp
trunk/darwinup/Column.h
trunk/darwinup/DB.cpp
trunk/darwinup/DB.h
trunk/darwinup/Database.cpp
trunk/darwinup/Database.h
trunk/darwinup/Table.cpp
trunk/darwinup/Table.h
trunk/testing/darwinup/300dirs.tbz2
trunk/testing/darwinup/300files.tbz2
Property Changed:
----------------
trunk/
trunk/darwinbuild/darwinbuild.in
trunk/darwinbuild/darwinmaster.in
trunk/darwinbuild/installXcode.in
trunk/darwinbuild/packageRoots.in
trunk/darwinbuild/thinPackages.in
Property changes on: trunk
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/PR-4841388:399-419
/branches/PR-6358021:442-443
/branches/PR-6392966:423-427
/branches/PR-6398060:433-434
/branches/PR-6493844:460-461
/branches/PR-6497694:466-468,471
/branches/PR-6634286:632-650
/branches/PR-6688645:479-490
/branches/PR-6722857:495-499
/branches/PR-6729491:655-664
/branches/PR-7250612:635-650
/branches/PR-7341154:682-694
/branches/PR-7431723:660-664
/branches/PR-7461534:650-664
/branches/PR-7482850:670-671
/branches/PR-7529688:692-694
/trunk:432-434
+ /branches/PR-4841388:399-419
/branches/PR-6358021:442-443
/branches/PR-6392966:423-427
/branches/PR-6398060:433-434
/branches/PR-6493844:460-461
/branches/PR-6497694:466-468,471
/branches/PR-6634286:632-650
/branches/PR-6688645:479-490
/branches/PR-6722857:495-499
/branches/PR-6729491:655-664
/branches/PR-7250612:635-650
/branches/PR-7341154:682-694
/branches/PR-7431723:660-664
/branches/PR-7461534:650-664
/branches/PR-7482850:670-671
/branches/PR-7489777:676-731
/branches/PR-7529688:692-694
/branches/PR-7598640:703-731
/trunk:432-434
Modified: trunk/CHANGES
===================================================================
--- trunk/CHANGES 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/CHANGES 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,6 +1,17 @@
Darwin Build Scripts Change History
-----------------------------------
+Release 15 [03-Mar-2010]
+ - darwinup: added new database abstraction layer to simplify Depot code,
+ reduce copy-paste, and reduce unnecessary statement preparation
+ - darwinup: allow list subcommand to run as not-root
+ - darwinup: support multiple command line arguments (ex: globbing)
+
+Release 14 [05-Feb-2010]
+ - darwinup: add upgrade command to automatically replace last root
+ installed with the same name.
+ - darwinup: added ability to install roots which have broken symlinks
+
Release 13.1 [22-Dec-2009]
- darwinup: fix bug where rollback archives for user modifications
did not contain parent directories and thus certain
Property changes on: trunk/darwinbuild/darwinbuild.in
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/PR-4841388/darwinbuild/darwinbuild:399-419
/branches/PR-6358021/darwinbuild/darwinbuild:442-443
/branches/PR-6392966/darwinbuild/darwinbuild:423-427
/branches/PR-6398060/darwinbuild/darwinbuild:433-434
/branches/PR-6493844/darwinbuild/darwinbuild.in:460-461
/branches/PR-6497694/darwinbuild/darwinbuild.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinbuild.in:632-650
/branches/PR-6688645/darwinbuild/darwinbuild.in:479-490
/branches/PR-6722857/darwinbuild/darwinbuild.in:495-499
/branches/PR-6729491/darwinbuild/darwinbuild.in:655-664
/branches/PR-7250612/darwinbuild/darwinbuild.in:635-650
/branches/PR-7341154/darwinbuild/darwinbuild.in:682-694
/branches/PR-7431723/darwinbuild/darwinbuild.in:660-664
/branches/PR-7461534/darwinbuild/darwinbuild.in:650-664
/branches/PR-7529688/darwinbuild/darwinbuild.in:692-694
/trunk/darwinbuild/darwinbuild:432-434
+ /branches/PR-4841388/darwinbuild/darwinbuild:399-419
/branches/PR-6358021/darwinbuild/darwinbuild:442-443
/branches/PR-6392966/darwinbuild/darwinbuild:423-427
/branches/PR-6398060/darwinbuild/darwinbuild:433-434
/branches/PR-6493844/darwinbuild/darwinbuild.in:460-461
/branches/PR-6497694/darwinbuild/darwinbuild.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinbuild.in:632-650
/branches/PR-6688645/darwinbuild/darwinbuild.in:479-490
/branches/PR-6722857/darwinbuild/darwinbuild.in:495-499
/branches/PR-6729491/darwinbuild/darwinbuild.in:655-664
/branches/PR-7250612/darwinbuild/darwinbuild.in:635-650
/branches/PR-7341154/darwinbuild/darwinbuild.in:682-694
/branches/PR-7431723/darwinbuild/darwinbuild.in:660-664
/branches/PR-7461534/darwinbuild/darwinbuild.in:650-664
/branches/PR-7489777/darwinbuild/darwinbuild.in:676-731
/branches/PR-7529688/darwinbuild/darwinbuild.in:692-694
/branches/PR-7598640/darwinbuild/darwinbuild.in:703-731
/trunk/darwinbuild/darwinbuild:432-434
Property changes on: trunk/darwinbuild/darwinmaster.in
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/PR-4841388/darwinbuild/darwinmaster.sh:399-419
/branches/PR-6358021/darwinbuild/darwinmaster.sh:442-443
/branches/PR-6392966/darwinbuild/darwinmaster.sh:423-427
/branches/PR-6398060/darwinbuild/darwinmaster.sh:433-434
/branches/PR-6493844/darwinbuild/darwinmaster.sh.in:460-461
/branches/PR-6497694/darwinbuild/darwinmaster.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinmaster.in:632-650
/branches/PR-6688645/darwinbuild/darwinmaster.sh.in:479-490
/branches/PR-6722857/darwinbuild/darwinmaster.sh.in:495-499
/branches/PR-6729491/darwinbuild/darwinmaster.in:655-664
/branches/PR-7250612/darwinbuild/darwinmaster.in:635-650
/branches/PR-7341154/darwinbuild/darwinmaster.in:682-694
/branches/PR-7431723/darwinbuild/darwinmaster.in:660-664
/branches/PR-7461534/darwinbuild/darwinmaster.in:650-664
/branches/PR-7529688/darwinbuild/darwinmaster.in:692-694
/trunk/darwinbuild/darwinmaster.sh:432-434
+ /branches/PR-4841388/darwinbuild/darwinmaster.sh:399-419
/branches/PR-6358021/darwinbuild/darwinmaster.sh:442-443
/branches/PR-6392966/darwinbuild/darwinmaster.sh:423-427
/branches/PR-6398060/darwinbuild/darwinmaster.sh:433-434
/branches/PR-6493844/darwinbuild/darwinmaster.sh.in:460-461
/branches/PR-6497694/darwinbuild/darwinmaster.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/darwinmaster.in:632-650
/branches/PR-6688645/darwinbuild/darwinmaster.sh.in:479-490
/branches/PR-6722857/darwinbuild/darwinmaster.sh.in:495-499
/branches/PR-6729491/darwinbuild/darwinmaster.in:655-664
/branches/PR-7250612/darwinbuild/darwinmaster.in:635-650
/branches/PR-7341154/darwinbuild/darwinmaster.in:682-694
/branches/PR-7431723/darwinbuild/darwinmaster.in:660-664
/branches/PR-7461534/darwinbuild/darwinmaster.in:650-664
/branches/PR-7489777/darwinbuild/darwinmaster.in:676-731
/branches/PR-7529688/darwinbuild/darwinmaster.in:692-694
/branches/PR-7598640/darwinbuild/darwinmaster.in:703-731
/trunk/darwinbuild/darwinmaster.sh:432-434
Property changes on: trunk/darwinbuild/installXcode.in
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/PR-4841388/darwinbuild/installXcode:399-419
/branches/PR-6358021/darwinbuild/installXcode:442-443
/branches/PR-6392966/darwinbuild/installXcode:423-427
/branches/PR-6398060/darwinbuild/installXcode:433-434
/branches/PR-6493844/darwinbuild/installXcode.in:460-461
/branches/PR-6497694/darwinbuild/installXcode.in:466-468,471
/branches/PR-6634286/darwinbuild/installXcode.in:632-650
/branches/PR-6688645/darwinbuild/installXcode.in:479-490
/branches/PR-6722857/darwinbuild/installXcode.in:495-499
/branches/PR-6729491/darwinbuild/installXcode.in:655-664
/branches/PR-7250612/darwinbuild/installXcode.in:635-650
/branches/PR-7341154/darwinbuild/installXcode.in:682-694
/branches/PR-7431723/darwinbuild/installXcode.in:660-664
/branches/PR-7461534/darwinbuild/installXcode.in:650-664
/branches/PR-7529688/darwinbuild/installXcode.in:692-694
/trunk/darwinbuild/installXcode:432-434
+ /branches/PR-4841388/darwinbuild/installXcode:399-419
/branches/PR-6358021/darwinbuild/installXcode:442-443
/branches/PR-6392966/darwinbuild/installXcode:423-427
/branches/PR-6398060/darwinbuild/installXcode:433-434
/branches/PR-6493844/darwinbuild/installXcode.in:460-461
/branches/PR-6497694/darwinbuild/installXcode.in:466-468,471
/branches/PR-6634286/darwinbuild/installXcode.in:632-650
/branches/PR-6688645/darwinbuild/installXcode.in:479-490
/branches/PR-6722857/darwinbuild/installXcode.in:495-499
/branches/PR-6729491/darwinbuild/installXcode.in:655-664
/branches/PR-7250612/darwinbuild/installXcode.in:635-650
/branches/PR-7341154/darwinbuild/installXcode.in:682-694
/branches/PR-7431723/darwinbuild/installXcode.in:660-664
/branches/PR-7461534/darwinbuild/installXcode.in:650-664
/branches/PR-7489777/darwinbuild/installXcode.in:676-731
/branches/PR-7529688/darwinbuild/installXcode.in:692-694
/branches/PR-7598640/darwinbuild/installXcode.in:703-731
/trunk/darwinbuild/installXcode:432-434
Property changes on: trunk/darwinbuild/packageRoots.in
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/PR-4841388/darwinbuild/packageRoots.sh:399-419
/branches/PR-6358021/darwinbuild/packageRoots.sh:442-443
/branches/PR-6392966/darwinbuild/packageRoots.sh:423-427
/branches/PR-6398060/darwinbuild/packageRoots.sh:433-434
/branches/PR-6493844/darwinbuild/packageRoots.sh.in:460-461
/branches/PR-6497694/darwinbuild/packageRoots.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/packageRoots.in:632-650
/branches/PR-6688645/darwinbuild/packageRoots.sh.in:479-490
/branches/PR-6722857/darwinbuild/packageRoots.sh.in:495-499
/branches/PR-6729491/darwinbuild/packageRoots.in:655-664
/branches/PR-7250612/darwinbuild/packageRoots.in:635-650
/branches/PR-7341154/darwinbuild/packageRoots.in:682-694
/branches/PR-7431723/darwinbuild/packageRoots.in:660-664
/branches/PR-7461534/darwinbuild/packageRoots.in:650-664
/branches/PR-7529688/darwinbuild/packageRoots.in:692-694
/trunk/darwinbuild/packageRoots.sh:432-434
+ /branches/PR-4841388/darwinbuild/packageRoots.sh:399-419
/branches/PR-6358021/darwinbuild/packageRoots.sh:442-443
/branches/PR-6392966/darwinbuild/packageRoots.sh:423-427
/branches/PR-6398060/darwinbuild/packageRoots.sh:433-434
/branches/PR-6493844/darwinbuild/packageRoots.sh.in:460-461
/branches/PR-6497694/darwinbuild/packageRoots.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/packageRoots.in:632-650
/branches/PR-6688645/darwinbuild/packageRoots.sh.in:479-490
/branches/PR-6722857/darwinbuild/packageRoots.sh.in:495-499
/branches/PR-6729491/darwinbuild/packageRoots.in:655-664
/branches/PR-7250612/darwinbuild/packageRoots.in:635-650
/branches/PR-7341154/darwinbuild/packageRoots.in:682-694
/branches/PR-7431723/darwinbuild/packageRoots.in:660-664
/branches/PR-7461534/darwinbuild/packageRoots.in:650-664
/branches/PR-7489777/darwinbuild/packageRoots.in:676-731
/branches/PR-7529688/darwinbuild/packageRoots.in:692-694
/branches/PR-7598640/darwinbuild/packageRoots.in:703-731
/trunk/darwinbuild/packageRoots.sh:432-434
Property changes on: trunk/darwinbuild/thinPackages.in
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/PR-4841388/darwinbuild/thinPackages.sh:399-419
/branches/PR-6358021/darwinbuild/thinPackages.sh:442-443
/branches/PR-6392966/darwinbuild/thinPackages.sh:423-427
/branches/PR-6398060/darwinbuild/thinPackages.sh:433-434
/branches/PR-6493844/darwinbuild/thinPackages.sh.in:460-461
/branches/PR-6497694/darwinbuild/thinPackages.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/thinPackages.in:632-650
/branches/PR-6688645/darwinbuild/thinPackages.sh.in:479-490
/branches/PR-6722857/darwinbuild/thinPackages.sh.in:495-499
/branches/PR-6729491/darwinbuild/thinPackages.in:655-664
/branches/PR-7250612/darwinbuild/thinPackages.in:635-650
/branches/PR-7341154/darwinbuild/thinPackages.in:682-694
/branches/PR-7431723/darwinbuild/thinPackages.in:660-664
/branches/PR-7461534/darwinbuild/thinPackages.in:650-664
/branches/PR-7529688/darwinbuild/thinPackages.in:692-694
/trunk/darwinbuild/thinPackages.sh:432-434
+ /branches/PR-4841388/darwinbuild/thinPackages.sh:399-419
/branches/PR-6358021/darwinbuild/thinPackages.sh:442-443
/branches/PR-6392966/darwinbuild/thinPackages.sh:423-427
/branches/PR-6398060/darwinbuild/thinPackages.sh:433-434
/branches/PR-6493844/darwinbuild/thinPackages.sh.in:460-461
/branches/PR-6497694/darwinbuild/thinPackages.sh.in:466-468,471
/branches/PR-6634286/darwinbuild/thinPackages.in:632-650
/branches/PR-6688645/darwinbuild/thinPackages.sh.in:479-490
/branches/PR-6722857/darwinbuild/thinPackages.sh.in:495-499
/branches/PR-6729491/darwinbuild/thinPackages.in:655-664
/branches/PR-7250612/darwinbuild/thinPackages.in:635-650
/branches/PR-7341154/darwinbuild/thinPackages.in:682-694
/branches/PR-7431723/darwinbuild/thinPackages.in:660-664
/branches/PR-7461534/darwinbuild/thinPackages.in:650-664
/branches/PR-7489777/darwinbuild/thinPackages.in:676-731
/branches/PR-7529688/darwinbuild/thinPackages.in:692-694
/branches/PR-7598640/darwinbuild/thinPackages.in:703-731
/trunk/darwinbuild/thinPackages.sh:432-434
Modified: trunk/darwinbuild.xcodeproj/project.pbxproj
===================================================================
--- trunk/darwinbuild.xcodeproj/project.pbxproj 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinbuild.xcodeproj/project.pbxproj 2010-03-03 21:37:30 UTC (rev 732)
@@ -163,6 +163,10 @@
72C86C9F109745BC00C66E90 /* Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 72C86BE610965E4F00C66E90 /* Utils.cpp */; };
72C86CE210974CC800C66E90 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72C86CE110974CC700C66E90 /* libcrypto.dylib */; };
72C86CE410974CC800C66E90 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72C86CE310974CC800C66E90 /* libsqlite3.dylib */; };
+ DF12E2821119E2B0007587C1 /* DB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF12E2811119E2B0007587C1 /* DB.cpp */; };
+ DFC9772D11138F9400CAE084 /* Column.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC9772711138F9400CAE084 /* Column.cpp */; };
+ DFC9772E11138F9400CAE084 /* Database.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC9772911138F9400CAE084 /* Database.cpp */; };
+ DFC9772F11138F9400CAE084 /* Table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC9772B11138F9400CAE084 /* Table.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -741,6 +745,14 @@
72C86CDD10974C3A00C66E90 /* libredo_prebinding.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libredo_prebinding.a; path = /usr/local/lib/libredo_prebinding.a; sourceTree = "<absolute>"; };
72C86CE110974CC700C66E90 /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = /usr/lib/libcrypto.dylib; sourceTree = "<absolute>"; };
72C86CE310974CC800C66E90 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = /usr/lib/libsqlite3.dylib; sourceTree = "<absolute>"; };
+ DF12E2801119E2B0007587C1 /* DB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DB.h; path = darwinup/DB.h; sourceTree = "<group>"; };
+ DF12E2811119E2B0007587C1 /* DB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DB.cpp; path = darwinup/DB.cpp; sourceTree = "<group>"; };
+ DFC9772711138F9400CAE084 /* Column.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Column.cpp; path = darwinup/Column.cpp; sourceTree = "<group>"; };
+ DFC9772811138F9400CAE084 /* Column.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Column.h; path = darwinup/Column.h; sourceTree = "<group>"; };
+ DFC9772911138F9400CAE084 /* Database.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Database.cpp; path = darwinup/Database.cpp; sourceTree = "<group>"; };
+ DFC9772A11138F9400CAE084 /* Database.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Database.h; path = darwinup/Database.h; sourceTree = "<group>"; };
+ DFC9772B11138F9400CAE084 /* Table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Table.cpp; path = darwinup/Table.cpp; sourceTree = "<group>"; };
+ DFC9772C11138F9400CAE084 /* Table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Table.h; path = darwinup/Table.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -1006,6 +1018,12 @@
72C86BD710965DD800C66E90 /* darwinup */ = {
isa = PBXGroup;
children = (
+ DFC9772711138F9400CAE084 /* Column.cpp */,
+ DFC9772811138F9400CAE084 /* Column.h */,
+ DFC9772911138F9400CAE084 /* Database.cpp */,
+ DFC9772A11138F9400CAE084 /* Database.h */,
+ DFC9772B11138F9400CAE084 /* Table.cpp */,
+ DFC9772C11138F9400CAE084 /* Table.h */,
72C86BDA10965E4F00C66E90 /* Archive.cpp */,
72C86BDB10965E4F00C66E90 /* Archive.h */,
72C86BDC10965E4F00C66E90 /* Depot.cpp */,
@@ -1020,6 +1038,8 @@
72C86BE510965E4F00C66E90 /* SerialSet.h */,
72C86BE610965E4F00C66E90 /* Utils.cpp */,
72C86BE710965E4F00C66E90 /* Utils.h */,
+ DF12E2801119E2B0007587C1 /* DB.h */,
+ DF12E2811119E2B0007587C1 /* DB.cpp */,
);
name = darwinup;
sourceTree = "<group>";
@@ -2158,6 +2178,10 @@
72C86C9D109745BC00C66E90 /* main.cpp in Sources */,
72C86C9E109745BC00C66E90 /* SerialSet.cpp in Sources */,
72C86C9F109745BC00C66E90 /* Utils.cpp in Sources */,
+ DFC9772D11138F9400CAE084 /* Column.cpp in Sources */,
+ DFC9772E11138F9400CAE084 /* Database.cpp in Sources */,
+ DFC9772F11138F9400CAE084 /* Table.cpp in Sources */,
+ DF12E2821119E2B0007587C1 /* DB.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Modified: trunk/darwintrace/darwintrace.c
===================================================================
--- trunk/darwintrace/darwintrace.c 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwintrace/darwintrace.c 2010-03-03 21:37:30 UTC (rev 732)
@@ -76,6 +76,7 @@
"/Volumes/BuildRoot_",
"/usr/bin/xcrun",
"/usr/bin/xcode",
+ "/usr/local/share/darwin",
"/usr/share/xcode",
"/var/folders/",
"/var/tmp/",
Modified: trunk/darwinup/Archive.cpp
===================================================================
--- trunk/darwinup/Archive.cpp 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Archive.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -89,7 +89,6 @@
char* Archive::create_directory(const char* prefix) {
int res = 0;
char* path = this->directory_name(prefix);
- IF_DEBUG("creating directory: %s\n", path);
if (path && res == 0) res = mkdir(path, 0777);
if (res != 0) {
fprintf(stderr, "%s:%d: could not create directory: %s: %s (%d)\n", __FILE__, __LINE__, path, strerror(errno), errno);
@@ -106,7 +105,6 @@
char uuidstr[37];
uuid_unparse_upper(m_uuid, uuidstr);
asprintf(&tarpath, "%s/%s.tar.bz2", prefix, uuidstr);
- IF_DEBUG("compacting %s/%s to %s\n", prefix, uuidstr, tarpath);
if (tarpath) {
const char* args[] = {
"/usr/bin/tar",
@@ -130,7 +128,6 @@
char uuidstr[37];
uuid_unparse_upper(m_uuid, uuidstr);
asprintf(&tarpath, "%s/%s.tar.bz2", prefix, uuidstr);
- IF_DEBUG("expanding %s to %s\n", tarpath, prefix);
if (tarpath) {
const char* args[] = {
"/usr/bin/tar",
Modified: trunk/darwinup/Archive.h
===================================================================
--- trunk/darwinup/Archive.h 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Archive.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -30,13 +30,23 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
+#ifndef _ARCHIVE_H
+#define _ARCHIVE_H
+
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <uuid/uuid.h>
+typedef char* archive_name_t;
+enum archive_keyword_t {
+ DEPOT_ARCHIVE_NEWEST,
+ DEPOT_ARCHIVE_OLDEST
+};
+
+
//
// ARCHIVE_INFO flags stored in the database
//
@@ -131,6 +141,7 @@
time_t m_date_installed;
friend struct Depot;
+ friend struct DarwinupDatabase;
};
@@ -301,3 +312,6 @@
ZipArchive(const char* path);
virtual int extract(const char* destdir);
};
+
+#endif
+
Copied: trunk/darwinup/Column.cpp (from rev 731, branches/PR-7489777/darwinup/Column.cpp)
===================================================================
--- trunk/darwinup/Column.cpp (rev 0)
+++ trunk/darwinup/Column.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "Column.h"
+
+Column::Column(const char* name, uint32_t type) {
+ m_name = strdup(name);
+ m_create_sql = NULL;
+ m_type = type;
+ m_is_index = false;
+ m_is_pk = false;
+ m_is_unique = false;
+}
+
+Column::Column(const char* name, uint32_t type,
+ bool is_index, bool is_pk, bool is_unique) {
+ m_name = strdup(name);
+ m_create_sql = NULL;
+ m_type = type;
+ m_is_index = is_index;
+ m_is_pk = is_pk;
+ m_is_unique = is_unique;
+}
+
+Column::~Column() {
+ free(m_name);
+ free(m_create_sql);
+}
+
+const char* Column::name() {
+ return m_name;
+}
+
+uint32_t Column::type() {
+ return m_type;
+}
+
+const bool Column::is_index() {
+ return m_is_index;
+}
+
+const bool Column::is_pk() {
+ return m_is_pk;
+}
+
+const bool Column::is_unique() {
+ return m_is_unique;
+}
+
+
+const char* Column::typestr() {
+ switch(m_type) {
+ case SQLITE_INTEGER:
+ return "INTEGER";
+ break;
+ case SQLITE_TEXT:
+ return "TEXT";
+ break;
+ case SQLITE_BLOB:
+ return "BLOB";
+ break;
+ default:
+ fprintf(stderr, "Error: unknown column type: %d \n", m_type);
+ return "UNKNOWN";
+ }
+}
+
+uint32_t Column::size() {
+ // integers are stored inband in the record
+ if (m_type == SQLITE_INTEGER) return sizeof(uint64_t);
+ // everything else is stored out of band
+ return sizeof(void*);
+}
+
+int Column::offset() {
+ return m_offset;
+}
+
+const char* Column::create() {
+ if (!m_create_sql) {
+ asprintf(&m_create_sql, "%s %s%s%s", m_name, this->typestr(),
+ (this->is_pk() ? " PRIMARY KEY AUTOINCREMENT" : ""),
+ (this->is_unique() ? " UNIQUE" : ""));
+ }
+ return (const char*)m_create_sql;
+}
Copied: trunk/darwinup/Column.h (from rev 731, branches/PR-7489777/darwinup/Column.h)
===================================================================
--- trunk/darwinup/Column.h (rev 0)
+++ trunk/darwinup/Column.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#ifndef _COLUMN_H
+#define _COLUMN_H
+
+#include <stdint.h>
+#include <sqlite3.h>
+
+#include "Utils.h"
+
+/**
+ * Column objects represent a column in a database table. They store
+ * type information and chunks of sql for their Table to build
+ * queries with.
+ */
+struct Column {
+ Column(const char* name, uint32_t type);
+ Column(const char* name, uint32_t type,
+ bool is_index, bool is_pk, bool is_unique);
+ virtual ~Column();
+
+ const char* name();
+ uint32_t type();
+ const bool is_index();
+ const bool is_pk();
+ const bool is_unique();
+
+ // return size of this column when packed into a result record
+ uint32_t size();
+
+protected:
+ // return a string representation of this columns type suitable
+ // for sql queries
+ const char* typestr();
+
+ // return the offset of this column in the Table's result record
+ int offset();
+
+ // generate the sql needed to create this column
+ const char* create();
+
+ char* m_name;
+ char* m_create_sql;
+ uint32_t m_type; // SQLITE_* type definition
+ bool m_is_index;
+ bool m_is_pk;
+ bool m_is_unique;
+ int m_offset;
+
+ friend struct Table;
+};
+
+#endif
Copied: trunk/darwinup/DB.cpp (from rev 731, branches/PR-7489777/darwinup/DB.cpp)
===================================================================
--- trunk/darwinup/DB.cpp (rev 0)
+++ trunk/darwinup/DB.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#include "DB.h"
+
+
+DarwinupDatabase::DarwinupDatabase(const char* path) : Database(path) {
+ this->connect();
+}
+
+DarwinupDatabase::~DarwinupDatabase() {
+ // parent automatically deallocates schema objects
+}
+
+void DarwinupDatabase::init_schema() {
+ this->m_archives_table = new Table("archives");
+ ADD_PK(m_archives_table, "serial");
+ ADD_INDEX(m_archives_table, "uuid", TYPE_BLOB, true);
+ ADD_TEXT(m_archives_table, "name");
+ ADD_INTEGER(m_archives_table, "date_added");
+ ADD_INTEGER(m_archives_table, "active");
+ ADD_INTEGER(m_archives_table, "info");
+ assert(this->add_table(this->m_archives_table)==0);
+
+ this->m_files_table = new Table("files");
+ ADD_PK(m_files_table, "serial");
+ ADD_INDEX(m_files_table, "archive", TYPE_INTEGER, false);
+ ADD_INTEGER(m_files_table, "info");
+ ADD_INTEGER(m_files_table, "mode");
+ ADD_INTEGER(m_files_table, "uid");
+ ADD_INTEGER(m_files_table, "gid");
+ ADD_INTEGER(m_files_table, "size");
+ ADD_BLOB(m_files_table, "digest");
+ ADD_INDEX(m_files_table, "path", TYPE_TEXT, false);
+ // custom index to protect from duplicate files
+ assert(this->m_files_table->set_custom_create("CREATE UNIQUE INDEX files_archive_path "
+ "ON files (archive, path);") == 0);
+ assert(this->add_table(this->m_files_table)==0);
+}
+
+int DarwinupDatabase::activate_archive(uint64_t serial) {
+ uint64_t active = 1;
+ return this->set_archive_active(serial, &active);
+}
+
+int DarwinupDatabase::deactivate_archive(uint64_t serial) {
+ uint64_t active = 0;
+ return this->set_archive_active(serial, &active);
+}
+
+int DarwinupDatabase::set_archive_active(uint64_t serial, uint64_t* active) {
+ return this->update_value("activate_archive",
+ this->m_archives_table,
+ this->m_archives_table->column(4), // active
+ (void**)active,
+ 1, // number of where conditions
+ this->m_archives_table->column(0), // serial
+ '=', serial);
+}
+
+int DarwinupDatabase::update_archive(uint64_t serial, uuid_t uuid, const char* name,
+ time_t date_added, uint32_t active, uint32_t info) {
+ return this->update(this->m_archives_table, serial,
+ (uint8_t*)uuid,
+ (uint32_t)sizeof(uuid_t),
+ name,
+ (uint64_t)date_added,
+ (uint64_t)active,
+ (uint64_t)info);
+}
+
+uint64_t DarwinupDatabase::insert_archive(uuid_t uuid, uint32_t info, const char* name,
+ time_t date_added) {
+
+ int res = this->insert(this->m_archives_table,
+ (uint8_t*)uuid,
+ (uint32_t)sizeof(uuid_t),
+ name,
+ (uint64_t)date_added,
+ (uint64_t)0,
+ (uint64_t)info);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to insert archive %s: %s \n",
+ name, this->error());
+ return 0;
+ }
+
+ return this->last_insert_id();
+}
+
+File* DarwinupDatabase::make_file(uint8_t* data) {
+ // XXX do this with a for loop and column->type()
+ uint64_t serial;
+ memcpy(&serial, &data[this->file_offset(0)], sizeof(uint64_t));
+ uint64_t archive_serial;
+ memcpy(&archive_serial, &data[this->file_offset(1)], sizeof(uint64_t));
+ uint64_t info;
+ memcpy(&info, &data[this->file_offset(2)], sizeof(uint64_t));
+ uint64_t mode;
+ memcpy(&mode, &data[this->file_offset(3)], sizeof(uint64_t));
+ uint64_t uid;
+ memcpy(&uid, &data[this->file_offset(4)], sizeof(uint64_t));
+ uint64_t gid;
+ memcpy(&gid, &data[this->file_offset(5)], sizeof(uint64_t));
+ uint64_t size;
+ memcpy(&size, &data[this->file_offset(6)], sizeof(uint64_t));
+
+ Digest* digest = NULL;
+ uint8_t* dp;
+ memcpy(&dp, &data[this->file_offset(7)], sizeof(uint8_t*));
+ if (dp) {
+ digest = new Digest();
+ digest->m_size = 20; // size of SHA1 hash
+ memcpy(digest->m_data, dp, 20);
+ }
+
+ char* path;
+ memcpy(&path, &data[this->file_offset(8)], sizeof(char*));
+
+ uint8_t* archive_data;
+ int res = this->get_archive(&archive_data, archive_serial);
+ Archive* archive = NULL;
+ if (FOUND(res)) {
+ archive = this->make_archive(archive_data);
+ } else {
+ fprintf(stderr, "Error: DB::make_file could not find the archive for file: %s: %d \n", path, res);
+ return NULL;
+ }
+ this->m_archives_table->free_result(archive_data);
+
+ File* result = FileFactory(serial, archive, info, (const char*)path, mode, uid, gid, size, digest);
+ this->m_files_table->free_result(data);
+
+ return result;
+}
+
+
+
+int DarwinupDatabase::get_next_file(uint8_t** data, File* file, file_starseded_t star) {
+ int res = SQLITE_OK;
+
+ char comp = '<';
+ const char* name = "file_preceded";
+ int order = ORDER_BY_DESC;
+ if (star == FILE_SUPERSEDED) {
+ comp = '>';
+ name = "file_superseded";
+ order = ORDER_BY_ASC;
+ }
+ res = this->get_row_ordered(name,
+ data,
+ this->m_files_table,
+ this->m_files_table->column(1), // order by archive
+ order,
+ 2,
+ this->m_files_table->column(1), // archive
+ comp, file->archive()->serial(),
+ this->m_files_table->column(8), // path
+ '=', file->path());
+
+ if (res == SQLITE_ROW) return (DB_FOUND | DB_OK);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::get_file_serial_from_archive(Archive* archive, const char* path, uint64_t** serial) {
+ int res = this->get_value("file_serial__archive_path",
+ (void**)serial,
+ this->m_files_table,
+ this->m_files_table->column(0), // serial
+ 2, // number of where conditions
+ this->m_files_table->column(1), // archive
+ '=', (uint64_t)archive->serial(),
+ this->m_files_table->column(8), // path
+ '=', path);
+
+ if (res == SQLITE_ROW) return (DB_FOUND | DB_OK);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::update_file(uint64_t serial, Archive* archive, uint32_t info, mode_t mode,
+ uid_t uid, gid_t gid, Digest* digest, const char* path) {
+
+ int res = SQLITE_OK;
+
+ // update the information
+ res = this->update(this->m_files_table, serial,
+ (uint64_t)archive->serial(),
+ (uint64_t)info,
+ (uint64_t)mode,
+ (uint64_t)uid,
+ (uint64_t)gid,
+ (uint64_t)0,
+ (uint8_t*)(digest ? digest->data() : NULL),
+ (uint32_t)(digest ? digest->size() : 0),
+ path);
+
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to update file with serial %llu and path %s: %s \n",
+ serial, path, this->error());
+ }
+
+ return res;
+}
+
+uint64_t DarwinupDatabase::insert_file(uint32_t info, mode_t mode, uid_t uid, gid_t gid,
+ Digest* digest, Archive* archive, const char* path) {
+
+ int res = this->insert(this->m_files_table,
+ (uint64_t)archive->serial(),
+ (uint64_t)info,
+ (uint64_t)mode,
+ (uint64_t)uid,
+ (uint64_t)gid,
+ (uint64_t)0,
+ (uint8_t*)(digest ? digest->data() : NULL),
+ (uint32_t)(digest ? digest->size() : 0),
+ path);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to insert file at %s: %s \n",
+ path, this->error());
+ return 0;
+ }
+
+ return this->last_insert_id();
+}
+
+uint64_t DarwinupDatabase::count_files(Archive* archive, const char* path) {
+ int res = SQLITE_OK;
+ uint64_t* c;
+ res = this->count("count_files",
+ (void**)&c,
+ this->m_files_table,
+ 2, // number of where conditions
+ this->m_files_table->column(1), // archive
+ '=', (uint64_t)archive->serial(),
+ this->m_files_table->column(8), // path
+ '=', path);
+ if (res != SQLITE_ROW) {
+ fprintf(stderr, "Error: unable to count files: %d \n", res);
+ return 0;
+ }
+ return *c;
+}
+
+uint64_t DarwinupDatabase::count_archives(bool include_rollbacks) {
+ int res = SQLITE_OK;
+ uint64_t* c;
+ if (include_rollbacks) {
+ res = this->count("count_archives",
+ (void**)&c,
+ this->m_archives_table, 0);
+ } else {
+ res = this->count("count_archives_norollback",
+ (void**)&c,
+ this->m_archives_table,
+ 1,
+ this->m_archives_table->column(2), // name
+ '!', "<Rollback>");
+ }
+ if (res != SQLITE_ROW) {
+ fprintf(stderr, "Error: unable to count archives: %d \n", res);
+ return 0;
+ }
+ return *c;
+}
+
+int DarwinupDatabase::delete_archive(Archive* archive) {
+ int res = this->del(this->m_archives_table, archive->serial());
+ if (res != SQLITE_OK) return DB_ERROR;
+ return DB_OK;
+}
+
+int DarwinupDatabase::delete_archive(uint64_t serial) {
+ int res = this->del(this->m_archives_table, serial);
+ if (res != SQLITE_OK) return DB_ERROR;
+ return DB_OK;
+}
+
+int DarwinupDatabase::delete_empty_archives() {
+ int res = this->sql("delete_empty_archives",
+ "DELETE FROM archives "
+ "WHERE serial IN "
+ " (SELECT serial FROM archives "
+ " WHERE serial NOT IN "
+ " (SELECT DISTINCT archive FROM files));");
+ if (res != SQLITE_OK) return DB_ERROR;
+ return DB_OK;
+}
+
+int DarwinupDatabase::delete_file(File* file) {
+ int res = this->del(this->m_files_table, file->serial());
+ if (res != SQLITE_OK) return DB_ERROR;
+ return DB_OK;
+}
+
+int DarwinupDatabase::delete_file(uint64_t serial) {
+ int res = this->del(this->m_files_table, serial);
+ if (res != SQLITE_OK) return DB_ERROR;
+ return DB_OK;
+}
+
+int DarwinupDatabase::delete_files(Archive* archive) {
+ int res = this->del("delete_files__archive",
+ this->m_files_table,
+ 1, // number of where conditions
+ this->m_files_table->column(1), // archive
+ '=', (uint64_t)archive->serial());
+ if (res != SQLITE_OK) return DB_ERROR;
+ return DB_OK;
+}
+
+
+int DarwinupDatabase::get_inactive_archive_serials(uint64_t** serials, uint32_t* count) {
+ int res = this->get_column("inactive_archive_serials",
+ (void**)serials, count,
+ this->m_archives_table,
+ this->m_archives_table->column(0), // serial
+ 1,
+ this->m_archives_table->column(4), // active
+ '=', (uint64_t)0);
+ if (res == SQLITE_DONE && *count) return (DB_OK | DB_FOUND);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::get_files(uint8_t*** data, uint32_t* count, Archive* archive) {
+ int res = this->get_all_ordered("files__archive",
+ data, count,
+ this->m_files_table,
+ this->m_files_table->column(8), // order by path
+ ORDER_BY_ASC,
+ 1,
+ this->m_files_table->column(1),
+ '=', archive->serial());
+
+ if ((res == SQLITE_DONE) && *count) return (DB_OK | DB_FOUND);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::get_file_serials(uint64_t** serials, uint32_t* count) {
+ int res = this->get_column("file_serials", (void**)serials, count,
+ this->m_files_table,
+ this->m_files_table->column(0),
+ 0);
+ if (res == SQLITE_DONE && *count) return (DB_OK | DB_FOUND);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+
+Archive* DarwinupDatabase::make_archive(uint8_t* data) {
+ // XXX do this with a for loop and column->type()
+ uint64_t serial;
+ memcpy(&serial, &data[this->archive_offset(0)], sizeof(uint64_t));
+ uuid_t* uuid;
+ memcpy(&uuid, &data[this->archive_offset(1)], sizeof(uuid_t*));
+ char* name;
+ memcpy(&name, &data[this->archive_offset(2)], sizeof(char*));
+ time_t date_added;
+ memcpy(&date_added, &data[this->archive_offset(3)], sizeof(time_t));
+ uint64_t info;
+ memcpy(&info, &data[this->archive_offset(5)], sizeof(uint64_t));
+
+ Archive* archive = new Archive(serial, *uuid, name, NULL, info, date_added);
+ this->m_archives_table->free_result(data);
+ return archive;
+}
+
+int DarwinupDatabase::get_archives(uint8_t*** data, uint32_t* count, bool include_rollbacks) {
+ int res = this->get_all_ordered("get_archives",
+ data, count,
+ this->m_archives_table,
+ this->m_archives_table->column(0), // order by path
+ ORDER_BY_DESC,
+ 1,
+ this->m_archives_table->column(2), // name
+ '!', (include_rollbacks ? "" : "<Rollback>") );
+
+ if ((res == SQLITE_DONE) && *count) return (DB_OK | DB_FOUND);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::get_archive(uint8_t** data, uuid_t uuid) {
+ int res = this->get_row("archive__uuid",
+ data,
+ this->m_archives_table,
+ 1,
+ this->m_archives_table->column(1), // uuid
+ '=', uuid, sizeof(uuid_t));
+ if (res == SQLITE_ROW) return (DB_FOUND | DB_OK);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::get_archive(uint8_t** data, uint64_t serial) {
+ int res = this->get_row("archive__serial",
+ data,
+ this->m_archives_table,
+ 1,
+ this->m_archives_table->column(0), // serial
+ '=', serial);
+ if (res == SQLITE_ROW) return (DB_FOUND | DB_OK);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::get_archive(uint8_t** data, const char* name) {
+ int res = this->get_row("archive__name",
+ data,
+ this->m_archives_table,
+ 1,
+ this->m_archives_table->column(2), // name
+ '=', name);
+ if (res == SQLITE_ROW) return (DB_FOUND | DB_OK);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::get_archive(uint8_t** data, archive_keyword_t keyword) {
+ int res = SQLITE_OK;
+ int order = ORDER_BY_DESC;
+
+ if (keyword == DEPOT_ARCHIVE_OLDEST) {
+ order = ORDER_BY_ASC;
+ }
+
+ res = this->get_row_ordered("archive__keyword",
+ data,
+ this->m_archives_table,
+ this->m_archives_table->column(3), // order by date_added
+ order,
+ 1,
+ this->m_archives_table->column(2), // name
+ '!', "<Rollback>");
+
+ if (res == SQLITE_ROW) return (DB_FOUND | DB_OK);
+ if (res == SQLITE_DONE) return DB_OK;
+ return DB_ERROR;
+}
+
+int DarwinupDatabase::archive_offset(int column) {
+ return this->m_archives_table->offset(column);
+}
+
+int DarwinupDatabase::file_offset(int column) {
+ return this->m_files_table->offset(column);
+}
Copied: trunk/darwinup/DB.h (from rev 731, branches/PR-7489777/darwinup/DB.h)
===================================================================
--- trunk/darwinup/DB.h (rev 0)
+++ trunk/darwinup/DB.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#ifndef _DB_H
+#define _DB_H
+
+#include <stdint.h>
+#include <assert.h>
+#include <uuid/uuid.h>
+#include <time.h>
+
+#include "Database.h"
+#include "Table.h"
+#include "Archive.h"
+#include "Digest.h"
+#include "File.h"
+
+
+/**
+ *
+ * Darwinup database abstraction. This class is responsible
+ * for generating the Table and Column objects that make
+ * up the darwinup database schema, but the parent handles
+ * deallocation.
+ *
+ */
+struct DarwinupDatabase : Database {
+ DarwinupDatabase(const char* path);
+ virtual ~DarwinupDatabase();
+ void init_schema();
+
+ uint64_t count_files(Archive* archive, const char* path);
+ uint64_t count_archives(bool include_rollbacks);
+
+ // Archives
+ Archive* make_archive(uint8_t* data);
+ int get_archives(uint8_t*** data, uint32_t* count, bool include_rollbacks);
+ int get_archive(uint8_t** data, uuid_t uuid);
+ int get_archive(uint8_t** data, uint64_t serial);
+ int get_archive(uint8_t** data, const char* name);
+ int get_archive(uint8_t** data, archive_keyword_t keyword);
+ int get_inactive_archive_serials(uint64_t** serials, uint32_t* count);
+ int archive_offset(int column);
+ int activate_archive(uint64_t serial);
+ int deactivate_archive(uint64_t serial);
+ int update_archive(uint64_t serial, uuid_t uuid, const char* name,
+ time_t date_added, uint32_t active, uint32_t info);
+ uint64_t insert_archive(uuid_t uuid, uint32_t info, const char* name, time_t date);
+ int delete_empty_archives();
+ int delete_archive(Archive* archive);
+ int delete_archive(uint64_t serial);
+
+ // Files
+ File* make_file(uint8_t* data);
+ int get_next_file(uint8_t** data, File* file, file_starseded_t star);
+ int get_file_serials(uint64_t** serials, uint32_t* count);
+ int get_file_serial_from_archive(Archive* archive, const char* path, uint64_t** serial);
+ int get_files(uint8_t*** data, uint32_t* count, Archive* archive);
+ int file_offset(int column);
+ int update_file(uint64_t serial, Archive* archive, uint32_t info, mode_t mode,
+ uid_t uid, gid_t gid, Digest* digest, const char* path);
+ uint64_t insert_file(uint32_t info, mode_t mode, uid_t uid, gid_t gid,
+ Digest* digest, Archive* archive, const char* path);
+ int delete_file(uint64_t serial);
+ int delete_file(File* file);
+ int delete_files(Archive* archive);
+
+
+protected:
+
+ int set_archive_active(uint64_t serial, uint64_t* active);
+
+ Table* m_archives_table;
+ Table* m_files_table;
+
+};
+
+#endif
+
Copied: trunk/darwinup/Database.cpp (from rev 731, branches/PR-7489777/darwinup/Database.cpp)
===================================================================
--- trunk/darwinup/Database.cpp (rev 0)
+++ trunk/darwinup/Database.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#include "Database.h"
+
+/**
+ * sqlite3_trace callback for debugging
+ */
+void dbtrace(void* context, const char* sql) {
+ IF_DEBUG("[TRACE] %s \n", sql);
+}
+
+Database::Database() {
+ m_table_max = 2;
+ m_table_count = 0;
+ m_tables = (Table**)malloc(sizeof(Table*) * m_table_max);
+ this->init_cache();
+ m_db = NULL;
+ m_path = NULL;
+ m_error_size = ERROR_BUF_SIZE;
+ m_error = (char*)malloc(m_error_size);
+}
+
+Database::Database(const char* path) {
+ m_table_max = 2;
+ m_table_count = 0;
+ m_tables = (Table**)malloc(sizeof(Table*) * m_table_max);
+ this->init_cache();
+ m_db = NULL;
+ m_path = strdup(path);
+ if (!m_path) {
+ fprintf(stderr, "Error: ran out of memory when constructing "
+ "database object.\n");
+ }
+ m_error_size = ERROR_BUF_SIZE;
+ m_error = (char*)malloc(m_error_size);
+}
+
+Database::~Database() {
+ for (uint32_t i = 0; i < m_table_count; i++) {
+ delete m_tables[i];
+ }
+ this->destroy_cache();
+
+ sqlite3_finalize(m_begin_transaction);
+ sqlite3_finalize(m_rollback_transaction);
+ sqlite3_finalize(m_commit_transaction);
+
+ free(m_tables);
+ free(m_path);
+ free(m_error);
+}
+
+
+void Database::init_schema() {
+ // do nothing... children should implement this
+}
+
+const char* Database::path() {
+ return m_path;
+}
+
+const char* Database::error() {
+ return m_error;
+}
+
+int Database::connect() {
+ if (!m_path) {
+ fprintf(stderr, "Error: need to specify a path to Database.\n");
+ return -1;
+ }
+ int res = SQLITE_OK;
+ this->init_schema();
+ res = sqlite3_open(m_path, &m_db);
+ if (res) {
+ sqlite3_close(m_db);
+ m_db = NULL;
+ fprintf(stderr, "Error: unable to connect to database at: %s \n",
+ m_path);
+ return res;
+ }
+ sqlite3_trace(m_db, dbtrace, NULL);
+ if (this->is_empty()) {
+ assert(this->create_tables() == 0);
+ }
+
+ // prepare transaction statements
+ if (res == SQLITE_OK)
+ res = sqlite3_prepare_v2(m_db, "BEGIN TRANSACTION", 18,
+ &m_begin_transaction, NULL);
+ if (res == SQLITE_OK)
+ res = sqlite3_prepare_v2(m_db, "ROLLBACK TRANSACTION", 21,
+ &m_rollback_transaction, NULL);
+ if (res == SQLITE_OK)
+ res = sqlite3_prepare_v2(m_db, "COMMIT TRANSACTION", 19,
+ &m_commit_transaction, NULL);
+
+ return res;
+}
+
+int Database::connect(const char* path) {
+ this->m_path = strdup(path);
+ if (!m_path) {
+ fprintf(stderr, "Error: ran out of memory when trying to connect to "
+ "database.\n");
+ return 1;
+ }
+ return this->connect();
+}
+
+int Database::begin_transaction() {
+ return this->execute(m_begin_transaction);
+}
+
+int Database::rollback_transaction() {
+ return this->execute(m_rollback_transaction);
+}
+
+int Database::commit_transaction() {
+ return this->execute(m_commit_transaction);
+}
+
+int Database::bind_all_columns(sqlite3_stmt* stmt, Table* table, va_list args) {
+ int res = DB_OK;
+ int param = 1;
+ for (uint32_t i=0; i<table->column_count(); i++) {
+ Column* col = table->column(i);
+ if (col->is_pk()) continue;
+ uint8_t* bdata = NULL;
+ uint32_t bsize = 0;
+ switch(col->type()) {
+ case TYPE_INTEGER:
+ res = sqlite3_bind_int64(stmt, param++, va_arg(args, uint64_t));
+ break;
+ case TYPE_TEXT:
+ res = sqlite3_bind_text(stmt, param++, va_arg(args, char*),
+ -1, SQLITE_STATIC);
+ break;
+ case TYPE_BLOB:
+ bdata = va_arg(args, uint8_t*);
+ bsize = va_arg(args, uint32_t);
+ res = sqlite3_bind_blob(stmt, param++,
+ bdata,
+ bsize,
+ SQLITE_STATIC);
+ break;
+ }
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: failed to bind parameter #%d with column #%d"
+ "of type %d table %s \n",
+ param, i, col->type(), table->name());
+ return res;
+ }
+ }
+ return res;
+}
+
+int Database::bind_va_columns(sqlite3_stmt* stmt, uint32_t count, va_list args) {
+ return this->bind_columns(stmt, count, 1, args);
+}
+
+int Database::bind_columns(sqlite3_stmt* stmt, uint32_t count, int param,
+ va_list args) {
+ int res = DB_OK;
+ for (uint32_t i=0; i<count; i++) {
+ Column* col = va_arg(args, Column*);
+ va_arg(args, int);
+ uint8_t* bdata = NULL;
+ uint32_t bsize = 0;
+ char* tval;
+ switch(col->type()) {
+ case TYPE_INTEGER:
+ res = sqlite3_bind_int64(stmt, param++, va_arg(args, uint64_t));
+ break;
+ case TYPE_TEXT:
+ tval = va_arg(args, char*);
+ res = sqlite3_bind_text(stmt, param++, tval, -1, SQLITE_STATIC);
+ break;
+ case TYPE_BLOB:
+ bdata = va_arg(args, uint8_t*);
+ bsize = va_arg(args, uint32_t);
+ res = sqlite3_bind_blob(stmt, param++,
+ bdata,
+ bsize,
+ SQLITE_STATIC);
+ break;
+ }
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: failed to bind parameter #%d with column #%d "
+ "of type %d res %d: %s \n",
+ param-1, i, col->type(), res,
+ sqlite3_errmsg(m_db));
+ return res;
+ }
+ }
+ return res;
+}
+
+#define __get_stmt(expr) \
+ sqlite3_stmt* stmt; \
+ sqlite3_stmt** pps; \
+ char* key = strdup(name); \
+ cache_get_and_retain(m_statement_cache, key, (void**)&pps); \
+ if (!pps) { \
+ va_list args; \
+ va_start(args, count); \
+ pps = expr; \
+ va_end(args); \
+ cache_set_and_retain(m_statement_cache, key, pps, 0); \
+ } \
+ stmt = *pps; \
+ free(key);
+
+int Database::count(const char* name, void** output, Table* table,
+ uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->count(m_db, count, args));
+ int res = SQLITE_OK;
+ res = this->bind_va_columns(stmt, count, args);
+ *output = malloc(sizeof(uint64_t));
+ assert(*output);
+ res = this->step_once(stmt, *(uint8_t**)output, NULL);
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, pps);
+ va_end(args);
+ return res;
+}
+
+int Database::get_value(const char* name, void** output, Table* table,
+ Column* value_column, uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->get_column(m_db, value_column, count, args));
+ int res = SQLITE_OK;
+ this->bind_va_columns(stmt, count, args);
+ uint32_t size = value_column->size();
+ *output = malloc(size);
+ assert(*output);
+ res = this->step_once(stmt, (uint8_t*)*output, NULL);
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, pps);
+ va_end(args);
+ return res;
+}
+
+int Database::get_column(const char* name, void** output, uint32_t* result_count,
+ Table* table, Column* column, uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->get_column(m_db, column, count, args));
+ int res = SQLITE_OK;
+ this->bind_va_columns(stmt, count, args);
+ uint32_t size = INITIAL_ROWS * column->size();
+ *output = malloc(size);
+ res = this->step_all(stmt, output, size, result_count);
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, pps);
+ va_end(args);
+ return res;
+}
+
+int Database::get_row(const char* name, uint8_t** output, Table* table,
+ uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->get_row(m_db, count, args));
+ int res = SQLITE_OK;
+ this->bind_va_columns(stmt, count, args);
+ *output = table->alloc_result();
+ res = this->step_once(stmt, *output, NULL);
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, pps);
+ va_end(args);
+ return res;
+}
+
+int Database::get_row_ordered(const char* name, uint8_t** output, Table* table,
+ Column* order_by, int order, uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->get_row_ordered(m_db, order_by, order, count, args));
+ int res = SQLITE_OK;
+ this->bind_va_columns(stmt, count, args);
+ *output = table->alloc_result();
+ res = this->step_once(stmt, *output, NULL);
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, pps);
+ va_end(args);
+ return res;
+}
+
+int Database::get_all_ordered(const char* name, uint8_t*** output,
+ uint32_t* result_count, Table* table,
+ Column* order_by, int order, uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->get_row_ordered(m_db, order_by, order, count, args));
+ int res = SQLITE_OK;
+ this->bind_va_columns(stmt, count, args);
+ uint8_t* current = NULL;
+ *result_count = 0;
+ uint32_t output_max = INITIAL_ROWS;
+ *output = (uint8_t**)calloc(output_max, sizeof(uint8_t*));
+
+ res = SQLITE_ROW;
+ while (res == SQLITE_ROW) {
+ if ((*result_count) >= output_max) {
+ output_max *= REALLOC_FACTOR;
+ *output = (uint8_t**)realloc((*output), output_max * sizeof(uint8_t*));
+ if (!(*output)) {
+ fprintf(stderr, "Error: ran out of memory trying to realloc output"
+ "in get_all_ordered.\n");
+ return DB_ERROR;
+ }
+ }
+ current = table->alloc_result();
+ res = this->step_once(stmt, current, NULL);
+ if (res == SQLITE_ROW) {
+ (*output)[(*result_count)] = current;
+ (*result_count)++;
+ } else {
+ table->free_result(current);
+ }
+ }
+
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, pps);
+ va_end(args);
+ return res;
+}
+
+int Database::update_value(const char* name, Table* table, Column* value_column,
+ void** value, uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->update_value(m_db, value_column, count, args));
+ int param = 1;
+ int res = SQLITE_OK;
+ switch(value_column->type()) {
+ case TYPE_INTEGER:
+ res = sqlite3_bind_int64(stmt, param++, (uint64_t)*value);
+ break;
+ case TYPE_TEXT:
+ res = sqlite3_bind_text(stmt, param++, (char*)*value, -1, SQLITE_STATIC);
+ break;
+ // XXX: support blob columns here
+ case TYPE_BLOB:
+ fprintf(stderr, "Error: Database::update_value() not implemented for "
+ "BLOB columns.\n");
+ assert(false);
+ }
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: update_value failed to bind value with value_column "
+ "type %d in table %s. \n",
+ value_column->type(), table->name());
+ return res;
+ }
+ this->bind_columns(stmt, count, param, args);
+ res = sqlite3_step(stmt);
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, pps);
+ va_end(args);
+ return (res == SQLITE_DONE ? SQLITE_OK : res);
+}
+
+int Database::del(const char* name, Table* table, uint32_t count, ...) {
+ va_list args;
+ va_start(args, count);
+ __get_stmt(table->del(m_db, count, args));
+ int res = SQLITE_OK;
+ this->bind_va_columns(stmt, count, args);
+ if (res == SQLITE_OK) res = this->execute(stmt);
+ va_end(args);
+ return res;
+
+}
+
+/**
+ * Given a table and an arg list in the same order as Table::add_column() calls,
+ * binds and executes a sql update. The Table is responsible for preparing the
+ * statement in Table::update()
+ *
+ * All integer args must be cast to uint64_t
+ * All blob columns must provide 2 args in the list. The first arg is a uint8_t*
+ * of data and then the uint32_t value for size of the data.
+ *
+ */
+int Database::update(Table* table, uint64_t pkvalue, ...) {
+ va_list args;
+ va_start(args, pkvalue);
+
+ int res = SQLITE_OK;
+
+ // get the prepared statement
+ sqlite3_stmt* stmt = table->update(m_db);
+ if (!stmt) {
+ fprintf(stderr, "Error: %s table gave a NULL statement when trying to "
+ "update.\n", table->name());
+ return 1;
+ }
+
+ this->bind_all_columns(stmt, table, args);
+
+ // bind the primary key in the WHERE clause
+ // bind_all_columns already bound the first n'th params, where n in the
+ // table's column count, so we provide that count as the parameter value
+ if (res==SQLITE_OK) res = sqlite3_bind_int64(stmt, table->column_count(),
+ pkvalue);
+ if (res==SQLITE_OK) res = this->execute(stmt);
+ va_end(args);
+ return res;
+}
+
+int Database::insert(Table* table, ...) {
+ va_list args;
+ va_start(args, table);
+
+ int res = SQLITE_OK;
+ // get the prepared statement
+ sqlite3_stmt* stmt = table->insert(m_db);
+ if (!stmt) {
+ fprintf(stderr, "Error: %s table gave a NULL statement when trying to "
+ "insert.\n", table->name());
+ return 1;
+ }
+ this->bind_all_columns(stmt, table, args);
+ if (res == SQLITE_OK) res = this->execute(stmt);
+ va_end(args);
+ return res;
+}
+
+#undef __get_stmt
+
+int Database::del(Table* table, uint64_t serial) {
+ int res = SQLITE_OK;
+ sqlite3_stmt* stmt = table->del(m_db);
+ if (!stmt) {
+ fprintf(stderr, "Error: %s table gave a NULL statement when trying to "
+ "delete.\n", table->name());
+ return res;
+ }
+ if (res == SQLITE_OK) res = sqlite3_bind_int64(stmt, 1, serial);
+ if (res == SQLITE_OK) res = this->execute(stmt);
+ return res;
+}
+
+uint64_t Database::last_insert_id() {
+ return (uint64_t)sqlite3_last_insert_rowid(m_db);
+}
+
+
+
+int Database::sql_once(const char* fmt, ...) {
+ int res = 0;
+ va_list args;
+ va_start(args, fmt);
+ char* error;
+ if (this->m_db) {
+ char *query = sqlite3_vmprintf(fmt, args);
+ res = sqlite3_exec(this->m_db, query, NULL, NULL, &error);
+ sqlite3_free(query);
+ } else {
+ fprintf(stderr, "Error: database not open.\n");
+ res = SQLITE_ERROR;
+ }
+ va_end(args);
+ if (error) {
+ strlcpy(m_error, error, m_error_size);
+ fprintf(stderr, "Error: sql(): %s \n", m_error);
+ fprintf(stderr, "Error: fmt: %s \n", fmt);
+ sqlite3_free(error);
+ }
+ return res;
+}
+
+int Database::sql(const char* name, const char* fmt, ...) {
+ sqlite3_stmt* stmt;
+ char* key = strdup(name);
+ cache_get_and_retain(m_statement_cache, key, (void**)&stmt);
+ if (!stmt) {
+ va_list args;
+ va_start(args, fmt);
+ char* query = sqlite3_vmprintf(fmt, args);
+ int res = sqlite3_prepare_v2(m_db, query, strlen(query), &stmt, NULL);
+ va_end(args);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to prepare statement for query: %s\n"
+ "Error: %s\n",
+ query, sqlite3_errmsg(m_db));
+ free(key);
+ return res;
+ }
+ cache_set_and_retain(m_statement_cache, key, stmt, 0); \
+ free(key);
+ }
+ return this->execute(stmt);
+}
+
+int Database::execute(sqlite3_stmt* stmt) {
+ int res = sqlite3_step(stmt);
+ if (res == SQLITE_DONE) {
+ res = SQLITE_OK;
+ } else {
+ strlcpy(m_error, sqlite3_errmsg(m_db), m_error_size);
+ fprintf(stderr, "Error: execute() error: %s \n", m_error);
+ }
+ res = sqlite3_reset(stmt);
+ return res;
+}
+
+int Database::add_table(Table* t) {
+ if (m_table_count >= m_table_max) {
+ m_tables = (Table**)realloc(m_tables,
+ m_table_max*sizeof(Table*)*REALLOC_FACTOR);
+ if (!m_tables) {
+ fprintf(stderr, "Error: unable to reallocate memory to add a "
+ "table\n");
+ return 1;
+ }
+ m_table_max *= REALLOC_FACTOR;
+ }
+ m_tables[m_table_count++] = t;
+
+ return 0;
+}
+
+/**
+ * get a row count of the first table to detect if the schema
+ * needs to be initialized
+ */
+bool Database::is_empty() {
+ if (!m_tables[0]) {
+ fprintf(stderr, "Warning: Database has not had a schema initialized.\n");
+ return false;
+ }
+ int res = SQLITE_OK;
+ char* query;
+ asprintf(&query, "SELECT count(*) FROM %s;", m_tables[0]->name());
+ res = sqlite3_exec(this->m_db, query, NULL, NULL, NULL);
+ free(query);
+ return res != SQLITE_OK;
+}
+
+int Database::create_tables() {
+ int res = SQLITE_OK;
+ for (uint32_t i=0; i<m_table_count; i++) {
+ this->sql_once(m_tables[i]->create());
+ if (res!=SQLITE_OK) {
+ fprintf(stderr, "Error: sql error trying to create table: %s: %s\n",
+ m_tables[i]->name(), m_error);
+ return res;
+ }
+ }
+ return res;
+}
+
+size_t Database::store_column(sqlite3_stmt* stmt, int column, uint8_t* output) {
+ size_t used;
+ int type = sqlite3_column_type(stmt, column);
+ const void* blob;
+ int blobsize;
+ switch(type) {
+ case SQLITE_INTEGER:
+ *(uint64_t*)output = (uint64_t)sqlite3_column_int64(stmt, column);
+ used = sizeof(uint64_t);
+ break;
+ case SQLITE_TEXT:
+ *(const char**)output = strdup((const char*)sqlite3_column_text(stmt,
+ column));
+ used = sizeof(char*);
+ break;
+ case SQLITE_BLOB:
+ blob = sqlite3_column_blob(stmt, column);
+ blobsize = sqlite3_column_bytes(stmt, column);
+ *(void**)output = malloc(blobsize);
+ if (*(void**)output && blobsize) {
+ memcpy(*(void**)output, blob, blobsize);
+ } else {
+ fprintf(stderr, "Error: unable to get blob from database stmt.\n");
+ }
+ used = sizeof(void*);
+ break;
+ case SQLITE_NULL:
+ // result row has a NULL value which is okay
+ *(const char**)output = NULL;
+ used = sizeof(char*);
+ break;
+ default:
+ fprintf(stderr, "Error: unhandled column type in "
+ "Database::store_column(): %d \n",
+ type);
+ return 0;
+ }
+
+ return used;
+}
+
+/**
+ * will not realloc memory for output since caller should know how
+ * much to alloc in the first place. Sets used to be how many bytes
+ * were written to output
+ */
+int Database::step_once(sqlite3_stmt* stmt, uint8_t* output, uint32_t* used) {
+ int res = sqlite3_step(stmt);
+ uint8_t* current = output;
+ if (used) *used = 0;
+ if (res == SQLITE_ROW) {
+ int count = sqlite3_column_count(stmt);
+ for (int i = 0; i < count; i++) {
+ current += this->store_column(stmt, i, current);
+ }
+ if (used) {
+ *used = current - output;
+ }
+ }
+
+ return res;
+}
+
+int Database::step_all(sqlite3_stmt* stmt, void** output, uint32_t size,
+ uint32_t* count) {
+ uint32_t used = 0;
+ uint32_t total_used = used;
+ uint32_t rowsize = size / INITIAL_ROWS;
+ uint8_t* current = *(uint8_t**)output;
+ *count = 0;
+ int res = SQLITE_ROW;
+ while (res == SQLITE_ROW) {
+ current = *(uint8_t**)output + total_used;
+ res = this->step_once(stmt, current, &used);
+ if (res == SQLITE_ROW) (*count)++;
+ total_used += used;
+ if (total_used >= (size - rowsize)) {
+ size *= REALLOC_FACTOR;
+ *output = realloc(*output, size);
+ if (!*output) {
+ fprintf(stderr, "Error: ran out of memory in Database::step_all \n");
+ return SQLITE_ERROR;
+ }
+ }
+ }
+ sqlite3_reset(stmt);
+ return res;
+}
+
+
+/**
+ *
+ * libcache
+ *
+ */
+void Database::init_cache() {
+ cache_attributes_t attrs;
+ attrs.version = CACHE_ATTRIBUTES_VERSION_2;
+ attrs.key_hash_cb = cache_key_hash_cb_cstring;
+ attrs.key_is_equal_cb = cache_key_is_equal_cb_cstring;
+ attrs.key_retain_cb = cache_key_retain;
+ attrs.key_release_cb = cache_release_cb_free;
+ attrs.value_release_cb = cache_statement_release;
+ attrs.value_retain_cb = NULL;
+ attrs.value_make_purgeable_cb = NULL;
+ attrs.value_make_nonpurgeable_cb = NULL;
+ attrs.user_data = NULL;
+ cache_create("org.macosforge.darwinbuild.darwinup.statements",
+ &attrs, &m_statement_cache);
+}
+
+void Database::destroy_cache() {
+ cache_destroy(m_statement_cache);
+}
+
+void cache_key_retain(void* key_in, void** key_out, void* user_data) {
+ *key_out = strdup((char*)key_in);
+}
+
+void cache_statement_release(void* value, void* user_data) {
+ sqlite3_finalize(*(sqlite3_stmt**)value);
+}
Copied: trunk/darwinup/Database.h (from rev 731, branches/PR-7489777/darwinup/Database.h)
===================================================================
--- trunk/darwinup/Database.h (rev 0)
+++ trunk/darwinup/Database.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#ifndef _DATABASE_H
+#define _DATABASE_H
+
+#include <assert.h>
+#include <cache.h>
+#include <cache_callbacks.h>
+#include <sqlite3.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "Table.h"
+#include "Digest.h"
+#include "Archive.h"
+
+// flag for generating queries with ORDER BY clauses
+#define ORDER_BY_DESC 0
+#define ORDER_BY_ASC 1
+
+// initial number of rows we allocate for when querying
+#define INITIAL_ROWS 8
+
+// how much we grow by when we need more space
+#define REALLOC_FACTOR 4
+#define ERROR_BUF_SIZE 1024
+
+// return code bits
+#define DB_OK 0x0000
+#define DB_ERROR 0x0001
+#define DB_FOUND 0x0010
+
+// test return code to see if actual results were found
+#define FOUND(x) ((x & DB_FOUND) && !(x & DB_ERROR))
+
+// Schema creation macros
+#define ADD_COLUMN(table, name, type, index, pk, unique) \
+ assert(table->add_column(new Column(name, type, index, pk, unique))==0);
+#define ADD_INDEX(table, name, type, unique) \
+ assert(table->add_column(new Column(name, type, true, false, unique))==0);
+#define ADD_PK(table, name) \
+ assert(table->add_column(new Column(name, TYPE_INTEGER, \
+ false, true, false))==0);
+#define ADD_TEXT(table, name) \
+ assert(table->add_column(new Column(name, TYPE_TEXT))==0);
+#define ADD_INTEGER(table, name) \
+ assert(table->add_column(new Column(name, TYPE_INTEGER))==0);
+#define ADD_BLOB(table, name) \
+ assert(table->add_column(new Column(name, TYPE_BLOB))==0);
+
+
+/**
+ *
+ * Generic sqlite abstraction
+ *
+ */
+struct Database {
+ Database();
+ Database(const char* path);
+ virtual ~Database();
+
+ /**
+ * init_schema is called during db connection.
+ * Projects implementing a Database derived class
+ * should use Table::add_column() or the ADD_*
+ * macros in their init_schema() to define their schema
+ */
+ virtual void init_schema();
+
+ const char* path();
+ const char* error();
+ int connect();
+ int connect(const char* path);
+
+ int begin_transaction();
+ int rollback_transaction();
+ int commit_transaction();
+
+ /**
+ * statement caching and execution
+ *
+ * - name is a string key that labels the query for caching purposes
+ * - output is where we will store the value requested
+ * - count is the number of sets of parameters
+ * - va_list should have sets of 3 (integer and text) or 4 (blob)
+ * parameters for WHERE clause like Column*, char, value(s)
+ * - Column* is the column to match against
+ * - char is how to compare, one of '=', '!', '>', or '<'
+ * - value(s) is the value to match
+ * - text columns require a char* arg
+ * - integer columns require a uint64_t arg
+ * - blob columns require 2 args in the list:
+ * - first is a uint8_t* of data
+ * - second is a uint32_t value for size of the data
+ *
+ */
+ int count(const char* name, void** output, Table* table, uint32_t count, ...);
+ int get_value(const char* name, void** output, Table* table, Column* value_column,
+ uint32_t count, ...);
+ int get_column(const char* name, void** output, uint32_t* result_count,
+ Table* table, Column* column, uint32_t count, ...);
+ int get_row(const char* name, uint8_t** output, Table* table, uint32_t count, ...);
+ int get_row_ordered(const char* name, uint8_t** output, Table* table, Column* order_by,
+ int order, uint32_t count, ...);
+ int get_all_ordered(const char* name, uint8_t*** output, uint32_t* result_count,
+ Table* table, Column* order_by, int order, uint32_t count, ...);
+ int update_value(const char* name, Table* table, Column* value_column, void** value,
+ uint32_t count, ...);
+ int del(const char* name, Table* table, uint32_t count, ...);
+
+ /**
+ * update/insert whole rows
+ *
+ * Given a table and a va_list in the same order as Table::add_column()
+ * calls, minus any primary key columns, bind and executes a sql query
+ * for insert or update.
+ *
+ * The Table is responsible for preparing the statement
+ *
+ * text columns require char* args
+ * integer columns require uint64_t args
+ * blob columns require 2 args in the list:
+ * - first is a uint8_t* of data
+ * - second is a uint32_t value for size of the data
+ *
+ */
+ int update(Table* table, uint64_t pkvalue, ...);
+ int insert(Table* table, ...);
+
+ // delete row with primary key equal to serial
+ int del(Table* table, uint64_t serial);
+
+ uint64_t last_insert_id();
+
+
+protected:
+
+ // execute query with printf-style format, does not cache statement
+ int sql_once(const char* fmt, ...);
+ // cache statement with name, execute query with printf-style format
+ int sql(const char* name, const char* fmt, ...);
+ int execute(sqlite3_stmt* stmt);
+
+ int add_table(Table*);
+
+ // test if database has had its tables created
+ bool is_empty();
+ int create_tables();
+
+ // bind all table columns from va_list
+ int bind_all_columns(sqlite3_stmt* stmt, Table* table, va_list args);
+ // bind each set of parameters from va_list
+ int bind_va_columns(sqlite3_stmt* stmt, uint32_t count, va_list args);
+ // bind parameters from va_list, starting with the param'th parameter in stmt
+ int bind_columns(sqlite3_stmt* stmt, uint32_t count, int param,
+ va_list args);
+
+ /**
+ * step and store functions
+ */
+ size_t store_column(sqlite3_stmt* stmt, int column, uint8_t* output);
+ int step_once(sqlite3_stmt* stmt, uint8_t* output, uint32_t* used);
+ int step_all(sqlite3_stmt* stmt, void** output, uint32_t size, uint32_t* count);
+
+ // libcache
+ void init_cache();
+ void destroy_cache();
+
+ char* m_path;
+ sqlite3* m_db;
+
+ Table** m_tables;
+ uint32_t m_table_count;
+ uint32_t m_table_max;
+
+ cache_t* m_statement_cache;
+
+ sqlite3_stmt* m_begin_transaction;
+ sqlite3_stmt* m_rollback_transaction;
+ sqlite3_stmt* m_commit_transaction;
+
+ char* m_error;
+ size_t m_error_size;
+
+ static const int TYPE_INTEGER = SQLITE_INTEGER;
+ static const int TYPE_TEXT = SQLITE3_TEXT;
+ static const int TYPE_BLOB = SQLITE_BLOB;
+
+};
+
+// libcache callbacks
+void cache_key_retain(void* key_in, void** key_out, void* user_data);
+void cache_statement_retain(void* value, void* user_data);
+void cache_statement_release(void* value, void* user_data);
+
+#endif
Modified: trunk/darwinup/Depot.cpp
===================================================================
--- trunk/darwinup/Depot.cpp 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Depot.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -35,7 +35,6 @@
#include "File.h"
#include "SerialSet.h"
#include "Utils.h"
-
#include <assert.h>
#include <copyfile.h>
#include <errno.h>
@@ -48,7 +47,6 @@
#include <unistd.h>
#include <sys/stat.h>
-#include <sqlite3.h>
Depot::Depot() {
m_prefix = NULL;
@@ -75,8 +73,12 @@
}
Depot::~Depot() {
+
+ // XXX: this is expensive, but is it necessary?
+ //this->check_consistency();
+
if (m_lock_fd != -1) this->unlock();
- if (m_db) sqlite3_close(m_db);
+ delete m_db;
if (m_prefix) free(m_prefix);
if (m_depot_path) free(m_depot_path);
if (m_database_path) free(m_database_path);
@@ -88,16 +90,17 @@
const char* Depot::downloads_path() { return m_downloads_path; }
const char* Depot::prefix() { return m_prefix; }
-// Initialize the depot storage on disk
-int Depot::initialize() {
- int res = 0;
-
- // initialization requires all these paths to be set
- if (!(m_prefix && m_depot_path && m_database_path && m_archives_path && m_downloads_path)) {
- return -1;
+int Depot::connect() {
+ m_db = new DarwinupDatabase(m_database_path);
+ if (!m_db) {
+ fprintf(stderr, "Error: unable to connect to database in Depot::connect().\n");
+ return 1;
}
-
- res = mkdir(m_depot_path, m_depot_mode);
+ return 0;
+}
+
+int Depot::create_storage() {
+ int res = mkdir(m_depot_path, m_depot_mode);
if (res && errno != EEXIST) {
perror(m_depot_path);
return res;
@@ -113,26 +116,39 @@
perror(m_downloads_path);
return res;
}
+ return 0;
+}
- res = this->lock(LOCK_SH);
- if (res) return res;
- m_is_locked = 1;
+// Initialize the depot
+int Depot::initialize(bool writable) {
+ int res = 0;
- int exists = is_regular_file(m_database_path);
-
- res = sqlite3_open(m_database_path, &m_db);
- if (res) {
- sqlite3_close(m_db);
- m_db = NULL;
+ // initialization requires all these paths to be set
+ if (!(m_prefix && m_depot_path && m_database_path && m_archives_path && m_downloads_path)) {
+ return -1;
}
- if (m_db && !exists) {
- this->SQL("CREATE TABLE archives (serial INTEGER PRIMARY KEY AUTOINCREMENT, uuid BLOB UNIQUE, name TEXT, date_added INTEGER, active INTEGER, info INTEGER)");
- this->SQL("CREATE TABLE files (serial INTEGER PRIMARY KEY AUTOINCREMENT, archive INTEGER, info INTEGER, mode INTEGER, uid INTEGER, gid INTEGER, size INTEGER, digest BLOB, path TEXT)");
- this->SQL("CREATE INDEX archives_uuid ON archives (uuid)");
- this->SQL("CREATE INDEX files_path ON files (path)");
+ if (writable) {
+ uid_t uid = getuid();
+ if (uid) {
+ fprintf(stderr, "You must be root to perform that operation.\n");
+ exit(3);
+ }
+ res = this->create_storage();
+ if (res) return res;
+ res = this->lock(LOCK_SH);
+ if (res) return res;
+ m_is_locked = 1;
}
-
+
+ int exists = is_regular_file(m_database_path);
+ if (!exists && !writable) {
+ // read-only mode requested but we have no database
+ return -2;
+ }
+
+ res = this->connect();
+
return res;
}
@@ -142,63 +158,26 @@
// Unserialize an archive from the database.
// Find the archive by UUID.
-// XXX: should be memoized
Archive* Depot::archive(uuid_t uuid) {
int res = 0;
Archive* archive = NULL;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT serial, name, info, date_added FROM archives WHERE uuid=?";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- res = sqlite3_bind_blob(stmt, 1, uuid, sizeof(uuid_t), SQLITE_STATIC);
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- uint64_t serial = sqlite3_column_int64(stmt, 0);
- const unsigned char* name = sqlite3_column_text(stmt, 1);
- uint64_t info = sqlite3_column_int64(stmt, 2);
- time_t date_added = sqlite3_column_int(stmt, 3);
- archive = new Archive(serial, uuid, (const char*)name, NULL, info, date_added);
- }
- sqlite3_reset(stmt);
- }
+ uint8_t* data;
+
+ res = this->m_db->get_archive(&data, uuid);
+ if (FOUND(res)) archive = this->m_db->make_archive(data);
return archive;
}
// Unserialize an archive from the database.
// Find the archive by serial.
-// XXX: should be memoized
Archive* Depot::archive(uint64_t serial) {
int res = 0;
Archive* archive = NULL;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT uuid, name, info, date_added FROM archives WHERE serial=?";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- res = sqlite3_bind_int64(stmt, 1, serial);
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- uuid_t uuid;
- const void* blob = sqlite3_column_blob(stmt, 0);
- int blobsize = sqlite3_column_bytes(stmt, 0);
- if (blobsize > 0) {
- assert(blobsize == sizeof(uuid_t));
- memcpy(uuid, blob, sizeof(uuid_t));
- } else {
- uuid_clear(uuid);
- }
- const unsigned char* name = sqlite3_column_text(stmt, 1);
- uint64_t info = sqlite3_column_int64(stmt, 2);
- time_t date_added = sqlite3_column_int(stmt, 3);
- archive = new Archive(serial, uuid, (const char*)name, NULL, info, date_added);
- }
- sqlite3_reset(stmt);
- }
+ uint8_t* data;
+
+ res = this->m_db->get_archive(&data, serial);
+ if (FOUND(res)) archive = this->m_db->make_archive(data);
+
return archive;
}
@@ -207,82 +186,23 @@
Archive* Depot::archive(archive_name_t name) {
int res = 0;
Archive* archive = NULL;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT serial, uuid, info, date_added FROM archives WHERE name=? ORDER BY date_added DESC LIMIT 1";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- res = sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC);
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- uuid_t uuid;
- const void* blob = sqlite3_column_blob(stmt, 1);
- int blobsize = sqlite3_column_bytes(stmt, 1);
- if (blobsize > 0) {
- assert(blobsize == sizeof(uuid_t));
- memcpy(uuid, blob, sizeof(uuid_t));
- } else {
- uuid_clear(uuid);
- }
- uint64_t serial = sqlite3_column_int64(stmt, 0);
- uint64_t info = sqlite3_column_int64(stmt, 2);
- time_t date_added = sqlite3_column_int(stmt, 3);
- archive = new Archive(serial, uuid, (const char*)name, NULL, info, date_added);
- }
- sqlite3_reset(stmt);
- }
+ uint8_t* data;
+
+ res = this->m_db->get_archive(&data, name);
+ if (FOUND(res)) archive = this->m_db->make_archive(data);
return archive;
}
Archive* Depot::archive(archive_keyword_t keyword) {
int res = 0;
Archive* archive = NULL;
- static sqlite3_stmt* stmt = NULL;
- const char* query = NULL;
- if (stmt == NULL && m_db) {
- if (keyword == DEPOT_ARCHIVE_NEWEST) {
- query = "SELECT serial FROM archives WHERE name != '<Rollback>' ORDER BY date_added DESC LIMIT 1";
- } else if (keyword == DEPOT_ARCHIVE_OLDEST) {
- query = "SELECT serial FROM archives WHERE name != '<Rollback>' ORDER BY date_added ASC LIMIT 1";
- } else {
- fprintf(stderr, "Error: unknown archive keyword.\n");
- res = -1;
- }
- if (res == 0) res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- uint64_t serial = sqlite3_column_int64(stmt, 0);
- archive = Depot::archive(serial);
- }
- sqlite3_reset(stmt);
- }
+ uint8_t* data;
+
+ res = this->m_db->get_archive(&data, keyword);
+ if (FOUND(res)) archive = this->m_db->make_archive(data);
return archive;
}
-// create a new Archive from a database row
-Archive* Depot::archive(sqlite3_stmt* stmt) {
- uuid_t uuid;
- uint64_t serial = sqlite3_column_int64(stmt, 0);
- const void* blob = sqlite3_column_blob(stmt, 1);
- int blobsize = sqlite3_column_bytes(stmt, 1);
- const unsigned char* name = sqlite3_column_text(stmt, 2);
- uint64_t info = sqlite3_column_int64(stmt, 3);
- time_t date_added = sqlite3_column_int(stmt, 4);
- if (blobsize > 0) {
- assert(blobsize == sizeof(uuid_t));
- memcpy(uuid, blob, sizeof(uuid_t));
- } else {
- uuid_clear(uuid);
- }
- return new Archive(serial, uuid, (const char*)name, NULL, info, date_added);
-}
-
-
// Return Archive from database matching arg, which is one of:
//
// uuid (ex: 22969F32-9C4F-4370-82C8-DD3609736D8D)
@@ -292,81 +212,71 @@
// or "oldest" for the oldest installed root)
//
Archive* Depot::get_archive(const char* arg) {
+
+ // test for arg being a uuid
uuid_t uuid;
- uint64_t serial;
if (uuid_parse(arg, uuid) == 0) {
return Depot::archive(uuid);
}
- serial = strtoull(arg, NULL, 0);
- if (serial) {
+
+ // test for arg being a serial number
+ uint64_t serial;
+ char* endptr = NULL;
+ serial = strtoull(arg, &endptr, 0);
+ if (serial && (*arg != '\0') && (*endptr == '\0')) {
return Depot::archive(serial);
}
+
+ // test for keywords
if (strncasecmp("oldest", arg, 6) == 0) {
- IF_DEBUG("looking for oldest\n");
return Depot::archive(DEPOT_ARCHIVE_OLDEST);
}
if (strncasecmp("newest", arg, 6) == 0) {
- IF_DEBUG("looking for newest\n");
return Depot::archive(DEPOT_ARCHIVE_NEWEST);
}
+
+ // if nothing else, must be an archive name
return Depot::archive((archive_name_t)arg);
}
-Archive** Depot::get_all_archives(size_t* count) {
+Archive** Depot::get_all_archives(uint32_t* count) {
extern uint32_t verbosity;
- int res = 0;
- *count = this->count_archives();
- Archive** list = (Archive**)malloc(*count * sizeof(Archive*));
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT serial, uuid, name, info, date_added FROM archives WHERE name != '<Rollback>' ORDER BY serial DESC";
- if (verbosity & VERBOSE_DEBUG) {
- query = "SELECT serial, uuid, name, info, date_added FROM archives ORDER BY serial DESC";
- }
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
+ int res = DB_OK;
+ uint8_t** archlist;
+ res = this->m_db->get_archives(&archlist, count, verbosity & VERBOSE_DEBUG);
+
+ Archive** list = (Archive**)malloc(sizeof(Archive*) * (*count));
+ if (!list) {
+ fprintf(stderr, "Error: ran out of memory in Depot::get_all_archives\n");
+ return NULL;
}
- if (stmt && res == 0) {
- size_t i = 0;
- while (res != SQLITE_DONE) {
- res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- list[i++] = this->archive(stmt);
- }
+ if (FOUND(res)) {
+ for (uint32_t i=0; i < *count; i++) {
+ Archive* archive = this->m_db->make_archive(archlist[i]);
+ if (archive) {
+ list[i] = archive;
+ } else {
+ fprintf(stderr, "%s:%d: DB::make_archive returned NULL\n", __FILE__, __LINE__);
+ res = -1;
+ break;
+ }
}
- sqlite3_reset(stmt);
}
+
return list;
}
-size_t Depot::count_archives() {
+uint64_t Depot::count_archives() {
extern uint32_t verbosity;
- int res = 0;
- size_t count = 0;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT count(*) FROM archives WHERE name != '<Rollback>'";
- if (verbosity & VERBOSE_DEBUG) {
- query = "SELECT count(*) FROM archives";
- }
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- count = sqlite3_column_int64(stmt, 0);
- }
- sqlite3_reset(stmt);
- }
- return count;
+ uint64_t c = this->m_db->count_archives((bool)(verbosity & VERBOSE_DEBUG));
+ return c;
}
int Depot::iterate_archives(ArchiveIteratorFunc func, void* context) {
int res = 0;
- size_t count = 0;
+ uint32_t count = 0;
Archive** list = this->get_all_archives(&count);
- for (size_t i = 0; i < count; i++) {
+ for (uint32_t i = 0; i < count; i++) {
if (list[i]) {
res = func(list[i], context);
delete list[i];
@@ -376,53 +286,24 @@
}
int Depot::iterate_files(Archive* archive, FileIteratorFunc func, void* context) {
- int res = 0;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT serial, info, path, mode, uid, gid, size, digest FROM files WHERE archive=? ORDER BY path";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- res = sqlite3_bind_int64(stmt, 1, archive->serial());
- while (res == 0) {
- res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- res = 0;
- int i = 0;
- uint64_t serial = sqlite3_column_int64(stmt, i++);
- uint32_t info = sqlite3_column_int(stmt, i++);
- const unsigned char* path = sqlite3_column_text(stmt, i++);
- mode_t mode = sqlite3_column_int(stmt, i++);
- uid_t uid = sqlite3_column_int(stmt, i++);
- gid_t gid = sqlite3_column_int(stmt, i++);
- off_t size = sqlite3_column_int64(stmt, i++);
- const void* blob = sqlite3_column_blob(stmt, i);
- int blobsize = sqlite3_column_bytes(stmt, i++);
-
- Digest* digest = NULL;
- if (blobsize > 0) {
- digest = new Digest();
- digest->m_size = blobsize;
- memcpy(digest->m_data, blob, ((size_t)blobsize < sizeof(digest->m_data)) ? blobsize : sizeof(digest->m_data));
- }
-
- File* file = FileFactory(serial, archive, info, (const char*)path, mode, uid, gid, size, digest);
- if (file) {
- res = func(file, context);
- delete file;
- } else {
- fprintf(stderr, "%s:%d: FileFactory returned NULL\n", __FILE__, __LINE__);
- res = -1;
- break;
- }
- } else if (res == SQLITE_DONE) {
- res = 0;
+ int res = DB_OK;
+ uint8_t** filelist;
+ uint32_t count;
+ res = this->m_db->get_files(&filelist, &count, archive);
+ if (FOUND(res)) {
+ for (uint32_t i=0; i < count; i++) {
+ File* file = this->m_db->make_file(filelist[i]);
+ if (file) {
+ res = func(file, context);
+ delete file;
+ } else {
+ fprintf(stderr, "%s:%d: DB::make_file returned NULL\n", __FILE__, __LINE__);
+ res = -1;
break;
}
}
- sqlite3_reset(stmt);
}
+
return res;
}
@@ -480,7 +361,7 @@
uint32_t actual_flags = File::compare(file, actual);
uint32_t preceding_flags = File::compare(actual, preceding);
-
+
// If file == actual && actual == preceding then nothing needs to be done.
if (actual_flags == FILE_INFO_IDENTICAL && preceding_flags == FILE_INFO_IDENTICAL) {
state = ' ';
@@ -550,20 +431,19 @@
if ((state != ' ' && preceding_flags != FILE_INFO_IDENTICAL) ||
INFO_TEST(actual->info(), FILE_INFO_BASE_SYSTEM | FILE_INFO_ROLLBACK_DATA)) {
*rollback_files += 1;
- IF_DEBUG("[analyze] insert rollback\n");
- res = this->insert(rollback, actual);
+ if (!this->has_file(rollback, actual)) {
+ IF_DEBUG("[analyze] insert rollback\n");
+ res = this->insert(rollback, actual);
+ }
assert(res == 0);
+
// need to save parent directories as well
- char *ppath;
- char *pathbuf;
- pathbuf = strdup(actual->path());
- ppath = dirname(pathbuf);
- free(pathbuf);
+ FTSENT *pent = ent->fts_parent;
+
// while we have a valid path that is below the prefix
- while (ppath
- && strncmp(ppath, this->prefix(), strlen(this->prefix())) == 0
- && strncmp(ppath, this->prefix(), strlen(ppath)) > 0) {
- File* parent = FileFactory(ppath);
+ while (pent && pent->fts_level >= 0) {
+ File* parent = FileFactory(rollback, pent);
+
// if parent dir does not exist, we are
// generating a rollback of base system
// which does not have matching directories,
@@ -572,10 +452,13 @@
IF_DEBUG("[analyze] parent path not found, skipping parents\n");
break;
}
- IF_DEBUG("[analyze] adding parent to rollback: %s \n", parent->path());
- res = this->insert(rollback, parent);
+
+ if (!this->has_file(rollback, parent)) {
+ IF_DEBUG("[analyze] adding parent to rollback: %s \n", parent->path());
+ res = this->insert(rollback, parent);
+ }
assert(res == 0);
- ppath = dirname(ppath);
+ pent = pent->fts_parent;
}
}
@@ -718,11 +601,6 @@
assert(rollback != NULL);
assert(archive != NULL);
- // Check the consistency of the database before proceeding with the installation
- // If this fails, abort the installation.
- // res = this->check_consistency();
- // if (res != 0) return res;
-
res = this->lock(LOCK_EX);
if (res != 0) return res;
@@ -791,14 +669,19 @@
// Installation is complete. Activate the archive in the database.
if (res == 0) res = this->begin_transaction();
- if (res == 0) res = SQL("UPDATE archives SET active=1 WHERE serial=%lld;", rollback->serial());
- if (res == 0) res = SQL("UPDATE archives SET active=1 WHERE serial=%lld;", archive->serial());
+ if (res == 0) {
+ res = this->m_db->activate_archive(rollback->serial());
+ if (res) this->rollback_transaction();
+ }
+ if (res == 0) {
+ res = this->m_db->activate_archive(archive->serial());
+ if (res) this->rollback_transaction();
+ }
if (res == 0) res = this->commit_transaction();
// Remove the stage and rollback directories (save disk space)
remove_directory(archive_path);
remove_directory(rollback_path);
-
free(rollback_path);
free(archive_path);
@@ -820,7 +703,6 @@
if (ent->fts_info == FTS_D) {
char path[PATH_MAX];
snprintf(path, PATH_MAX, "%s/%s", m_archives_path, ent->fts_name);
- IF_DEBUG("pruning: %s\n", path);
res = remove_directory(path);
}
ent = ent->fts_link;
@@ -831,21 +713,7 @@
int Depot::prune_archives() {
int res = 0;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "DELETE FROM archives WHERE serial IN (SELECT serial FROM archives WHERE serial NOT IN (SELECT DISTINCT archive FROM files));";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_DONE) {
- res = 0;
- } else {
- fprintf(stderr, "%s:%d: Could not prune archives in database: %s (%d)\n", __FILE__, __LINE__, sqlite3_errmsg(m_db), res);
- }
- sqlite3_reset(stmt);
- }
+ res = this->m_db->delete_empty_archives();
return res;
}
@@ -934,9 +802,6 @@
return -1;
}
-// res = this->check_consistency();
-// if (res != 0) return res;
-
res = this->lock(LOCK_EX);
if (res != 0) return res;
@@ -946,7 +811,7 @@
// We do this here to get an exclusive lock on the database.
if (res == 0) res = this->begin_transaction();
- if (res == 0) res = SQL("UPDATE archives SET active=0 WHERE serial=%lld;", serial);
+ if (res == 0) res = m_db->deactivate_archive(serial);
if (res == 0) res = this->commit_transaction();
InstallContext context(this, archive);
@@ -956,8 +821,7 @@
uint32_t i;
for (i = 0; i < context.files_to_remove->count; ++i) {
uint64_t serial = context.files_to_remove->values[i];
- IF_DEBUG("deleting file %lld\n", serial);
- if (res == 0) res = SQL("DELETE FROM files WHERE serial=%lld;", serial);
+ if (res == 0) res = m_db->delete_file(serial);
}
if (res == 0) res = this->commit_transaction();
@@ -1067,79 +931,18 @@
}
-File* Depot::file_star_eded_by(File* file, sqlite3_stmt* stmt) {
- assert(file != NULL);
- assert(file->archive() != NULL);
-
- File* result = NULL;
- uint64_t serial = 0;
- int res = 0;
- if (stmt && res == 0) {
- if (res == 0) res = sqlite3_bind_int64(stmt, 1, file->archive()->serial());
- if (res == 0) res = sqlite3_bind_text(stmt, 2, file->path(), -1, SQLITE_STATIC);
- if (res == 0) res = sqlite3_step(stmt);
- switch (res) {
- case SQLITE_DONE:
- serial = 0;
- break;
- case SQLITE_ROW:
- {
- int i = 0;
- uint64_t serial = sqlite3_column_int64(stmt, i++);
- uint64_t archive_serial = sqlite3_column_int64(stmt, i++);
- uint32_t info = sqlite3_column_int(stmt, i++);
- const unsigned char* path = sqlite3_column_text(stmt, i++);
- mode_t mode = sqlite3_column_int(stmt, i++);
- uid_t uid = sqlite3_column_int(stmt, i++);
- gid_t gid = sqlite3_column_int(stmt, i++);
- off_t size = sqlite3_column_int64(stmt, i++);
- const void* blob = sqlite3_column_blob(stmt, i);
- int blobsize = sqlite3_column_bytes(stmt, i++);
-
- Digest* digest = NULL;
- if (blobsize > 0) {
- digest = new Digest();
- digest->m_size = blobsize;
- memcpy(digest->m_data, blob, ((size_t)blobsize < sizeof(digest->m_data)) ? blobsize : sizeof(digest->m_data));
- }
-
- Archive* archive = this->archive(archive_serial);
-
- result = FileFactory(serial, archive, info, (const char*)path, mode, uid, gid, size, digest);
- }
- break;
- default:
- fprintf(stderr, "%s:%d: unexpected SQL error: %d\n", __FILE__, __LINE__, res);
- break;
- }
- sqlite3_reset(stmt);
- } else {
- fprintf(stderr, "%s:%d: unexpected SQL error: %d\n", __FILE__, __LINE__, res);
- }
-
- return result;
-}
-
File* Depot::file_superseded_by(File* file) {
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- // archive which installed this file immediately after
- const char* query = "SELECT serial, archive, info, path, mode, uid, gid, size, digest FROM files WHERE archive>? AND path=? ORDER BY archive ASC LIMIT 1";
- int res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- return this->file_star_eded_by(file, stmt);
+ uint8_t* data;
+ int res = this->m_db->get_next_file(&data, file, FILE_SUPERSEDED);
+ if (FOUND(res)) return this->m_db->make_file(data);
+ return NULL;
}
File* Depot::file_preceded_by(File* file) {
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- // archive which installed this file immediately before
- const char* query = "SELECT serial, archive, info, path, mode, uid, gid, size, digest FROM files WHERE archive<? AND path=? ORDER BY archive DESC LIMIT 1";
- int res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- return this->file_star_eded_by(file, stmt);
+ uint8_t* data;
+ int res = this->m_db->get_next_file(&data, file, FILE_PRECEDED);
+ if (FOUND(res)) return this->m_db->make_file(data);
+ return NULL;
}
int Depot::check_consistency() {
@@ -1148,34 +951,22 @@
SerialSet* inactive = new SerialSet();
assert(inactive != NULL);
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT serial FROM archives WHERE active=0 ORDER BY serial DESC";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
+ // get inactive archives serials from the database
+ uint64_t* serials;
+ uint32_t count;
+ this->m_db->get_inactive_archive_serials(&serials, &count);
+ for (uint32_t i=0; i < count; i++) {
+ inactive->add(serials[i]);
}
- if (stmt && res == 0) {
- while (res == 0) {
- res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- res = 0;
- uint64_t serial = sqlite3_column_int64(stmt, 0);
- inactive->add(serial);
- } else if (res == SQLITE_DONE) {
- res = 0;
- break;
- } else {
- fprintf(stderr, "%s:%d: unexpected SQL error: %d\n", __FILE__, __LINE__, res);
- }
- }
- sqlite3_reset(stmt);
- }
+ free(serials);
+ // print a list of inactive archives
if (res == 0 && inactive && inactive->count > 0) {
- fprintf(stderr, "The following archive%s in an inconsistent state and must be uninstalled before proceeding:\n\n", inactive->count > 1 ? "s are" : " is");
+ fprintf(stderr, "The following archive%s in an inconsistent state and must be uninstalled "
+ "before proceeding:\n\n", inactive->count > 1 ? "s are" : " is");
uint32_t i;
- fprintf(stderr, "%-36s %-23s %s\n", "UUID", "Date Installed", "Name");
- fprintf(stderr, "==================================== ======================= =================\n");
+ fprintf(stderr, "%-6s %-36s %-23s %s\n", "Serial", "UUID", "Date Installed", "Name");
+ fprintf(stderr, "====== ==================================== ======================= =================\n");
for (i = 0; i < inactive->count; ++i) {
Archive* archive = this->archive(inactive->values[i]);
if (archive) {
@@ -1203,15 +994,15 @@
int Depot::begin_transaction() {
- return this->SQL("BEGIN TRANSACTION");
+ return this->m_db->begin_transaction();
}
int Depot::rollback_transaction() {
- return this->SQL("ROLLBACK TRANSACTION");
+ return this->m_db->rollback_transaction();
}
int Depot::commit_transaction() {
- return this->SQL("COMMIT TRANSACTION");
+ return this->m_db->commit_transaction();
}
int Depot::is_locked() { return m_is_locked; }
@@ -1247,35 +1038,14 @@
int Depot::insert(Archive* archive) {
// Don't insert an archive that is already in the database
assert(archive->serial() == 0);
-
- int res = 0;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "INSERT INTO archives (uuid, info, name, date_added) VALUES (?, ?, ?, ?)";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- int i = 1;
- if (res == 0) res = sqlite3_bind_blob(stmt, i++, archive->uuid(), sizeof(uuid_t), SQLITE_STATIC);
- if (res == 0) res = sqlite3_bind_int(stmt, i++, archive->info());
- if (res == 0) res = sqlite3_bind_text(stmt, i++, archive->name(), -1, SQLITE_STATIC);
- if (res == 0) res = sqlite3_bind_int(stmt, i++, archive->date_installed());
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_DONE) {
- archive->m_serial = (uint64_t)sqlite3_last_insert_rowid(m_db);
- res = 0;
- } else {
- fprintf(stderr, "%s:%d: Could not add archive to database: %s (%d)\n", __FILE__, __LINE__, sqlite3_errmsg(m_db), res);
- }
- sqlite3_reset(stmt);
- }
- return res;
+ archive->m_serial = m_db->insert_archive(archive->uuid(),
+ archive->info(),
+ archive->name(),
+ archive->date_installed());
+ return archive->m_serial == 0;
}
int Depot::insert(Archive* archive, File* file) {
- int res = 0;
- int do_update = 0;
// check for the destination prefix in file's path, remove if found
char *path, *relpath;
size_t prefixlen = strlen(this->prefix());
@@ -1285,49 +1055,19 @@
relpath += prefixlen - 1;
}
- const char* query = NULL;
- if (this->has_file(archive, file)) {
- do_update = 1;
- IF_DEBUG("archive(%llu) already has %s, updating instead \n", archive->serial(), relpath);
- query = "UPDATE files SET info=?, mode=?, uid=?, gid=?, digest=? WHERE archive=? and path=?";
- } else {
- query = "INSERT INTO files (info, mode, uid, gid, digest, archive, path) VALUES (?, ?, ?, ?, ?, ?, ?)";
+ file->m_serial = m_db->insert_file(file->info(), file->mode(), file->uid(), file->gid(),
+ file->digest(), archive, relpath);
+ if (!file->m_serial) {
+ fprintf(stderr, "Error: unable to insert file at path %s for archive %s \n",
+ relpath, archive->name());
+ return DB_ERROR;
}
- sqlite3_stmt* stmt = NULL;
- if (m_db) {
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- int i = 1;
- if (res == 0) res = sqlite3_bind_int(stmt, i++, file->info());
- if (res == 0) res = sqlite3_bind_int(stmt, i++, file->mode());
- if (res == 0) res = sqlite3_bind_int(stmt, i++, file->uid());
- if (res == 0) res = sqlite3_bind_int(stmt, i++, file->gid());
- Digest* dig = file->digest();
- if (res == 0 && dig) res = sqlite3_bind_blob(stmt, i++, dig->data(), dig->size(), SQLITE_STATIC);
- else if (res == 0) res = sqlite3_bind_blob(stmt, i++, NULL, 0, SQLITE_STATIC);
- if (res == 0) res = sqlite3_bind_int64(stmt, i++, archive->serial());
- if (res == 0) res = sqlite3_bind_text(stmt, i++, relpath, -1, SQLITE_STATIC);
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_DONE) {
- // if we did an insert, update the file serial
- if (!do_update) {
- file->m_serial = (uint64_t)sqlite3_last_insert_rowid(m_db);
- }
- res = 0;
- } else {
- fprintf(stderr, "%s:%d: Could not add file to database: %s (%d)\n", __FILE__, __LINE__, sqlite3_errmsg(m_db), res);
- }
- sqlite3_reset(stmt);
- }
+
free(path);
- return res;
+ return 0;
}
int Depot::has_file(Archive* archive, File* file) {
- int res = 0;
- size_t count = 0;
// check for the destination prefix in file's path, remove if found
char *path, *relpath;
size_t prefixlen = strlen(this->prefix());
@@ -1336,44 +1076,31 @@
if (strncmp(file->path(), this->prefix(), prefixlen) == 0) {
relpath += prefixlen - 1;
}
-
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "SELECT count(*) FROM files WHERE archive=? and path=?";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- int i = 1;
- if (res == 0) res = sqlite3_bind_int64(stmt, i++, archive->serial());
- if (res == 0) res = sqlite3_bind_text(stmt, i++, relpath, -1, SQLITE_STATIC);
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_ROW) {
- count = sqlite3_column_int64(stmt, 0);
- IF_DEBUG("has_file(%llu, %s) got count = %u \n", archive->serial(), relpath, (unsigned int)count);
- } else {
- res = -1;
- fprintf(stderr, "%s:%d: Could not query for file in archive: %s (%d)\n", __FILE__, __LINE__, sqlite3_errmsg(m_db), res);
- }
- sqlite3_reset(stmt);
- }
+
+ uint64_t count = m_db->count_files(archive, relpath);
+
free(path);
return count > 0;
}
+
int Depot::remove(Archive* archive) {
int res = 0;
- uint64_t serial = archive->serial();
- if (res == 0) res = SQL("DELETE FROM files WHERE archive=%lld", serial);
- if (res == 0) res = SQL("DELETE FROM archives WHERE serial=%lld", serial);
+ res = m_db->delete_files(archive);
+ if (res) {
+ fprintf(stderr, "Error: unable to delete files for archive %llu \n", archive->serial());
+ return res;
+ }
+ res = m_db->delete_archive(archive);
+ if (res) {
+ fprintf(stderr, "Error: unable to delete archive %llu \n", archive->serial());
+ return res;
+ }
return res;
}
int Depot::remove(File* file) {
- int res = 0;
- uint64_t serial = file->serial();
- if (res == 0) res = SQL("DELETE FROM files WHERE serial=%lld", serial);
- return res;
+ return m_db->delete_file(file);
}
// helper to dispatch the actual command for process_archive()
@@ -1399,7 +1126,7 @@
int Depot::process_archive(const char* command, const char* arg) {
extern uint32_t verbosity;
int res = 0;
- size_t count = 0;
+ uint32_t count = 0;
Archive** list = NULL;
if (strncasecmp(arg, "all", 3) == 0) {
@@ -1427,29 +1154,3 @@
free(list);
return res;
}
-
-
-#define __SQL(callback, context, fmt) \
- va_list args; \
- char* errmsg; \
- va_start(args, fmt); \
- if (this->m_db) { \
- char *query = sqlite3_vmprintf(fmt, args); \
- res = sqlite3_exec(this->m_db, query, callback, context, &errmsg); \
- if (res != SQLITE_OK) { \
- fprintf(stderr, "Error: %s (%d)\n SQL: %s\n", errmsg, res, query); \
- } \
- sqlite3_free(query); \
- } else { \
- fprintf(stderr, "Error: database not open.\n"); \
- res = SQLITE_ERROR; \
- } \
- va_end(args);
-
-int Depot::SQL(const char* fmt, ...) {
- int res;
- __SQL(NULL, NULL, fmt);
- return res;
-}
-
-#undef __SQL
Modified: trunk/darwinup/Depot.h
===================================================================
--- trunk/darwinup/Depot.h 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Depot.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -30,30 +30,36 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
+#ifndef _DEPOT_H
+#define _DEPOT_H
+
#include <sys/types.h>
#include <uuid/uuid.h>
-#include <sqlite3.h>
+#include "DB.h"
+#include "Archive.h"
struct Archive;
struct File;
+struct DarwinupDatabase;
typedef int (*ArchiveIteratorFunc)(Archive* archive, void* context);
typedef int (*FileIteratorFunc)(File* file, void* context);
-typedef char* archive_name_t;
-
-enum archive_keyword_t {
- DEPOT_ARCHIVE_NEWEST,
- DEPOT_ARCHIVE_OLDEST
-};
-
struct Depot {
Depot();
Depot(const char* prefix);
virtual ~Depot();
- int initialize();
+ // establish database connection
+ int connect();
+
+ // create directories we need for storage
+ int create_storage();
+
+ // use initialize() to connect to database
+ // and (optionally) create the storage directories
+ int initialize(bool writable);
int is_initialized();
const char* prefix();
@@ -69,12 +75,11 @@
Archive* archive(uuid_t uuid);
Archive* archive(archive_name_t name);
Archive* archive(archive_keyword_t keyword);
- Archive* archive(sqlite3_stmt* stmt);
Archive* get_archive(const char* arg);
// returns a list of Archive*. Caller must free the list.
- Archive** get_all_archives(size_t *count);
- size_t count_archives();
+ Archive** get_all_archives(uint32_t *count);
+ uint64_t count_archives();
int dump();
static int dump_archive(Archive* archive, void* context);
@@ -107,30 +112,31 @@
// test if the depot is currently locked
int is_locked();
- protected:
+protected:
+
// Serialize access to the Depot via flock(2).
- int lock(int operation);
- int unlock(void);
+ int lock(int operation);
+ int unlock(void);
// Inserts an Archive into the database.
// This modifies the Archive's serial number.
// If the Archive already has a serial number, it cannot be inserted.
- int insert(Archive* archive);
+ int insert(Archive* archive);
// Inserts a File into the database, as part of the specified Archive.
// This modifies the File's serial number.
// This modifies the File's Archive pointer.
// If the File already has a serial number, it cannot be inserted.
- int insert(Archive* archive, File* file);
-
- int has_file(Archive* archive, File* file);
+ int insert(Archive* archive, File* file);
+ int has_file(Archive* archive, File* file);
+
// Removes an Archive from the database.
- int remove(Archive* archive);
+ int remove(Archive* archive);
// Removes a File from the database.
- int remove(File* file);
+ int remove(File* file);
int analyze_stage(const char* path, Archive* archive, Archive* rollback, int* rollback_files);
int prune_directories();
@@ -138,22 +144,21 @@
// Removes all archive entries which have no corresponding files entries.
int prune_archives();
- File* file_superseded_by(File* file);
- File* file_preceded_by(File* file);
- File* file_star_eded_by(File* file, sqlite3_stmt* stmt);
+ File* file_superseded_by(File* file);
+ File* file_preceded_by(File* file);
int check_consistency();
-
- virtual int SQL(const char* fmt, ...);
-
- sqlite3* m_db;
+ DarwinupDatabase* m_db;
+
mode_t m_depot_mode;
- char* m_prefix;
+ char* m_prefix;
char* m_depot_path;
char* m_database_path;
char* m_archives_path;
char* m_downloads_path;
- int m_lock_fd;
- int m_is_locked;
+ int m_lock_fd;
+ int m_is_locked;
};
+
+#endif
Modified: trunk/darwinup/Digest.cpp
===================================================================
--- trunk/darwinup/Digest.cpp 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Digest.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
Modified: trunk/darwinup/Digest.h
===================================================================
--- trunk/darwinup/Digest.h 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Digest.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -30,10 +30,15 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
+#ifndef _DIGEST_H
+#define _DIGEST_H
+
#include <sys/types.h>
#include <stdint.h>
#include <openssl/evp.h>
+#include "Utils.h"
+
////
// Digest
//
@@ -90,6 +95,7 @@
uint32_t m_size;
friend struct Depot;
+ friend struct DarwinupDatabase;
};
////
@@ -132,3 +138,6 @@
// The target is obtained via readlink(2).
SHA1DigestSymlink(const char* filename);
};
+
+#endif
+
Modified: trunk/darwinup/File.cpp
===================================================================
--- trunk/darwinup/File.cpp 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/File.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
Modified: trunk/darwinup/File.h
===================================================================
--- trunk/darwinup/File.h 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/File.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -30,12 +30,20 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
+#ifndef _FILE_H
+#define _FILE_H
+
#include "Digest.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
+enum file_starseded_t {
+ FILE_SUPERSEDED,
+ FILE_PRECEDED
+};
+
//
// FILE_INFO flags stored in the database
//
@@ -214,3 +222,5 @@
virtual int install(const char* prefix, const char* dest);
virtual int remove();
};
+
+#endif
Modified: trunk/darwinup/SerialSet.cpp
===================================================================
--- trunk/darwinup/SerialSet.cpp 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/SerialSet.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
Modified: trunk/darwinup/SerialSet.h
===================================================================
--- trunk/darwinup/SerialSet.h 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/SerialSet.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -30,6 +30,9 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
+#ifndef _SERIALSET_H
+#define _SERIALSET_H
+
#include <stdint.h>
#include <sys/types.h>
@@ -44,3 +47,5 @@
uint32_t count;
uint64_t* values;
};
+
+#endif
Copied: trunk/darwinup/Table.cpp (from rev 731, branches/PR-7489777/darwinup/Table.cpp)
===================================================================
--- trunk/darwinup/Table.cpp (rev 0)
+++ trunk/darwinup/Table.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "Table.h"
+#include "Database.h"
+
+
+Table::Table(const char* name) {
+ m_column_max = 2;
+ m_column_count = 0;
+ m_columns = (Column**)malloc(sizeof(Column*) * m_column_max);
+ m_columns_size = 0;
+ m_result_max = 1;
+ m_result_count = 0;
+ m_results = (uint8_t**)malloc(sizeof(uint8_t*) * m_result_max);
+ m_name = strdup(name);
+ m_create_sql = NULL;
+ m_custom_create_sql = NULL;
+ m_insert_sql = NULL;
+ m_update_sql = NULL;
+ m_delete_sql = NULL;
+ m_prepared_insert = NULL;
+ m_prepared_update = NULL;
+ m_prepared_delete = NULL;
+}
+
+Table::~Table() {
+ for (uint32_t i = 0; i < m_column_count; i++) {
+ delete m_columns[i];
+ }
+ free(m_columns);
+
+
+ for (uint32_t i=0; i < m_result_count; i++) {
+ if (m_results[i]) {
+ this->free_result(m_results[i]);
+ }
+ }
+ free(m_results);
+
+ free(m_name);
+
+ free(m_create_sql);
+ free(m_custom_create_sql);
+ free(m_insert_sql);
+ free(m_update_sql);
+ free(m_delete_sql);
+
+ sqlite3_finalize(m_prepared_insert);
+ sqlite3_finalize(m_prepared_update);
+ sqlite3_finalize(m_prepared_delete);
+
+}
+
+const char* Table::name() {
+ return m_name;
+}
+
+int Table::set_custom_create(const char* sql) {
+ this->m_custom_create_sql = strdup(sql);
+ return this->m_custom_create_sql == 0;
+}
+
+int Table::add_column(Column* c) {
+ // accumulate offsets for columns in m_columns_size
+ c->m_offset = this->m_columns_size;
+ this->m_columns_size += c->size();
+
+ // reallocate if needed
+ if (m_column_count >= m_column_max) {
+ m_columns = (Column**)realloc(m_columns, m_column_max * sizeof(Column*) * REALLOC_FACTOR);
+ if (!m_columns) {
+ fprintf(stderr, "Error: unable to reallocate memory to add a column\n");
+ return 1;
+ }
+ m_column_max *= REALLOC_FACTOR;
+ }
+ m_columns[m_column_count++] = c;
+
+ return 0;
+}
+
+Column* Table::column(uint32_t index) {
+ if (index < m_column_count) {
+ return this->m_columns[index];
+ } else {
+ return NULL;
+ }
+}
+
+int Table::offset(uint32_t index) {
+ return this->m_columns[index]->offset();
+}
+
+uint32_t Table::row_size() {
+ return m_columns_size;
+}
+
+uint8_t* Table::alloc_result() {
+ if (m_result_count >= m_result_max) {
+ m_results = (uint8_t**)realloc(m_results, m_result_max * sizeof(uint8_t*) * REALLOC_FACTOR);
+ if (!m_results) {
+ fprintf(stderr, "Error: unable to reallocate memory to add a result row\n");
+ return NULL;
+ }
+ m_result_max *= REALLOC_FACTOR;
+ }
+ m_result_count++;
+ m_results[m_result_count-1] = (uint8_t*)calloc(1, this->row_size());
+ return m_results[m_result_count-1];
+}
+
+int Table::free_result(uint8_t* result) {
+ for (uint32_t i=0; i < m_result_count; i++) {
+ // look for matching result
+ if (result == m_results[i]) {
+ this->free_row((uint8_t*)m_results[i]);
+ free(m_results[i]);
+ m_results[i] = NULL;
+ // if we did not free the last result,
+ // move last result to the empty slot
+ if (i != (m_result_count - 1)) {
+ m_results[i] = m_results[m_result_count-1];
+ m_results[m_result_count-1] = NULL;
+ }
+ m_result_count--;
+ }
+ }
+ return 0;
+}
+
+sqlite3_stmt* Table::count(sqlite3* db) {
+ sqlite3_stmt* stmt = (sqlite3_stmt*)malloc(sizeof(sqlite3_stmt*));
+ char* query;
+ int size = asprintf(&query, "SELECT count(*) FROM %s ;", m_name) + 1;
+ int res = sqlite3_prepare_v2(db, query, size, &stmt, NULL); \
+ free(query); \
+ if (res != SQLITE_OK) { \
+ fprintf(stderr, "Error: unable to prepare statement: %s\n", \
+ sqlite3_errmsg(db)); \
+ return NULL; \
+ }
+ return stmt;
+}
+
+/**
+ * Prepare and cache the update statement.
+ * Assumes table only has 1 primary key
+ */
+sqlite3_stmt* Table::update(sqlite3* db) {
+ // we only need to prepare once, return if we already have it
+ if (m_prepared_update) {
+ return m_prepared_update;
+ }
+ uint32_t i = 0;
+ bool comma = false; // flag we set to start adding commas
+
+ // calculate the length of the sql statement
+ size_t size = 27 + 5*m_column_count;
+ for (i=0; i<m_column_count; i++) {
+ size += strlen(m_columns[i]->name());
+ }
+
+ // generate the sql query
+ m_update_sql = (char*)malloc(size);
+ strlcpy(m_update_sql, "UPDATE ", size);
+ strlcat(m_update_sql, m_name, size);
+ strlcat(m_update_sql, " SET ", size);
+ for (i=0; i<m_column_count; i++) {
+ // comma separate after 0th column
+ if (comma) strlcat(m_update_sql, ", ", size);
+ // primary keys do not get inserted
+ if (!m_columns[i]->is_pk()) {
+ strlcat(m_update_sql, m_columns[i]->name(), size);
+ strlcat(m_update_sql, "=?", size);
+ comma = true;
+ }
+ }
+
+ // WHERE statement using primary keys
+ strlcat(m_update_sql, " WHERE ", size);
+ for (i=0; i<m_column_count; i++) {
+ if (m_columns[i]->is_pk()) {
+ strlcat(m_update_sql, m_columns[i]->name(), size);
+ strlcat(m_update_sql, "=?", size);
+ break;
+ }
+ }
+ strlcat(m_update_sql, ";", size);
+
+ // prepare
+ int res = sqlite3_prepare_v2(db, m_update_sql, strlen(m_update_sql), &m_prepared_update, NULL);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to prepare update statement for table: %s \n", m_name);
+ return NULL;
+ }
+ return m_prepared_update;
+}
+
+
+sqlite3_stmt* Table::insert(sqlite3* db) {
+ // we only need to prepare once, return if we already have it
+ if (m_prepared_insert) {
+ return m_prepared_insert;
+ }
+
+ uint32_t i = 0;
+ bool comma = false; // flag we set to start adding commas
+
+ // calculate the length of the sql statement
+ size_t size = 27 + 5*m_column_count;
+ for (i=0; i<m_column_count; i++) {
+ size += strlen(m_columns[i]->name());
+ }
+
+ // generate the sql query
+ m_insert_sql = (char*)malloc(size);
+ strlcpy(m_insert_sql, "INSERT INTO ", size);
+ strlcat(m_insert_sql, m_name, size);
+ strlcat(m_insert_sql, " (", size);
+ for (i=0; i<m_column_count; i++) {
+ // comma separate after 0th column
+ if (comma) strlcat(m_insert_sql, ", ", size);
+ // primary keys do not get inserted
+ if (!m_columns[i]->is_pk()) {
+ strlcat(m_insert_sql, m_columns[i]->name(), size);
+ comma = true;
+ }
+ }
+ comma = false;
+ strlcat(m_insert_sql, ") VALUES (", size);
+ for (i=0; i<m_column_count; i++) {
+ // comma separate after 0th column
+ if (comma) strlcat(m_insert_sql, ", ", size);
+ // primary keys do not get inserted
+ if (!m_columns[i]->is_pk()) {
+ strlcat(m_insert_sql, "?", size);
+ comma = true;
+ }
+ }
+ strlcat(m_insert_sql, ");", size);
+
+ // prepare
+ int res = sqlite3_prepare_v2(db, m_insert_sql, strlen(m_insert_sql), &m_prepared_insert, NULL);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to prepare insert statement for table: %s \n", m_name);
+ return NULL;
+ }
+ return m_prepared_insert;
+}
+
+sqlite3_stmt* Table::del(sqlite3* db) {
+ // we only need to prepare once, return if we already have it
+ if (m_prepared_delete) return m_prepared_delete;
+
+ uint32_t i = 0;
+
+ // generate the sql query
+ size_t size = 22 + strlen(m_name);
+ for (i=0; i<m_column_count; i++) {
+ if (m_columns[i]->is_pk()) {
+ size += strlen(m_columns[i]->name()) + 2;
+ break;
+ }
+ }
+ m_delete_sql = (char*)malloc(size);
+ strlcpy(m_delete_sql, "DELETE FROM ", size);
+ strlcat(m_delete_sql, m_name, size);
+
+ // WHERE statement using primary keys
+ strlcat(m_delete_sql, " WHERE ", size);
+ for (i=0; i<m_column_count; i++) {
+ if (m_columns[i]->is_pk()) {
+ strlcat(m_delete_sql, m_columns[i]->name(), size);
+ strlcat(m_delete_sql, "=?", size);
+ break;
+ }
+ }
+ strlcat(m_delete_sql, ";", size);
+
+ // prepare
+ int res = sqlite3_prepare_v2(db, m_delete_sql, strlen(m_delete_sql), &m_prepared_delete, NULL);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to prepare delete statement for table: %s \n", m_name);
+ return NULL;
+ }
+ return m_prepared_delete;
+
+}
+
+#define __alloc_stmt_query \
+ size_t size = 256; \
+ size_t used = 0; \
+ char* query = (char*)malloc(size); \
+ sqlite3_stmt** pps = (sqlite3_stmt**)malloc(sizeof(sqlite3_stmt*));
+
+#define __check_and_cat(text) \
+ used = strlcat(query, text, size); \
+ if (used >= size-1) { \
+ size *= 4; \
+ query = (char*)realloc(query, size); \
+ if (!query) { \
+ fprintf(stderr, "Error: ran out of memory!\n"); \
+ return NULL; \
+ } \
+ used = strlcat(query, text, size); \
+ }
+
+#define __prepare_stmt \
+ int res = sqlite3_prepare_v2(db, query, size, pps, NULL); \
+ free(query); \
+ if (res != SQLITE_OK) { \
+ fprintf(stderr, "Error: unable to prepare statement: %s\n", \
+ sqlite3_errmsg(db)); \
+ return NULL; \
+ }
+
+sqlite3_stmt** Table::count(sqlite3* db, uint32_t count, va_list args) {
+ __alloc_stmt_query;
+ strlcpy(query, "SELECT count(*) FROM ", size);
+ __check_and_cat(m_name);
+ __check_and_cat(" WHERE 1");
+ this->where_va_columns(count, query, size, &used, args);
+ strlcat(query, ";", size);
+ __prepare_stmt;
+
+ return pps;
+}
+
+sqlite3_stmt** Table::get_column(sqlite3* db, Column* value_column, uint32_t count, va_list args) {
+ __alloc_stmt_query;
+ strlcpy(query, "SELECT ", size);
+ __check_and_cat(value_column->name());
+ __check_and_cat(" FROM ");
+ __check_and_cat(m_name);
+ __check_and_cat(" WHERE 1");
+ this->where_va_columns(count, query, size, &used, args);
+ strlcat(query, ";", size);
+ __prepare_stmt;
+
+ return pps;
+}
+
+sqlite3_stmt** Table::get_row(sqlite3* db, uint32_t count, va_list args) {
+ __alloc_stmt_query;
+ strlcpy(query, "SELECT * FROM ", size);
+ __check_and_cat(m_name);
+ __check_and_cat(" WHERE 1");
+ this->where_va_columns(count, query, size, &used, args);
+ strlcat(query, ";", size);
+ __prepare_stmt;
+
+ return pps;
+}
+
+sqlite3_stmt** Table::get_row_ordered(sqlite3* db, Column* order_by, int order,
+ uint32_t count, va_list args) {
+ __alloc_stmt_query;
+ strlcpy(query, "SELECT * FROM ", size);
+ __check_and_cat(m_name);
+ __check_and_cat(" WHERE 1");
+ this->where_va_columns(count, query, size, &used, args);
+ __check_and_cat(" ORDER BY ");
+ __check_and_cat(order_by->name());
+ __check_and_cat((order == ORDER_BY_DESC ? " DESC" : " ASC"));
+ strlcat(query, ";", size);
+ __prepare_stmt;
+
+ return pps;
+}
+
+sqlite3_stmt** Table::update_value(sqlite3* db, Column* value_column, uint32_t count, va_list args) {
+ __alloc_stmt_query;
+ strlcpy(query, "UPDATE ", size);
+ __check_and_cat(m_name);
+ __check_and_cat(" SET ");
+ __check_and_cat(value_column->name());
+ __check_and_cat("=? WHERE 1");
+ this->where_va_columns(count, query, size, &used, args);
+ strlcat(query, ";", size);
+ __prepare_stmt;
+
+ return pps;
+}
+
+sqlite3_stmt** Table::del(sqlite3* db, uint32_t count, va_list args) {
+ __alloc_stmt_query;
+ strlcpy(query, "DELETE FROM ", size);
+ __check_and_cat(m_name);
+ __check_and_cat(" WHERE 1");
+ this->where_va_columns(count, query, size, &used, args);
+ strlcat(query, ";", size);
+ __prepare_stmt;
+
+ return pps;
+}
+
+const char* Table::create() {
+ size_t size = 0;
+ if (!m_create_sql) {
+ uint32_t i = 0;
+
+ // size of "create table ( );" plus table name, plus 1 for each column to separate
+ size = strlen(m_name) + 22 + m_column_count;
+ for (i=0; i<m_column_count; i++) {
+ // size for column spec
+ size += strlen(m_columns[i]->create());
+ // size for create index query
+ size += 26 + 2*strlen(m_columns[i]->name()) + 2*strlen(m_name);
+ // custom sql
+ if (m_custom_create_sql) size += strlen(m_custom_create_sql);
+ }
+
+ // create creation sql
+ m_create_sql = (char*)malloc(size);
+ strlcpy(m_create_sql, "CREATE TABLE ", size);
+ strlcat(m_create_sql, m_name, size);
+ strlcat(m_create_sql, " (", size);
+ // get creation sql for each column
+ for (i=0; i<m_column_count; i++) {
+ if (i) strlcat(m_create_sql, ", ", size); // comma separate after 0th column
+ strlcat(m_create_sql, m_columns[i]->create(), size);
+ }
+ strlcat(m_create_sql, "); ", size);
+
+ for (i=0; i<m_column_count; i++) {
+ if (m_columns[i]->is_index()) {
+ char* buf;
+ asprintf(&buf, "CREATE INDEX %s_%s ON %s (%s);",
+ m_name, m_columns[i]->name(), m_name, m_columns[i]->name());
+ strlcat(m_create_sql, buf, size);
+ free(buf);
+ }
+ }
+ if (m_custom_create_sql) strlcat(m_create_sql, m_custom_create_sql, size);
+ }
+
+ return (const char*)m_create_sql;
+}
+
+int Table::where_va_columns(uint32_t count, char* query, size_t size,
+ size_t* used, va_list args) {
+ char tmpstr[256];
+ char tmp_op = '=';
+ char op = '=';
+ char not_op = ' ';
+ int len;
+ for (uint32_t i=0; i < count; i++) {
+ Column* col = va_arg(args, Column*);
+ tmp_op = va_arg(args, int);
+ if (tmp_op == '!') {
+ not_op = tmp_op;
+ } else {
+ op = tmp_op;
+ }
+ va_arg(args, void*);
+ if (col->type() == SQLITE_BLOB) va_arg(args, uint32_t);
+ len = snprintf(tmpstr, 256, " AND %s%c%c?", col->name(), not_op, op);
+ if (len >= 255) {
+ fprintf(stderr, "Error: column name is too big (limit: 248): %s\n",
+ col->name());
+ return NULL;
+ }
+ *used = strlcat(query, tmpstr, size);
+ if (*used >= size-1) {
+ size *= 4;
+ query = (char*)realloc(query, size);
+ if (!query) {
+ fprintf(stderr, "Error: ran out of memory!\n");
+ return -1;
+ }
+ *used = strlcat(query, tmpstr, size);
+ }
+ }
+
+ return 0;
+}
+
+const Column** Table::columns() {
+ return (const Column**)m_columns;
+}
+
+uint32_t Table::column_count() {
+ return this->m_column_count;
+}
+
+int Table::free_row(uint8_t* row) {
+ uint8_t* current = row;
+ void* ptr;
+ for (uint32_t i=0; i < m_column_count; i++) {
+ switch (m_columns[i]->type()) {
+ case SQLITE_INTEGER:
+ current += sizeof(uint64_t);
+ // nothing to free
+ break;
+ default:
+ memcpy(&ptr, current, sizeof(void*));
+ free(ptr);
+ current += sizeof(void*);
+ }
+ }
+ return 0;
+}
+
+void Table::dump_results(FILE* f) {
+ fprintf(f, "====================================================================\n");
+ for (uint32_t i=0; i < m_result_count; i++) {
+ fprintf(f, "%p %u:\n", m_results[i], i);
+ __data_hex(f, m_results[i], 48);
+ }
+ fprintf(f, "====================================================================\n");
+}
Copied: trunk/darwinup/Table.h (from rev 731, branches/PR-7489777/darwinup/Table.h)
===================================================================
--- trunk/darwinup/Table.h (rev 0)
+++ trunk/darwinup/Table.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#ifndef _TABLE_H
+#define _TABLE_H
+
+#include <stdint.h>
+#include <sqlite3.h>
+
+#include "Column.h"
+
+
+struct Table {
+ Table(const char* name);
+ virtual ~Table();
+
+ const char* name();
+
+ // Add custom SQL to table initialization
+ int set_custom_create(const char* sql);
+
+ // Column handling
+ int add_column(Column*);
+ Column* column(uint32_t index);
+ // get the result record offset for column at index
+ int offset(uint32_t index);
+ // get total size of result record
+ uint32_t row_size();
+
+ // Result record handling
+ uint8_t* alloc_result();
+ int free_result(uint8_t* result);
+
+ /**
+ * sql statement generators (cached on Table)
+ */
+ sqlite3_stmt* count(sqlite3* db);
+ sqlite3_stmt* update(sqlite3* db);
+ sqlite3_stmt* insert(sqlite3* db);
+ sqlite3_stmt* del(sqlite3* db);
+
+ /**
+ * sql statement generators (cached by Database & libcache)
+ *
+ * - order is either ORDER_BY_ASC or ORDER_BY_DESC
+ * - count parameters should be the number of items in the va_list
+ * - args should have sets of 3 (integer and text) or 4 (blob)
+ * parameters for WHERE clause like Column*, char, value
+ * - Column* is the column to match against
+ * - char is how to compare, one of '=', '!', '>', or '<'
+ * - value is the value to match (1 for integer and text, 2 for blobs)
+ * which is ignored by these API since they leave placeholders
+ * instead
+ *
+ */
+ sqlite3_stmt** count(sqlite3* db, uint32_t count, va_list args);
+ sqlite3_stmt** get_column(sqlite3* db, Column* value_column,
+ uint32_t count, va_list args);
+ sqlite3_stmt** get_row(sqlite3* db, uint32_t count, va_list args);
+ sqlite3_stmt** get_row_ordered(sqlite3* db, Column* order_by, int order,
+ uint32_t count, va_list args);
+ sqlite3_stmt** update_value(sqlite3* db, Column* value_column,
+ uint32_t count, va_list args);
+ sqlite3_stmt** del(sqlite3* db, uint32_t count, va_list args);
+
+protected:
+
+ const char* create();
+
+ int where_va_columns(uint32_t count, char* query, size_t size,
+ size_t* used, va_list args);
+ const Column** columns();
+ uint32_t column_count();
+
+ // free the out-of-band columns (text, blob) from a result record
+ int free_row(uint8_t* row);
+ void dump_results(FILE* f);
+
+ char* m_name;
+
+ char* m_create_sql;
+ char* m_custom_create_sql;
+ char* m_insert_sql;
+ char* m_update_sql;
+ char* m_delete_sql;
+
+ Column** m_columns;
+ uint32_t m_column_count;
+ uint32_t m_column_max;
+ int m_columns_size;
+
+ sqlite3_stmt* m_prepared_insert;
+ sqlite3_stmt* m_prepared_update;
+ sqlite3_stmt* m_prepared_delete;
+
+ uint8_t** m_results;
+ uint32_t m_result_count;
+ uint32_t m_result_max;
+
+ friend struct Database;
+};
+
+#endif
Modified: trunk/darwinup/Utils.cpp
===================================================================
--- trunk/darwinup/Utils.cpp 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Utils.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -245,3 +245,21 @@
if (res == 0) return localfile;
return NULL;
}
+
+void __data_hex(FILE* f, uint8_t* data, uint32_t size) {
+ if (!size) return;
+ for (uint32_t i=0; i < size; i++) {
+ if (!(i%8)) {
+ if (i<10) fprintf(f, " ");
+ fprintf(f, "%d", i);
+ } else {
+ fprintf(f, " ");
+ }
+ }
+ fprintf(f, "\n");
+ for (uint32_t i=0; i < size; i++) {
+ fprintf(f, "%02x", data[i]);
+ }
+ fprintf(f, "\n");
+}
+
Modified: trunk/darwinup/Utils.h
===================================================================
--- trunk/darwinup/Utils.h 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/Utils.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -30,6 +30,9 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
+#ifndef _UTILS_H
+#define _UTILS_H
+
#include <stdint.h>
#include <sys/types.h>
#include <fts.h>
@@ -59,7 +62,10 @@
char* fetch_url(const char* srcpath, const char* dstpath);
char* fetch_userhost(const char* srcpath, const char* dstpath);
+void __data_hex(FILE* f, uint8_t* data, uint32_t size);
+
inline int INFO_TEST(uint32_t word, uint32_t flag) { return ((word & flag) != 0); }
inline int INFO_SET(uint32_t word, uint32_t flag) { return (word | flag); }
inline int INFO_CLR(uint32_t word, uint32_t flag) { return (word & (~flag)); }
+#endif
Modified: trunk/darwinup/main.cpp
===================================================================
--- trunk/darwinup/main.cpp 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/main.cpp 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
@@ -30,10 +30,6 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
-#include "Archive.h"
-#include "Depot.h"
-#include "Utils.h"
-
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
@@ -41,8 +37,15 @@
#include <unistd.h>
#include <limits.h>
+#include "Archive.h"
+#include "Depot.h"
+#include "Utils.h"
+#include "DB.h"
+
+
void usage(char* progname) {
fprintf(stderr, "usage: %s [-v] [-p DIR] [command] [args] \n", progname);
+ fprintf(stderr, "version: 15 \n");
fprintf(stderr, " \n");
fprintf(stderr, "options: \n");
fprintf(stderr, " -f force operation to succeed at all costs \n");
@@ -83,6 +86,7 @@
uint32_t verbosity;
uint32_t force;
+
int main(int argc, char* argv[]) {
char* progname = strdup(basename(argv[0]));
@@ -118,13 +122,7 @@
}
argc -= optind;
argv += optind;
-
- // you must be root
- uid_t uid = getuid();
- if (uid) {
- fprintf(stderr, "You must be root to run this tool.\n");
- exit(3);
- }
+ if (argc == 0) usage(progname);
int res = 0;
@@ -133,39 +131,55 @@
}
Depot* depot = new Depot(path);
- res = depot->initialize();
- if (res) {
- fprintf(stderr, "Error: unable to initialize storage.\n");
- exit(2);
+
+ // commands with no arguments
+ if (argc == 1) {
+ if (strcmp(argv[0], "list") == 0) {
+ res = depot->initialize(false);
+ if (res == -2) {
+ fprintf(stdout, "Nothing has been installed yet.\n");
+ exit(0);
+ }
+ if (res == 0) depot->list();
+ } else if (strcmp(argv[0], "dump") == 0) {
+ if (depot->initialize(false)) exit(11);
+ depot->dump();
+ } else {
+ usage(progname);
+ }
}
-
- if (argc == 2 && strcmp(argv[0], "install") == 0) {
- res = depot->install(argv[1]);
- } else if (argc == 2 && strcmp(argv[0], "upgrade") == 0) {
- // find most recent matching archive by name
- Archive* old = depot->get_archive(basename(argv[1]));
- if (!old) {
- fprintf(stderr, "Error: unable to find a matching root to upgrade.\n");
- res = 5;
+
+ // loop over arguments
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[0], "install") == 0) {
+ if (i==1 && depot->initialize(true)) exit(13);
+ res = depot->install(argv[i]);
+ } else if (strcmp(argv[0], "upgrade") == 0) {
+ if (i==1 && depot->initialize(true)) exit(14);
+ // find most recent matching archive by name
+ Archive* old = depot->get_archive(basename(argv[i]));
+ if (!old) {
+ fprintf(stderr, "Error: unable to find a matching root to upgrade.\n");
+ res = 5;
+ }
+ // install new archive
+ if (res == 0) res = depot->install(argv[i]);
+ // uninstall old archive
+ if (res == 0) res = depot->uninstall(old);
+ } else if (strcmp(argv[0], "files") == 0) {
+ if (i==1 && depot->initialize(false)) exit(12);
+ res = depot->process_archive(argv[0], argv[i]);
+ } else if (strcmp(argv[0], "uninstall") == 0) {
+ if (i==1 && depot->initialize(true)) exit(15);
+ res = depot->process_archive(argv[0], argv[i]);
+ } else if (strcmp(argv[0], "verify") == 0) {
+ if (i==1 && depot->initialize(true)) exit(16);
+ res = depot->process_archive(argv[0], argv[i]);
+ } else {
+ usage(progname);
}
- // install new archive
- if (res == 0) res = depot->install(argv[1]);
- // uninstall old archive
- if (res == 0) res = depot->uninstall(old);
- } else if (argc == 1 && strcmp(argv[0], "list") == 0) {
- depot->list();
- } else if (argc == 1 && strcmp(argv[0], "dump") == 0) {
- depot->dump();
- } else if (argc == 2 && strcmp(argv[0], "files") == 0) {
- res = depot->process_archive(argv[0], argv[1]);
- } else if (argc == 2 && strcmp(argv[0], "uninstall") == 0) {
- res = depot->process_archive(argv[0], argv[1]);
- } else if (argc == 2 && strcmp(argv[0], "verify") == 0) {
- res = depot->process_archive(argv[0], argv[1]);
- } else {
- usage(progname);
}
-
+
free(path);
exit(res);
return res;
Modified: trunk/darwinup/redo_prebinding.h
===================================================================
--- trunk/darwinup/redo_prebinding.h 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/darwinup/redo_prebinding.h 2010-03-03 21:37:30 UTC (rev 732)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Computer, Inc. All rights reserved.
*
* @APPLE_BSD_LICENSE_HEADER_START@
*
Copied: trunk/testing/darwinup/300dirs.tbz2 (from rev 731, branches/PR-7489777/testing/darwinup/300dirs.tbz2)
===================================================================
(Binary files differ)
Copied: trunk/testing/darwinup/300files.tbz2 (from rev 731, branches/PR-7489777/testing/darwinup/300files.tbz2)
===================================================================
(Binary files differ)
Modified: trunk/testing/darwinup/run-tests.sh
===================================================================
--- trunk/testing/darwinup/run-tests.sh 2010-03-02 21:08:27 UTC (rev 731)
+++ trunk/testing/darwinup/run-tests.sh 2010-03-03 21:37:30 UTC (rev 732)
@@ -32,6 +32,11 @@
tar zxvf $R.tar.gz -C $PREFIX
done;
+for R in 300dirs 300files;
+do
+ cp $R.tbz2 $PREFIX/
+done;
+
mkdir -p $ORIG
cp -R $DEST/* $ORIG/
@@ -47,6 +52,18 @@
$DIFF $ORIG $DEST 2>&1
done
+echo "========== TEST: Multiple argument test ==========";
+darwinup -vv -p $DEST install $PREFIX/root{,2,3}
+LINES=$(darwinup -p $DEST list | wc -l)
+if [ $LINES -lt 5 ]; then
+ echo "Failed multiple argument test."
+ exit 1;
+fi
+darwinup -vv -p $DEST uninstall all
+echo "DIFF: diffing original test files to dest (should be no diffs) ..."
+$DIFF $ORIG $DEST 2>&1
+
+
echo "========== TEST: Trying all roots at once, uninstall in reverse ==========";
for R in $ROOTS;
do
@@ -107,6 +124,25 @@
echo "DIFF: diffing original test files to dest (should be no diffs) ..."
$DIFF $ORIG $DEST 2>&1
+echo "========== TEST: trying large roots ==========";
+echo "INFO: installing 300files";
+darwinup -vv -p $DEST install $PREFIX/300files.tbz2
+darwinup -vv -p $DEST uninstall 300files.tbz2
+echo "DIFF: diffing original test files to dest (should be no diffs) ..."
+$DIFF $ORIG $DEST 2>&1
+echo "INFO: installing 300dir";
+darwinup -vv -p $DEST install $PREFIX/300dirs.tbz2
+darwinup -vv -p $DEST uninstall 300dirs.tbz2
+echo "DIFF: diffing original test files to dest (should be no diffs) ..."
+$DIFF $ORIG $DEST 2>&1
+echo "INFO: installing both 300files and 300dirs";
+darwinup -vv -p $DEST install $PREFIX/300dirs.tbz2
+darwinup -vv -p $DEST install $PREFIX/300files.tbz2
+darwinup -vv -p $DEST uninstall 300dirs.tbz2
+darwinup -vv -p $DEST uninstall 300files.tbz2
+echo "DIFF: diffing original test files to dest (should be no diffs) ..."
+$DIFF $ORIG $DEST 2>&1
+
echo "========== TEST: Try uninstalling with user data in rollback =========="
echo "INFO: Installing root5 ...";
darwinup -vv -p $DEST install $PREFIX/root5
@@ -131,8 +167,10 @@
echo "DIFF: diffing original test files to dest (should be no diffs) ..."
$DIFF $ORIG $DEST 2>&1
-
-# expected failures
+
+#
+# The following are expected failures
+#
set +e
echo "========== TEST: Trying a root that will fail due to object change =========="
darwinup -vv -p $DEST install $PREFIX/root4
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/darwinbuild-changes/attachments/20100303/21b4acec/attachment-0001.html>
More information about the darwinbuild-changes
mailing list